当前位置:K88软件开发文章中心编程语言Objective-CObjective-C01 → 文章内容

对象之间的通讯

减小字体 增大字体 作者:佚名  来源:网上搜集  发布时间:2019-1-10 11:12:24

在竞态条件里面变成 null, 所以先把他定义成 strong 的属性)可以用下面的代码展示__weak typeof(self) weakSelf = self;
myObj.myBlock = ^{ id localVal = weakSelf->
someIVar;
{
;
在最后【疑问】1: 只能在 block 不是作为一个 property 的时候使用,
否则会导致 retain cycle。
2: 当 block 被声明为一个 property 的时候使用。
Case 3: 和并发执行有关。
当涉及异步的服务的时候,
block 可以在之后被执行,
并且不会发生关于 self 是否存在的问题。
委托和数据源委托是 Apple 的框架里面使用广泛的模式,
同时它是一个重要的 四人帮的书“设计模式”中的模式。
委托模式是单向的,
消息的发送方(委托方)需要知道接收方(委托),
反过来就不是了。
对象之间没有多少耦合,
因为发送方只要知道它的委托实现了对应的 protocol。
本质上,
委托模式只需要委托提供一些回调方法,
就是说委托实现了一系列空返回值的方法。
不幸的是 Apple 的 API 并没有尊重这个原则,
开发者也效仿 Apple 进入了歧途。
一个典型的例子是 UITableViewDelegate 协议。
一些有 void 返回类型的方法就像回调- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath;
但是其他的不是- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
- (BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender;
当委托者询问委托对象一些信息的时候,
这就暗示着信息是从委托对象流向委托者,
而不会反过来。
这个概念就和委托模式有些不同,
它是一个另外的模式:数据源。
可能有人会说 Apple 有一个 UITableViewDataSouce protocol 来做这个(虽然使用委托模式的名字),
但是实际上它的方法是用来提供真实的数据应该如何被展示的信息的。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
此外,
以上两个方法 Apple 混合了展示层和数据层,
这显的非常糟糕,
但是很少的开发者感到糟糕。
而且我们在这里把空返回值和非空返回值的方法都天真地叫做委托方法。
为了分离概念,
我们应该这样做:委托模式:事件发生的时候,
委托者需要通知委托数据源模式: 委托方需要从数据源对象拉取数据这个是实际的例子:@class ZOCSignUpViewController;
@protocol ZOCSignUpViewControllerDelegate <
NSObject>
- (void)signUpViewControllerDidPressSignUpButton:(ZOCSignUpViewController *)controller;
@end@protocol ZOCSignUpViewControllerDataSource <
NSObject>
- (ZOCUserCredentials *)credentialsForSignUpViewController:(ZOCSignUpViewController *)controller;
@end@protocol ZOCSignUpViewControllerDataSource <
NSObject>
@interface ZOCSignUpViewController : UIViewController@property (nonatomic, weak) id<
ZOCSignUpViewControllerDelegate>
delegate;
@property (nonatomic, weak) id<
ZOCSignUpViewControllerDataSource>
dataSource;
@end在上面的例子里面,
委托方法需要总是有一个调用方作为第一个参数,
否则委托对象可能被不能区别不同的委托者的实例。
此外,
如果调用者没有被传递到委托对象,
那么就没有办法让一个委托对象处理两个不同的委托者了。
所以,
下面这样的方法就是人神共愤的:- (void)calculatorDidCalculateValue:(CGFloat)value;
默认情况下,
委托对象需要实现 protocol 的方法。
可以用@required 和 @optional 关键字来标记方法是否是必要的还是可选的。
@protocol ZOCSignUpViewControllerDelegate <
NSObject>
@required- (void)signUpViewController:(ZOCSignUpViewController *)controller didProvideSignUpInfo:(NSDictionary *);
@optional- (void)signUpViewControllerDidPressSignUpButton:(ZOCSignUpViewController *)controller;
@end对于可选的方法,
委托者必须在发送消息前检查委托是否确实实现了特定的方法(否则会Crash):if ([self.delegate respondsToSelector:@selector(signUpViewControllerDidPressSignUpButton:)]) { [self.delegate signUpViewControllerDidPressSignUpButton:self];
{
继承有时候你可能需要重载委托方法。
考虑有两个 UIViewController 子类的情况:UIViewControllerA 和 UIViewControllerB,
有下面的类继承关系。
UIViewControllerB <
UIViewControllerA <
UIViewControllerUIViewControllerA conforms to UITableViewDelegate and implements - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath.UIViewControllerA 遵从 UITableViewDelegate 并且实现了 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath.你可能会想要提供一个和 UIViewControllerB 不同的实现。
一个实现可能是这样子的:- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { CGFloat retVal = 0;
if ([super respondsToSelector:@selector(tableView:heightForRowAtIndexPath:)]) { retVal = [super tableView:self.tableView heightForRowAtIndexPath:indexPath];
{
return retVal + 10.0f;
{
但是如果超类(UIViewControllerA)没有实现这个方法呢?调用过程[super respondsToSelector:@selector(tableView:heightForRowAtIndexPath:)]会用 NSObject 的实现,
寻找,
在 self 的上下文中无疑有它的实现,
但是 app 会在下一行 Crash 并且报下面的错:*** Terminating app due to uncaught exception '
NSInvalidArgumentException'
, reason: '
-[UIViewControllerB tableView:heightForRowAtIndexPath:]: unrecognized selector sent to instance 0x8d82820'
这种情况下我们需要来询问特定的类实例是否可以响应对应的 selector。
下面的代码提供了一个小技巧:- (CGFloa

上一页  [1] [2] [3] [4]  下一页


对象之间的通讯