ReactiveObjC官方文檔翻譯

前言

此為ReactiveObjC文檔翻譯,gitHub tag:2.12 date:2017-03-15 QQ: 809199658.
原文地址:ReactiveCocoa/ReactiveObjC(四級(jí)險(xiǎn)過翻譯,請(qǐng)諒解)

ReactiveObjC

提示:本文是使用老版本ReactiveCocoa - Objective-C的介紹,Objective-C ReactiveCocoa又名ReactiveObjC,如果希望使用新版(swift)的ReactiveCocoa,可以查看ReactiveCocoa或者ReactiveSwift.

ReactiveObjC (一般來說又叫做ReactiveCocoa或者RAC)是一個(gè)基于響應(yīng)式編程的Objective-C的框架.使用它提供API用以創(chuàng)建和改變數(shù)據(jù)流.

如果你已經(jīng)熟悉響應(yīng)式編程或者了解基本的ReactiveObjC概念,你可以查看github上的其他文件來了解其框架的概述然后在實(shí)踐中深入了解其使用

新接觸ReactiveObjC?

ReactiveObjC的文檔非常完善,并且有非常豐富的介紹材料用以了解并使用RAC.

如果你想學(xué)習(xí)更多,我們推薦你下列的這些資源

  1. introduction
  2. when-to-use-reactiveobjc
  3. Framework Overview
  4. Basic Operators
  5. Header Documentation
  6. Stack Overflow之前問題的回答或者GitHub issues.
  7. 本文章的剩余部分
  8. Functional Reactive Programming on iOS (eBook)

如果你還有更多問題,請(qǐng)提交issue

介紹

ReactiveObjC是基于函數(shù)響應(yīng)式編程,相對(duì)于修改或替換現(xiàn)有變量,RAC提供信號(hào)類(代表:RACSugnal)來捕捉現(xiàn)有和 未來(future???)的變量

通過鏈接,綁定以及響應(yīng)信號(hào),不需要監(jiān)聽來更新變量,使得程序更加簡(jiǎn)潔

例如,一個(gè)文本框被綁定后,相對(duì)于使用額外的代碼去監(jiān)聽時(shí)間和更新文本框,使用block來重寫RAC使得其更像KVO
-observeValueForKeyPath:ofObject:change:context:

信號(hào)類也可以像多線程一樣使用,像并發(fā)式編程.這簡(jiǎn)化了包括在網(wǎng)絡(luò)請(qǐng)求在內(nèi)的多線程程序.

RAC的最大優(yōu)點(diǎn)就是它提供了一個(gè)信號(hào),統(tǒng)一了解決異步行為的方法,包括代理方法,target-action機(jī)制,通知,和KVO.

例1:

// 當(dāng)self.username 改變時(shí),控制臺(tái)會(huì)輸出他的新名字
//
// RACObserve(self, username)在文本改變的時(shí)候創(chuàng)建了發(fā)送當(dāng)前姓名的一個(gè)新信號(hào)
// -subscribeNext: 在收到信號(hào)后執(zhí)行block
[RACObserve(self, username) subscribeNext:^(NSString *newName) {
    NSLog(@"%@", newName);
}];

相對(duì)于KVO,信號(hào)可以被鏈接到一起并一同執(zhí)行

//只打印以'j'開頭的名字
//
// 過濾器在第一個(gè)信號(hào)block被調(diào)用返回YES時(shí)才發(fā)送一個(gè)新值給下一個(gè)block
[[RACObserve(self, username)
    filter:^(NSString *newName) {
        return [newName hasPrefix:@"j"];
    }]
    subscribeNext:^(NSString *newName) {
        NSLog(@"%@", newName);
    }];

信號(hào)也可以用來獲取狀態(tài),RAC可以將屬性快速的轉(zhuǎn)換成信號(hào)和操作來替代監(jiān)聽屬性然后改變值得這種方式.

//創(chuàng)建一個(gè)單程綁定,這樣當(dāng)self.password和self.passwordConfirmation一樣時(shí)self.createEnabled將會(huì)變成ture
//
// RAC() 宏可以使得綁定表示的更清楚
//
// +combineLatest:reduce: 獲取一個(gè)信號(hào)數(shù)組,當(dāng)其中任何一個(gè)改變時(shí)傳遞新值并調(diào)用這些blocks,并且返回block返回值的一個(gè)新RACSignal信號(hào)
//(returns a new RACSignal that sends the return value of that block as values.)
RAC(self, createEnabled) = [RACSignal
    combineLatest:@[ RACObserve(self, password), RACObserve(self, passwordConfirmation) ]
    reduce:^(NSString *password, NSString *passwordConfirm) {
        return @([passwordConfirm isEqualToString:password]);
    }];

