适配 iOS 8 时遇到的问题两则:远程推送和 Unwind Segue

时间:2022-06-01 20:16:13

原文:http://imtx.me/archives/1910.html

昨天我在微博上吐槽:iOS
8 / Xcode 6 真是史上对开发人员最糟糕的版本号了
。收到非常多朋友表达同感。

之所以这么说。倒不是针对 iOS 8 本身的特性来说的,相反,iOS 8 开放的那些扩展机制以及各种 Kit 对开发人员来说是很好。

我抱怨的是 Apple 近期对软件质量的控制不太好。上次发一个让手机不工作的 iOS 8.0.1 就不说了。iOS 8 / Xcode 6 本身充满了许多的 Bug。Xcode 作为 IDE,提交 App 的时候还常常失败。比方前几天我提交 Manico 1.4.1 版本号,Xcode 6 还直接失败,最后还用
Xcode 5 完毕了提交。

这让作为开发人员的我们很窝火。

除此之外。Apple 在 iOS 上的演进越来越激烈。为了推进新的系统特性,Apple 直接 break 了软件在升级后的向下兼容兼容特性。实在是让我惊讶。今天就谈两则近期遇到的吧。

实际上我要记录的这些在 Apple 的 WWDC 上应该都有提到,无奈视频没有所有看完。仅仅有在碰到问题的时候才去解决。

远程推送机制的变化

假设你还在代码里用 registerForRemoteNotificationTypes 这种方法来注冊推送功能。你的 App 又用 iOS 8 的 SDK 编译了。那么你的 App 在 iOS 8 下将无法注冊功能推送(在 iOS 7 下是能够的)。

Apple 直接将这个 API 在 iOS 8 下设置成了「无法工作」。而不是简单的标记了
deprecated。

那么在 iOS 8 下用哪个 API 去注冊远程推送功能?用新的 API:registerForRemoteNotifications。

可是,这个 API,只会注冊一个静默功能的远程推送,虽然 App 之后会收到推送并进行处理,它不会在用户界面上有不论什么提示。

那么怎样在 iOS 8 下完毕和 iOS 7 下一样的远程推送注冊支持?以下的代码能够让推送的支持在 iOS 7 和 iOS 8 下都正常工作,if 里面的是 iOS 8 的,而
else 那里是 iOS 7。

UIApplication *application = [UIApplication sharedApplication];

if ([application respondsToSelector:@selector(isRegisteredForRemoteNotifications)]) {
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIRemoteNotificationTypeBadge
|UIRemoteNotificationTypeSound
|UIRemoteNotificationTypeAlert)
categories:nil];
[application registerUserNotificationSettings:settings];
[application registerForRemoteNotifications];
} else {
[application registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge
|UIRemoteNotificationTypeSound
|UIRemoteNotificationTypeAlert)];
}

能够看到,iOS 8 把原先一步到位的 RemoteNotification 的注冊分成两部分,一部分是注冊新引入的那个「UIUserNotificationSettings」,还有一部分才是 RemoteNotifications。

Apple 为什么要这样设计?

简单的说,Apple 在 iOS 8 将 RemoteNotification 和 LocalNotification 统一了起来。

两种 Notifications 将统一由 UIUserNotificationSettings 来管理用户界面相关的东西:标记、声音和提醒。除了统一用户界面的通知外,UIUserNotificationSettings
还引入了 UIUserNotificationCategory,能够让用户方便的直接在 Notification 上进行一些快捷的操作(Action)。这部分我还没玩过,所以又不多讲了。

总之。Apple 为了推进新的技术,不惜直接把老的 API 弄成不工作,实在是让人惊叹…

Unwind Segue 的变化

Unwind Segue 是 Storyboard 里面一项我非常喜欢并且有用的技术。通过 Unwind,能够非常方便的在同一层级(通过 Push 进行)和不同层级(通过 Modal 进行)的 ViewController 之间进行回退,仅仅要前面的 ViewController 有一个实现了特定的 Unwind。那么在当前的
ViewController 运行这个 Unwind,就会回跳到前面的某个 ViewController,无论中间隔了几个,都能准确的跳回去。

喜欢这个技术主要是由于 Unwind 比 Delegate 更灵活。ViewController 中间能够隔好几个,不须要用 delegate 关联起来,仅仅要实现特定的 Unwind 方法就能够了。

然而,在 iOS 8 其中。非常遗憾的。Unwind 不再像曾经一样好好工作了:假设你的 ViewController 是基于NavigationController。那么如今它仅仅支持同一层级的 ViewController 之间的相互跳转(即通过 Push 方式产生的),而不支持不同层级的
ViewController 之间的相互跳转了(即通过 Modal 形式产生)。

Apple 没有什么 Depcated 的 Warning,直接就让 Modal 形式的 ViewController 下运行 Unwind 不工作了,没有不论什么错误和提示…

关于这个,* 上有一个讨论:Unwind
Segue not working in iOS 8

眼下为止,没有一个好办法(包含那个被接受的 Answer 实际上了不行),眼下为止我发现最好的办法就是重写相关代码,然后用 delegate 去实现。假设你有更好的办法,请记得告诉我。

后记

因为我差点儿相同是 iOS 7 时代才開始正式做 iOS 开发的,我不知道曾经 Apple 从 iOS 5 -> iOS 6,从 iOS 6 -> iOS 7 有没有过类似的直接把某个 API 弄为不工作,而不是循序渐进的 deprecated 的过程。

总之这次让我真切的体验会到新旧版本号切换时作为开发人员的阵痛,且不说破坏 API 的向下兼容究竟合不合适,光是 iOS 8 / Xcode 6 里各种令人无奈的 Bug 就让人足够头疼了。还是希望 Apple 能在 Xcode 6.1 里把问题变得少一些。

接下去,我要去适配 Manico 的 Yosemite 风格了…