Objective-c多播代表

S.J*_*S.J 3 protocols objective-c ios

我在xcode中创建了新的选项卡式视图项目,在appdelegate中我创建了一个协议

.h文件

@protocol myProtocol <NSObject>
-(void)myProtocolMethodOne;
@end
.
.
.
@property (weak) id<myProtocol> mypDelegate;
Run Code Online (Sandbox Code Playgroud)

.m文件

@synthesize mypDelegate;
.
.
.
//Inside didFinishLaunchingWithOptions
[mypDelegate myProtocolMethodOne];
Run Code Online (Sandbox Code Playgroud)

在firstViewController和secondViewController中(两者都显示为两个不同的选项卡)我在两者中都这样做了

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

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

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

我搜索了很多,但没有找到任何解决方案,除了这个,但代码是提前为我明白,所以我采取了循序渐进的方式通过启动形式一个简单的项目明白这一点.请帮我解决这个问题.两个视图控制器如何同时响应委托,我该怎么办?

ilu*_*pra 5

您可以考虑使用看似访问者模式的内容而不是代理.

@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
Run Code Online (Sandbox Code Playgroud)


Ste*_*her 5

由于委托是一个简单的变量,因此分配它会覆盖该值而不是添加它.您可以将其转换为数组,但由于NSArray保留对其中对象的强引用,因此您需要处理潜在的循环引用.(在这种情况下的循环引用是两个对象彼此拥有.因为它们都是由某人拥有,所以它们都不会被释放.即使它们只相互拥有.维基百科有更多.但Objective-C中的典型模式是因为这个原因让所有代表都变得虚弱.)

您可能希望考虑使用NSNotificationCenter通知,而不是代表.

而不是1:1,它们是1:任何(包括0而无需特殊考虑).想法是一个对象发布通知,对它感兴趣的对象观察它.每个对象都可以选择他们感兴趣的事件.

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

  1. 删除您编写的所有代理代码.
  2. 同意通知名称.
  3. 注册将响应通知的对象.(这是您设置委托的位置.)
  4. 处理通知.
  5. 发布通知(您之前称之为委托的地方).
  6. 当对象被销毁时取消注册.

你会做的是同意一把钥匙,可能是一个常数.

Keys.h:

extern NSString *MethodOneNotification;
Run Code Online (Sandbox Code Playgroud)

Keys.m:

NSString *MethodOneNotification = @"MethodOneNotification";
Run Code Online (Sandbox Code Playgroud)

然后在某处注册firstViewControllersecondViewController喜欢这样viewDidLoad:

[[NSNotificationCenter defaultCenter] addObserver:self
      selector:@selector(methodOneNotification:) object:nil];
Run Code Online (Sandbox Code Playgroud)

在两者firstViewControllersecondViewController选择器中提供处理程序:

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

调用之前调用该委托的通知:

[[NSNotificationCenter defaultCenter] postNotificationName:MethodOneNotification
     object:nil];
Run Code Online (Sandbox Code Playgroud)

而在这两个firstViewControllersecondViewController,你要删除的通知注册(当然在dealloc中):

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

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

如果您需要将值返回到发布消息的对象,则必须通过向海报发送消息(您可以访问该消息)将其发回notification.object.例如:

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

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

您需要在类实例上保留返回值.当然,如果您有多个可能的返回,您将需要returningValue:使用数组收集它们.但至少你已经跳过了循环引用.

解决这个问题的另一种方法是使用块.不过,这会使这个答案的规模扩大一倍.:)尽管如此:委托模式是这个问题的错误模式.幸运的是,其他人很容易接受.