信號(hào)可以在任何時(shí)間任何數(shù)據(jù)流上創(chuàng)建,不僅限于KVO,例如,可以用于按鈕點(diǎn)擊事件

// 在按鈕點(diǎn)擊時(shí)打印信息
// RACCommand 用以表示一個(gè)UI事件. 每一個(gè)信號(hào)可以表示一次點(diǎn)擊, 例如,在點(diǎn)擊事件時(shí)處理額外的事件
// -rac_command 是 NSButton 的額外方法 . 在點(diǎn)擊時(shí),按鈕將自身發(fā)送給它自己.
self.button.rac_command = [[RACCommand alloc] initWithSignalBlock:^(id _) {
    NSLog(@"button was pressed!");
    return [RACSignal empty];
}];

或者異步網(wǎng)絡(luò)請(qǐng)求

// 給按鈕綁定一個(gè)登錄事件請(qǐng)求網(wǎng)絡(luò)
//
// 在登錄命令執(zhí)行的時(shí)候這個(gè)block將用以執(zhí)行登錄程序
self.loginCommand = [[RACCommand alloc] initWithSignalBlock:^(id sender) {
    // 這個(gè)登錄命令在網(wǎng)絡(luò)請(qǐng)求結(jié)束后返回發(fā)送值得一個(gè)信號(hào)
    return [client logIn];
}];

// -executionSignals 返回一個(gè)包含上面block的信號(hào),收到一次信號(hào)執(zhí)行一次
[self.loginCommand.executionSignals subscribeNext:^(RACSignal *loginSignal) {
    // 登錄成功調(diào)用
    [loginSignal subscribeCompleted:^{
        NSLog(@"Logged in successfully!");
    }];
}];

// 按鈕點(diǎn)擊時(shí)執(zhí)行登錄命令
self.loginButton.rac_command = self.loginCommand;

信號(hào)也可以在timer,UI事件,或者其他隨時(shí)間改變的事情上

將多個(gè)信號(hào)鏈接在一起成為一組操作(a group of operations completes)可以使得更復(fù)雜的異步操作變得簡(jiǎn)單

// 在兩個(gè)網(wǎng)絡(luò)請(qǐng)求結(jié)束后打印信息
//
// +merge: takes an array of signals and returns a new RACSignal that passes
// through the values of all of the signals and completes when all of the
// signals complete.(太長(zhǎng)了,求翻譯)
//
// -subscribeCompleted: 在信號(hào)結(jié)束后調(diào)用
[[RACSignal
    merge:@[ [client fetchUserRepos], [client fetchOrgRepos] ]]
    subscribeCompleted:^{
        NSLog(@"They're both done!");
    }];

多個(gè)異步操作也可以將信號(hào)鏈接實(shí)現(xiàn),不同于回調(diào)block,這個(gè)和并發(fā)操作的一般做法一致.

// 登錄用戶,服務(wù)器獲取信息,獲取本地緩存信息,之后顯示全部信息
//
// hypothetical -logInUser 在登錄完成后返回完成信號(hào)
//
// -flattenMap: 在信號(hào)發(fā)送后執(zhí)行block, 返回一個(gè)合并所有block返回信號(hào)的新的RACSignal
[[[[client logInUser]
    flattenMap:^(User *user) {
       //返回本地緩存已讀取完成的信號(hào)
        return [client loadCachedMessagesForUser:user];
    }]
    flattenMap:^(NSArray *messages) {
        // 返回信息已匹配的信號(hào)
        return [client fetchMessagesAfterMessage:messages.lastObject];
    }]
    subscribeNext:^(NSArray *newMessages) {
        NSLog(@"New messages: %@", newMessages);
    } completed:^{
        NSLog(@"Fetched all messages.");
    }];

RAC也可以輕松綁定一步操作的結(jié)果

