我正在制作一个可以为我所有的视图控制器下载东西的对象。该对象是单例实例,并且在下载完成后具有接收数据的回调方法。它还有一个委托属性,以便在下载完成后知道要回调哪个对象。
有多个控制器使用这个共享实例,我的问题是如何回调请求下载的正确视图控制器。
我的方法是使用委托,但问题是由于其他视图控制器也是它的委托,下载对象可能会回调每个对象,这将很难跟踪。
我曾参与过人们试图使用多个代表的项目,但这基本上是个坏主意。委托模式是关于一个类和它的委托之间的一对一关系。虽然可以通过切换代表的进出来实现某种程度的多重委托,但它更有可能导致不可预知的行为和错误。
我的建议是改变你对此的看法。在我看来,您有两个选择:
切换到观察者模式,您可以在其中注册多个观察者,您的主类可以与之交互。这在您的观察者都实现相同的协议以及您的主类想要了解观察者并与他们交互的情况下很有用。
广播 NSNotifications 以指示状态更改和事件。这是一种更加解耦的方法,因为主类不需要知道谁在听,也不直接与他们交互。其他人可以在闲暇时开始和停止收到通知。它还有一个优点是您不需要创建或实现单独的协议。相反,您使用 NSNotificationCenter 注册需要了解更改的类,该 NSNotificationCenter 依次为您处理所有通知路由。
实际上听起来委托模式可能不是这里最好的方法。
我会调查一下NSNotificationCenter
。
基本思想是你的单例进行网络连接会发布一个通知(带有类似的东西postNotificationName:object:userInfo:
),说有新数据可用。在此通知中,您可以传递一个字典对象 ( userInfo
),其中包含您已获取的数据,或有关模型的哪些部分包含更新数据的信息。
然后,您的其他视图控制器可以通过调用来注册自己以“观察”这些通知addObserver:selector:name:object:
。一般来说,当一个 vc 变得可见时,我调用addObserver
,并且removeObserver
当它被隐藏或转换出来时。
祝你好运!
委派似乎不是解决这个问题的正确方法。要求请求视图控制器提供一个对象(它自己)和一个选择器供您调用作为完成通知怎么样?当然,您需要一个地方来存储该对象和选择器,直到下载完成。希望您有(或可以创建)一个对象。
虽然我同意这里的大多数答案,但如果您确实想要实现多个委托,您可以声明一个委托数组并向该数组中的所有委托发送消息。如果您的协议具有可选的委托方法,您可以responds(to aSelector: Selector!) -> Bool
在调用之前安全地检查使用(注意内存管理,因为这些委托将在数组中被强烈引用)。我再次同意多个代表可能是一个糟糕的架构理念,使用块或通知中心会更好地满足您的需求。
如果您只有一个其他对象要向其转发消息,那么一种方法对我有用,那就是创建一个forwardingDelegate
这不会导致难以调试委托排序的问题,也不会不必要地创建对另一个对象的依赖关系。请记住,如果您有很多对象,那么这可能不是最好的方法,它主要用于一个额外的对象,但只要有一个对象接收 SDK 并将其转发到其他对象 [1]。请注意,转发对象所需的每个方法都需要传递它,即使转发对象没有使用它。
例如,如果我需要转发来自 mapView 委托的消息:
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
// handle this object here.
if ([self.forwardingDelegate respondsToSelector:@selector(mapView:regionDidChangeAnimated:)])
{
[self.forwardingDelegate mapView:mapView regionDidChangeAnimated:animated];
}
// or handle this object here.
}
[self.forwardingDelegate mapView:mapView regionDidChangeAnimated:animated];
转发属性将像这样声明。
@property (nonatomic) id<MKMapViewDelegate> forwardingDelegate;
另一个对象将采用该协议,就好像它正在接收原始消息一样。
[1] 多个代表的数组方法可能会变得棘手,因为您无法像其他帖子中提到的那样控制调用代表的顺序。