Objective-C组播代表

我在xcode中创build新的标签视图项目,在appdelegate中创build了一个协议

.h文件

@protocol myProtocol <NSObject> -(void)myProtocolMethodOne; @end . . . @property (weak) id<myProtocol> mypDelegate; 

.m文件

 @synthesize mypDelegate; . . . //Inside didFinishLaunchingWithOptions [mypDelegate myProtocolMethodOne]; 

在firstViewController&secondViewController(都显示为两个不同的选项卡),我在这两个

 AppDelegate *ad = (AppDelegate*)[[UIApplication sharedApplication]delegate]; [ad setMypDelegate:self]; . . . -(void)myProtocolMethodOne { NSLog(@"1st VC"); [[self tabBarItem]setBadgeValue:@"ok"]; } 

代码工作正常,但只有secondViewController响应。

我正在寻找一种使用委托而不是通知的广播和监听器机制。

我search了很多,但find了除此之外的任何解决scheme,但是代码提前让我理解,所以我正在一步一步地从一个简单的项目开始理解这一点。 请帮助我这一点。 视图控制器如何同时响应委托,我该怎么做?

在你的情况下,足以容纳一个数组与所有代表,通过持有代表数组,可能作为一个私人财产,并允许添加/删除代表:

 @interface AppDelegate() // .h file @property (nonatomic,strong,readwrite) NSMutableArray* delegates; @end // .m file - (void) addDelegate: (id<MyProtocol>) delegate // By convention the first letter should be capital. { // Optional code you may need to execute before adding it. [delegates addObject: delegate]; } 

我留给你removeDelegate方法,这是非常简单的实现。

如何调用委托方法

在每个对象上调用select器就足够了:

 [delegates makeObjectsPerformSelector: myProtocolMethodOne]; 

如果你需要返回值,最好这样做:

 NSMutableArray* returnValues= [NSMutableArray new]; for(id<MyProtocol> delegate in delegates) { id result= [delegate myProtocolMethodTwo]; // Method returning a value [returnValues addObject: result]; } 

如何添加代表

在每个控制器(最多N次)中,您应该可以添加它:

 AppDelegate *ad = (AppDelegate*)[[UIApplication sharedApplication]delegate]; [ad addDelegate:self]; 

额外的问题 :你可能想要弱代理,但是NSArray拥有强大的引用。 在这里你可以find一个很好的解决scheme:

弱引用的NSArray(__unsafe_unretained)到ARC下的对象

它基本上说,使用valueWithNonretainedObject方法使用NSValue存储弱引用。

您可能会考虑与访问者模式类似的内容,而不是代表。

 @interface MyVisitor : NSObject < myProtocol > -(void)addAcceptor:(id < myProtocol >)acceptor @end @implementation -(void)myProtocolMethodOne { [_acceptors enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *break){ [obj performSelector:_sel]; }]; } // etc etc ... obviously you have to handle return values if you're getting these @end 

由于委托是一个简单的variables,赋值给它覆盖的价值,而不是添加到它。 你可以将它转换为一个数组,但是由于NSArray保持对它内部对象的强引用,所以你需要处理潜在的循环引用。 (在这种情况下,循环引用是两个对象相互拥有,既然它们都属于某个人,那么它们也不会被释放,即使它们只是相互拥有对方, 维基百科也有更多的东西 ,但Objective-C中的典型模式是让所有代表都软弱无力。)

代替代表,您可能希望考虑使用NSNotificationCenter通知。

而不是1:1,他们是1:任何(包括0没有特别的考虑)。 这个想法是,一个对象发布通知,并感兴趣的对象观察它。 每个对象可以select他们感兴趣的事件。

您需要执行以下几个步骤:

  1. 删除你写的所有委托代码。
  2. 同意通知名称。
  3. 注册将响应通知的对象。 (这是你设置委托的地方。)
  4. 处理通知。
  5. 发布通知(以前称为委托的地方)。
  6. 取消注册对象时,他们被摧毁。

你要做的是同意一个关键,可能是一个常数。

Keys.h:

 extern NSString *MethodOneNotification; 

Keys.m:

 NSString *MethodOneNotification = @"MethodOneNotification"; 

然后注册firstViewControllersecondViewController像这样viewDidLoad

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(methodOneNotification:) object:nil]; 

在select器的firstViewControllersecondViewController提供一个处理程序:

 - (void)methodOneNotification:(NSNotification *)notification { NSLog(@"%@ got the notification!", [self class]); } 

调用之前称为委托的通知:

 [[NSNotificationCenter defaultCenter] postNotificationName:MethodOneNotification object:nil]; 

firstViewControllersecondViewController ,你都要删除通知注册(当然在dealloc中):

 - (void)dealloc { [[NSNotification defaultCenter] removeObserver:self name:MethodOneNotification object:nil]; // [super dealloc] if you're not using ARC, but you should be } 

在通知处理程序中,您可以通知notification.object的发件人。 如果您需要传递信息以及通知,则可以使用postNotification:的不同变体postNotification:接受NSDictionary ,然后可以通过notification.userInfo访问字典。

如果您需要将值返回给发布消息的对象,则必须通过将消息发送给发布者(您可以通过notification.object访问)来发回消息。 例如:

 - (void)methodOneNotification:(NSNotification *)notification { AppDelegate *appDelegate = notification.object; [appDelegate returningValue:1]; } 

在这里,显然,AppDelegate需要定义和处理-(void)returningValue:(int)value

你需要保持类实例的返回值。 当然,如果你有多个可能的返回值,你需要通过一个数组来收集returningValue: 。 但至less你已经跳过循环引用。

解决这个问题的另一种方法是使用块。 这将会使这个答案的大小加倍。 :)底线,虽然:委托模式是这个问题的错误模式。 幸运的是,其他人很容易接受。