// 在用戶頭像下載完成后可以輕松綁定self.imageView.image
//
//hypothetical -fetchUserWithUsername: 發(fā)送給用戶的信號(hào)
//
// -deliverOn: 在其他隊(duì)列上創(chuàng)建一個(gè)新的信號(hào)在本例中,
//它用來將任務(wù)放置在后臺(tái)隊(duì)列然后返回主隊(duì)列中
//
RAC(self.imageView, image) = [[[[client
    fetchUserWithUsername:@"joshaber"]
    deliverOn:[RACScheduler scheduler]]
    map:^(User *user) {
        // 在后臺(tái)下載頭像
        return [[NSImage alloc] initWithContentsOfURL:user.avatarURL];
    }]
    // 此操作在主線程
    deliverOn:RACScheduler.mainThreadScheduler];

上面這些例子表明了RAC可以做的事情,但是很難再README大小的例子中展示為什么RAC很犀利,但是可以表明RAC怎么樣讓代碼更清晰(吹牛中)....

如果要更多的代碼示例,可以查看C-41或者GroceryList.其中所有的iOS APP都是用RAC來實(shí)現(xiàn)的,更多關(guān)于RAC的信息都可以在其中找到.

什么時(shí)候使用RAC

初看的時(shí)候,RAC非常抽象,而且很難了解什么時(shí)候使用來解決問題.
接下來的demo是RAC擅長(zhǎng)的領(lǐng)域.

操作異步或者事件驅(qū)動(dòng)數(shù)據(jù)源

許多的cocoa程序關(guān)注于程序?qū)κ录捻憫?yīng)或改變,處理的代碼很可能變得非常復(fù)雜(就像意大利面條??一樣),非常多的回調(diào)block和狀態(tài)變量用來處理問題.
樣式(Patterns)看起來是突出的那個(gè),像UI的回調(diào),網(wǎng)絡(luò)回應(yīng),KVO,通知,其實(shí)他們都有許多一樣的地方,RACSignal統(tǒng)一了不用的API調(diào)用方法,讓他們用一致的方式被調(diào)用.

例如:

static void *ObservationContext = &ObservationContext;

- (void)viewDidLoad {
    [super viewDidLoad];

    [LoginManager.sharedManager addObserver:self forKeyPath:@"loggingIn" options:NSKeyValueObservingOptionInitial context:&ObservationContext];
    [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(loggedOut:) name:UserDidLogOutNotification object:LoginManager.sharedManager];

    [self.usernameTextField addTarget:self action:@selector(updateLogInButton) forControlEvents:UIControlEventEditingChanged];
    [self.passwordTextField addTarget:self action:@selector(updateLogInButton) forControlEvents:UIControlEventEditingChanged];
    [self.logInButton addTarget:self action:@selector(logInPressed:) forControlEvents:UIControlEventTouchUpInside];
}

- (void)dealloc {
    [LoginManager.sharedManager removeObserver:self forKeyPath:@"loggingIn" context:ObservationContext];
    [NSNotificationCenter.defaultCenter removeObserver:self];
}

- (void)updateLogInButton {
    BOOL textFieldsNonEmpty = self.usernameTextField.text.length > 0 && self.passwordTextField.text.length > 0;
    BOOL readyToLogIn = !LoginManager.sharedManager.isLoggingIn && !self.loggedIn;
    self.logInButton.enabled = textFieldsNonEmpty && readyToLogIn;
}

- (IBAction)logInPressed:(UIButton *)sender {
    [[LoginManager sharedManager]
        logInWithUsername:self.usernameTextField.text
        password:self.passwordTextField.text
        success:^{
            self.loggedIn = YES;
        } failure:^(NSError *error) {
            [self presentError:error];
        }];
}

