观察者,通知,代表swift ios8

时间:2015-03-26 00:57:55

标签: ios swift design-patterns delegates notifications

我正在寻找一些建议,如何最好地实现我认为可能是观察者的东西,可能是多播代表,或者我只是使用通知输入。

我正在创建一个DataManager类,它连接到各种数据源并生成通用数据格式。

实施例

我们可以从内核位置文件播放网络套接字提供位置等生成LocationMessage < / p>

返回的数据类型为LocationMessage,具有通用格式,如有必要,也可以转换为CLLocation

在我目前的“多委托”模型中,如果要获取位置更新,则必须实现定义的LocationConsumer协议

func didUpdateLocation(newLocation: LocationMessage) 
{
    println("\(__FUNCTION__)   \(newLocation)")
}

然后你会

//Instantiate a data manager
let dm : DataManager = DataManager()

//Register yourself as a delegate
dm.addLocationDelegate(self)

在我们获取新的位置数据时,我们会在内部调用以下内容:

    let closure = {
        (delegate : LocationDataConsumer) -> () in
        dispatch_async(self.delegateQueue) {
            delegate.didUpdateLocation(parsedLocation)
        }
    }
    locationDelegates.map(closure)

其中locationDelegates[LocationConsumer]

的数组

讨论

所以,首先,这显然不是真正遵循委托模式,因为你不应该有多个委托。

然而,我真正喜欢当前的方法是使用协议来识别类关心特定数据类型似乎非常干净。然而,我感到不舒服的是“破坏”标准委托模式。

从做一些阅读我认为最合适的方法是使用通知模式,但是,从编码的角度来看,我觉得涉及更多的维护(虽然我可能是错的) 。使用此委托方法实现协议并调用addDelegate的简单性会因通知而丢失。我假设我必须专门注册我关心的每个通知 - 对吗?

我做不了类似的事情:

class notificaitonClass : LocationNotifiee, WeatherNotifiee {

}

所以我想我的问题是

  • 1:我实施了观察员模式
  • 2:我当前方法的缺点是什么
  • 3:有没有办法定义一个swift协议,它将导致实现它的类自动订阅一组通知
  • 4:什么是更好的方法?

(希望这不是太模糊)

2 个答案:

答案 0 :(得分:1)

Stackoverflow不是回答此问题的最佳论坛,您应该尝试programmers.stackexchange.com。但到底是什么,这是我的快速回答。

不要将其称为代表

在Objective C / Swift委托中有一个特定的含义,你描述的模式并不合适。称之为事件处理程序,将其称为更改回调,heck,称之为多委托(ala dm.addLocationMultiDelegate(self)):不要通过重载术语委托来混淆人们。

重新考虑通知

您可以控制通知的内容以及通知的发送时间。你可以有一个DataMangerDidUpdateLocationNotification,可以从任何来源发布到任何接收者。在userInfo,如果您需要跟踪发布通知的人员,则可以DataMangerSourceKey

此外,您可以进一步概括它。对于一组数据管理器更改,您可以拥有DataMangerDidChangeNotification。您可能希望拥有DataMangerChangeTypeKey

例如:

NSNotificationCenter.defaultCenter().addObserverForName(DataMangerDidChangeNotification, object: nil, queue: nil) {
    note in
    let changeType = note.userInfo![DataMangerChangeTypeKey] as String

    if changeType == DataMangerChangeTypeLocation {
        …
    } else if changeType == DataMangerChangeTypeOther {
        …
    }
}

答案 1 :(得分:1)

我同意@JefferyThomas。您所做的完全有效,但Swift和Objective-C都没有将多播委托作为标准设计模式的概念。

这并不是说它有什么问题。拥有符合给定协议的对象数组是完全有效的,就像使用map函数调用该数组中所有对象的闭包一样。 Voila,即时多播代表。

Cocoa / Cocoa Touch程序员(像我一样)如果你使用那个术语,很容易看到你很有趣,仅仅因为术语&#34;委托&#34;在Cocoa中有一个相当狭窄的含义,这个含义不包括多播代表。

在我看来,你已经为你的多播代表设计了很多&#34;映射出来&#34; (双关语)所以如果它非常适合你需要做的事情那就去吧。您没有打破委托设计模式 - 您正在实施一种在平台上没有广泛使用的不同设计模式,但仍然完全有效且有用。

当我第一次开始阅读你的问题时,我想&#34;代表是一对一的。通知更适合。&#34;这是因为,作为一个典型的Cocoa / Cocoa Touch开发人员,术语&#34; delegate&#34;对我来说意义不大 - 一个没有覆盖多播代表的意思。然而,在我搜索这个术语之前,我非常清楚你的意思,我正在考虑符合通用协议和地图功能的对象数组。

通知是解决问题的另一种完全有效的方法。令我感到震惊的是,通知和多播代表之间的区别在于谁负责这项工作。在多播代理中,发送者必须维护一个目标列表(我不愿称他们为代理),并将所需的消息发送给每个目标。

在通知中,发件人不知道或不关心谁在听。发送者只是发出一个信号弹,负担是听众的关心和回应。 KVO类似于这方面的通知。

编辑:

考虑到这一点,我不认为地图功能是正确的选择。 Map旨在获取源数组,对每个元素执行一些变异操作,并在新数组中返回变异元素。它会创建一个您忽略的新数组。

对于您的多播委托设计模式,您不需要将源数组转换(映射)到目标数组。您需要让数组中的每个元素执行任务。

最好使用forEach方法。这一行

locationDelegates.map(closure)

看起来像这样:

locationDelegates.foreach
{
  closure()
}

(我认为我的语法正确 - 我最近在Objective-C工作并且在Swift中生锈了。)