上面的@weakify 和 @strongify 语句是在Extended Objective-C库中定义的宏,也被包括在ReactiveCocoa中。@weakify宏让你创建一个弱引用的影子对象(如果你需要多个弱引用,你可以传入多个变量),@strongify让你创建一个对之前传入@weakify对象的强引用。
注意:如果你有兴趣了解@weakify 和 @strongify 实际上做了什么,在Xcode中,选择Product -> Perform Action -> Preprocess “RWSearchForViewController”。这会对view controller 进行预处理,展开所有的宏,以便你能看到最终的输出。
最后需要注意的一点,在block中使用实例变量时请小心谨慎。这也会导致block捕获一个self的强引用。你可以打开一个编译警告,当发生这个问题时能提醒你。在项目的build settings中搜索“retain”,找到下面显示的这个选项:
好了,你已经通过理论的考验,祝贺你。现在你应该能够开始有意思的部分了:为你的应用添加一些真正的功能!
注意:你们中一些眼尖的读者,那些关注了上一篇教程的读者,无疑已经注意到可以在目前的管道中移除subscribeNext:block,转而使用RAC宏。如果你发现了这个,修改代码,然后奖励自己一个小星星吧~
你将要使用Social Framework来让TwitterInstant应用能搜索Twitter的内容,使用Accounts Framework来获取Twitter的访问权限。关于Social Framework的更详细内容,参见iOS 6 by Tutorials中的相关章节。
在你添加代码之前,你需要在模拟器或者iPad真机上输入Twitter的登录信息。打开设置应用,选择Twitter选项,然后在屏幕右边的页面中输入登录信息。
初始工程已经添加了需要的框架,所以你只需引入头文件。在RWSearchFormViewController.m中,添加下面的引用。
#import <Accounts/Accounts.h>#import <Social/Social.h> ?
就在引用的下面,添加下面的枚举和常量:
typedef NS_ENUM(NSInteger, RWTwitterInstantError) { RWTwitterInstantErrorAccessDenied, RWTwitterInstantErrorNoTwitterAccounts, RWTwitterInstantErrorInvalidResponse }; static NSString * const RWTwitterInstantDomain = @"TwitterInstant";?
一会儿你就要用到它们来标示错误。
还是在这个文件中,在已有属性声明的下面,添加下面的代码:
@property (strong, nonatomic) ACAccountStore *accountStore; @property (strong, nonatomic) ACAccountType *twitterAccountType;?
ACAccountsStore类能让你访问你的设备能连接到的多个社交媒体账号,ACAccountType类则代表账户的类型。
还是在这个文件中,把下面的代码添加到viewDidLoad的最下面:
self.accountStore = [[ACAccountStore alloc] init]; self.twitterAccountType = [self.accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
上面的代码创建了一个account store和Twitter账户标识符。
当应用获取访问社交媒体账号的权限时,用户会看见一个弹框。这是一个异步操作,因此把这封装进一个signal是很好的选择。
还是在这个文件中,添加下面的代码:
- (RACSignal *)requestAccessToTwitterSignal { // 1 - define an error NSError *accessError = [NSError errorWithDomain:RWTwitterInstantDomain code:RWTwitterInstantErrorAccessDenied userInfo:nil]; // 2 - create the signal @weakify(self) return [RACSignal createSignal:^RACDisposable *(id subscriber) { // 3 - request access to twitter @strongify(self) [self.accountStore requestAccessToAccountsWithType:self.twitterAccountType options:nil completion:^(BOOL granted, NSError *error) { // 4 - handle the response if (!granted) { [subscriber sendError:accessError]; } else { [subscriber sendNext:nil]; [subscriber sendCompleted]; } }]; return nil; }]; }?
这个方法做了下面几件事:
回忆一下教程的第一部分,signal能发送3种不同类型的事件:
在signal的生命周期中,它可能不发送事件,发送一个或多个next事件,在这之后还能发送一个completed事件或一个error事件。