3

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

.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 响应。

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

我进行了很多搜索,但确实找到了除此之外的任何解决方案但代码对于我来说是提前理解的,所以我正在通过一个简单的项目开始逐步理解这一点。请帮助我解决这个问题。两个视图控制器如何同时响应委托,我该怎么办?

4

3 回答 3

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
于 2013-02-09T06:09:18.080 回答
5

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

您可能希望考虑使用NSNotificationCenter通知,而不是委托。

它们不是 1:1,而是 1:any(包括 0 没有特殊考虑)。这个想法是一个对象发布一个通知,对它感兴趣的对象会观察它。每个对象都可以选择他们感兴趣的事件。

您需要执行几个步骤:

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

你要做的就是在一个键上达成一致,可能是一个常数。

键.h:

extern NSString *MethodOneNotification;

键.m:

NSString *MethodOneNotification = @"MethodOneNotification";

然后注册firstViewControllersecondViewController喜欢这样的地方viewDidLoad

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

firstViewController为选择器提供一个处理程序secondViewController

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

在您之前调用代理的位置调用通知:

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

firstViewControllerand中secondViewController,您需要删除通知注册(当然是在 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:接受 a的不同变体NSDictionary,然后您可以访问字典作为notification.userInfo.

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

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

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

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

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

于 2013-02-09T23:20:50.963 回答
4

在您的情况下,通过持有一个委托数组(可能作为私有属性)并允许添加/删除委托,足以保存一个包含所有委托的数组:

@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 方法留给你,它实现起来非常简单。

如何调用委托方法

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

[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 拥有强引用。在这里你可以找到一个很好的解决方案:

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

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

于 2013-02-09T23:02:47.100 回答