- (void)loggedOut:(NSNotification *)notification {
    self.loggedIn = NO;
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if (context == ObservationContext) {
        [self updateLogInButton];
    } else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

用RAC可以被這樣實(shí)現(xiàn)

- (void)viewDidLoad {
    [super viewDidLoad];

    @weakify(self);
//將button的enable和accountText,passwordText,isLogin,logined綁定起來
    RAC(self.logInButton, enabled) = [RACSignal
        combineLatest:@[
            self.usernameTextField.rac_textSignal,
            self.passwordTextField.rac_textSignal,
            RACObserve(LoginManager.sharedManager, loggingIn),
            RACObserve(self, loggedIn)
        ] reduce:^(NSString *username, NSString *password, NSNumber *loggingIn, NSNumber *loggedIn) {
            return @(username.length > 0 && password.length > 0 && !loggingIn.boolValue && !loggedIn.boolValue);
        }];
//loginbutton 的點(diǎn)擊事件
    [[self.logInButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(UIButton *sender) {
        @strongify(self);
//調(diào)起登錄接口
        RACSignal *loginSignal = [LoginManager.sharedManager
            logInWithUsername:self.usernameTextField.text
            password:self.passwordTextField.text];
//登錄接口回調(diào)
            [loginSignal subscribeError:^(NSError *error) {
                @strongify(self);
                [self presentError:error];
            } completed:^{
                @strongify(self);
                self.loggedIn = YES;
            }];
    }];

    RAC(self, loggedIn) = [[NSNotificationCenter.defaultCenter
        rac_addObserverForName:UserDidLogOutNotification object:nil]
        mapReplace:@NO];
}

鏈?zhǔn)揭蕾嚥僮?/h2>

網(wǎng)絡(luò)請(qǐng)求中經(jīng)常出現(xiàn)依賴關(guān)系,在上一個(gè)操作完成后才能進(jìn)行下一個(gè)操作,像下面這樣:

[client logInWithSuccess:^{
    [client loadCachedMessagesWithSuccess:^(NSArray *messages) {
        [client fetchMessagesAfterMessage:messages.lastObject success:^(NSArray *nextMessages) {
            NSLog(@"Fetched all messages.");
        } failure:^(NSError *error) {
            [self presentError:error];
        }];
    } failure:^(NSError *error) {
        [self presentError:error];
    }];
} failure:^(NSError *error) {
    [self presentError:error];
}];

使用RAC可以更簡(jiǎn)單

[[[[client logIn]
    then:^{
        return [client loadCachedMessages];
    }]
    flattenMap:^(NSArray *messages) {
        return [client fetchMessagesAfterMessage:messages.lastObject];
    }]
    subscribeError:^(NSError *error) {
        [self presentError:error];
    } completed:^{
        NSLog(@"Fetched all messages.");
    }];

獨(dú)立并行功能

在并行的線程處理獨(dú)立數(shù)據(jù)并把處理好的數(shù)據(jù)合并在一起在cocoa中是非常重要的事情,而且很容易引起同步問題.

__block NSArray *databaseObjects;
__block NSArray *fileContents;

NSOperationQueue *backgroundQueue = [[NSOperationQueue alloc] init];
NSBlockOperation *databaseOperation = [NSBlockOperation blockOperationWithBlock:^{
    databaseObjects = [databaseClient fetchObjectsMatchingPredicate:predicate];
}];

NSBlockOperation *filesOperation = [NSBlockOperation blockOperationWithBlock:^{
    NSMutableArray *filesInProgress = [NSMutableArray array];
    for (NSString *path in files) {
        [filesInProgress addObject:[NSData dataWithContentsOfFile:path]];
    }

    fileContents = [filesInProgress copy];
}];

NSBlockOperation *finishOperation = [NSBlockOperation blockOperationWithBlock:^{
    [self finishProcessingDatabaseObjects:databaseObjects fileContents:fileContents];
    NSLog(@"Done processing");
}];

[finishOperation addDependency:databaseOperation];
[finishOperation addDependency:filesOperation];
[backgroundQueue addOperation:databaseOperation];
[backgroundQueue addOperation:filesOperation];
[backgroundQueue addOperation:finishOperation];

使用RAC可以簡(jiǎn)化成如下代碼

RACSignal *databaseSignal = [[databaseClient
    fetchObjectsMatchingPredicate:predicate]
    subscribeOn:[RACScheduler scheduler]];

RACSignal *fileSignal = [RACSignal startEagerlyWithScheduler:[RACScheduler scheduler] block:^(id<RACSubscriber> subscriber) {
    NSMutableArray *filesInProgress = [NSMutableArray array];
    for (NSString *path in files) {
        [filesInProgress addObject:[NSData dataWithContentsOfFile:path]];
    }

    [subscriber sendNext:[filesInProgress copy]];
    [subscriber sendCompleted];
}];

[[RACSignal
    combineLatest:@[ databaseSignal, fileSignal ]
    reduce:^ id (NSArray *databaseObjects, NSArray *fileContents) {
        [self finishProcessingDatabaseObjects:databaseObjects fileContents:fileContents];
        return nil;
    }]
    subscribeCompleted:^{
        NSLog(@"Done processing");
    }];

簡(jiǎn)化集合的變形

高序列化功能像map,filter,fold/reduce也可能在fondation框架中缺失或者導(dǎo)致loop-focused崩潰.

//在遍歷中添加數(shù)據(jù)導(dǎo)致無限循環(huán)
NSMutableArray *results = [NSMutableArray array];
for (NSString *str in strings) {
    if (str.length < 2) {
        continue;
    }

    NSString *newString = [str stringByAppendingString:@"foobar"];
    [results addObject:newString];
}

RAC中RACSequence允許在遍歷中添加值.

RACSequence *results = [[strings.rac_sequence
    filter:^ BOOL (NSString *str) {
        return str.length >= 2;
    }]
    map:^(NSString *str) {
        return [str stringByAppendingString:@"foobar"];
    }];

系統(tǒng)要求

OS X 10.8+ 及iOS8.0+

導(dǎo)入ReactiveObjC

導(dǎo)入ReactiveObjC你可以

  1. 添加ReactiveObjC倉庫到你的程序倉庫中
  2. 在你的ReactiveObjC文件夾中運(yùn)行
    git submodule update --init --recursive
  3. ReactiveObjC.xcodeproj拖入你的Xcode項(xiàng)目中
  4. 在"Build Phases"中添加RAC到"Link Binary With Libraries"中
  5. 添加ReactiveObjC.frameworkRAC也必須添加到任何"Copy Frameworks"build phase中.如果你還沒創(chuàng)建,簡(jiǎn)單的添加一個(gè)"Copy Files" build phase指向(target)"Frameworks"位置
  6. 添加"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/include" $(inherited)到"Header Search Paths" build setting 中
  7. 如果是iOS,則需要在"Other Linker Flags" build setting添加-ObjC

后記

四級(jí)渣翻譯,如果有什么意見或者改善的地方可以留言或者通過QQ聯(lián)系我~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市停忿,隨后出現(xiàn)的幾起案子光涂,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件猛遍,死亡現(xiàn)場(chǎng)離奇詭異育灸,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)滩字,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門造虏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來御吞,“玉大人,你說我怎么就攤上這事漓藕√罩椋” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵享钞,是天一觀的道長(zhǎng)揍诽。 經(jīng)常有香客問我,道長(zhǎng)栗竖,這世上最難降的妖魔是什么暑脆? 我笑而不...
    開封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮狐肢,結(jié)果婚禮上添吗,老公的妹妹穿的比我還像新娘。我一直安慰自己份名,他們只是感情好碟联,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著僵腺,像睡著了一般鲤孵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上辰如,一...
    開封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天普监,我揣著相機(jī)與錄音,去河邊找鬼琉兜。 笑死鹰椒,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的呕童。 我是一名探鬼主播漆际,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼夺饲!你這毒婦竟也來了奸汇?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤往声,失蹤者是張志新(化名)和其女友劉穎擂找,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體浩销,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡贯涎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了慢洋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片塘雳。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡陆盘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出败明,到底是詐尸還是另有隱情隘马,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布妻顶,位于F島的核電站酸员,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏讳嘱。R本人自食惡果不足惜幔嗦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望沥潭。 院中可真熱鬧邀泉,春花似錦、人聲如沸叛氨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寞埠。三九已至,卻和暖如春焊夸,著一層夾襖步出監(jiān)牢的瞬間仁连,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來泰國(guó)打工阱穗, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留饭冬,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓揪阶,卻偏偏與公主長(zhǎng)得像昌抠,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子鲁僚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫炊苫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,105評(píng)論 4 62
  • 一冰沙、概述 筆者 強(qiáng)烈推薦 大家在閱讀本文之前侨艾,還請(qǐng)先移步閱讀?? iOS 關(guān)于MVC和MVVM設(shè)計(jì)模式的那些事 和...
    CoderMikeHe閱讀 15,610評(píng)論 28 147
  • 打算在項(xiàng)目中大面積使用RAC來開發(fā),所以整理一些常用的實(shí)踐范例和比較完整的api說明方便開發(fā)時(shí)隨時(shí)查閱 聲明式編程...
    星光社的戴銘閱讀 5,350評(píng)論 5 49
  • 注意: 此文只是自己翻譯學(xué)習(xí)拓挥,如有不對(duì)地方還望指出唠梨。此文結(jié)合如下倆篇文章翻譯,一則練習(xí)自己的翻譯能力侥啤,二則真正理解...
    暮落晨曦閱讀 6,253評(píng)論 8 81
  • 不時(shí)地我想起了你当叭,努力了很久茬故,卻不能清晰地刻畫出你的輪廓。 我記得你秀氣或稚拙的筆記科展,我記得你說過的一些話語均牢,我記...
    陳大仙兒_英姐閱讀 287評(píng)論 0 2