背景
首先让我们总结一下我们所知道的。
我们有
- 在 iPhone 上运行的应用程序(我将其称为 iPhone 应用程序)
- 在 Watch 上运行的应用程序...特别是
- 在 Watch 上运行的 UI
- 作为扩展程序在 iPhone 上运行的代码。
第一行和最后一行对我们来说是最重要的。是的,扩展程序随您的 iPhone 应用程序一起运送到 AppStore,但是这两个东西可以在 iOS 操作系统中单独运行。因此,扩展程序和 iPhone 应用程序是两个不同的进程 - 两个在操作系统中运行的不同程序。
因此,我们不能使用[NSNotificationCenter defaultCenter],因为当您尝试在 iPhone 上使用NSLog() defaultCenter 和在 Extension 中使用 defaultCenter 时,它们将具有不同的内存地址。
达尔文来救援!
正如你想象的那样,这类问题对开发人员来说并不新鲜,恰当的说法是进程间通信。所以在 OS X 和 iOS 中有...达尔文通知机制。最简单的使用方法是从CFNotificationCenter 类中实现一些方法。
示例
当使用 CFNotificationCenter 时,你会发现它看起来与 NSNotificationCenter 非常相似。我的猜测是 NSNotif.. 是围绕 CFNotif.. 构建的,但我没有证实这个假设。言归正传。
假设您想从 iPhone 向 Watch 来回发送通知。我们应该做的第一件事是注册通知。
- (void)registerToNotification
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceivedNSNotification) name:@"com.example.MyAwesomeApp" object:nil];
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), (__bridge const void *)(self), didReceivedDarwinNotification, CFSTR("NOTIFICATION_TO_WATCH"), NULL, CFNotificationSuspensionBehaviorDrop);
}
您可能想知道为什么我为 NSNotificationCenter 添加了观察者?为了完成我们的任务,我们需要创建一些循环,稍后您将看到它。
至于第二种方法。
CFNotificationCenterGetDarwinNotifyCenter() - 获取达尔文通知中心
(__bridge const void *)(self) - 通知观察者
didReceivedDarwinNotification - callBack 方法,当对象收到通知时触发。
基本上和NSNotification中的@selector一样
CFSTR("NOTIFICATION_TO_WATCH") - 通知的名称,在 NSNotification 中也是一样,但这里我们需要 CFSTR 方法将字符串转换为 CFStringRef
最后两个参数object 和suspensionBehaviour - 在我们使用 DarwinNotifyCenter 时都被忽略了。
酷,所以我们注册为观察者。那么让我们实现我们的回调方法(有两种,一种用于CFNotificationCenter,一种用于NSNotificationCenter)。
void didReceivedDarwinNotification()
{
[[NSNotificationCenter defaultCenter] postNotificationName:@"com.example.MyAwesomeApp" object:nil];
}
现在,如您所见,此方法并非以 - (void)Name... 开头。为什么?因为它是C方法。你明白为什么我们需要 NSNotificationCenter 了吗?从 C 方法我们无权访问self。一种选择是声明自己的静态指针,如下所示:static id staticSelf 分配它staticSelf = self 然后从didReceivedDarwinNotification 使用它:((YourClass*)staticSelf)->_yourProperty 但我认为 NSNotificationCenter 是更好的方法。
然后在响应您的 NSNotification 的选择器中:
- (void)didReceivedNSNotification
{
// you can do what you want, Obj-C method
}
当我们最终注册为观察者时,我们可以从 iPhone 应用发送一些东西。
为此,我们只需要一行代码。
CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), CFSTR("NOTIFICATION_TO_WATCH"), (__bridge const void *)(self), nil, TRUE);
可以在您的 ViewController 或模型中。
再次,我们想要获得CFNotificationCenterGetDarwinNotifyCenter(),然后我们指定通知名称、发布通知的对象、字典对象(使用 DarwinNotifyCenter 时忽略,最后一个参数是问题的答案:立即交付?
以类似的方式,您可以将通知从 Watch 发送到 iPhone。出于显而易见的原因,我建议使用不同的通知名称,例如CFSTR("NOTIFICATION_TO_IPHONE"),以避免出现例如 iPhone 向 Watch 和自身发送通知的情况。
总结一下
MMWormhole 是一个非常优秀且编写良好的类,即使测试涵盖了大部分(如果不是全部)代码。它很容易使用,只需要记得在之前设置你的 AppGroups。
但是,如果您不想将第三方代码导入您的项目,或者出于其他原因不想使用它,您可以使用此答案中提供的实现。
特别是如果您不想/不需要在 iPhone 和 Watch 之间交换数据。
还有第二个好项目LLBSDMessaging。它基于伯克利套接字。更复杂并基于更底层的代码。这是冗长但写得很好的博客文章的链接,你会在那里找到到 Github 的链接。 http://ddeville.me/2015/02/interprocess-communication-on-ios-with-berkeley-sockets/.
希望对您有所帮助。