当协议的可为空性发生变化时,支持多个 iOS SDK 版本



iOS11中的MCSessionDelegate协议已从

- (void)                    session:(MCSession *)session
didFinishReceivingResourceWithName:(NSString *)resourceName
fromPeer:(MCPeerID *)peerID
atURL:(NSURL *)localURL
withError:(nullable NSError *)error;

- (void)                    session:(MCSession *)session
didFinishReceivingResourceWithName:(NSString *)resourceName
fromPeer:(MCPeerID *)peerID
atURL:(nullable NSURL *)localURL
withError:(nullable NSError *)error;

这导致在Swift中实现此委托时,使用

func session(_ session: MCSession,
didFinishReceivingResourceWithName resourceName: String,
fromPeer peerID: MCPeerID,
at localURL: URL?,
withError error: Error?) {}

无法在Xcode 8上编译;并且

func session(_ session: MCSession,
didFinishReceivingResourceWithName resourceName: String,
fromPeer peerID: MCPeerID,
at localURL: URL,
withError error: Error?) {}

无法在Xcode 9上编译。

在这两种情况下,Xcode都会显示此错误:

"session(_:didFinishReceivingResourceWithName:fromPeer:at:withError:)"的参数具有与协议"MCSessionDelegate"所要求的不同的可选性


如何使其在两个版本上编译?

我不明白为什么这是一个问题。

如果您使用 Xcode 8 进行构建,则可以使用旧方法签名,构建应用并将其提交到 AppStore。该应用程序将针对 iOS10 SDK 构建,并将在 iOS10 和 iOS11 设备上运行。

当您切换到 Xcode 9 时,您可以切换到新的方法签名,并(当 Xcode 9 超出测试阶段时)提交到 AppStore。该应用程序基于 iOS11 SDK 构建,将在 iOS11 设备上运行。

唯一的困难是您可能想要同时使用 Xcode 8(立即发布应用程序更新)和 Xcode 9(准备在 iOS11 发布后发布应用程序)的短暂时期。你需要在你的 git 存储库中有一个单独的 iOS11 分支 - 但无论如何你都会这样做,对吧?

要通过 XCode 版本的混合和匹配来改进代码,您可以检查 swift 版本,例如

#if swift(>=2.3)
let specifier = url.resourceSpecifier ?? ""
#else
let specifier = url.resourceSpecifier
#endif

但是这里有一个小助手可能很有用..在 http://radex.io/xcode7-xcode8/上找到:

func optionalize<T>(x: T?) -> T? {
return x
}

我知道,这有点奇怪。如果你第一次看到结果,也许会更容易解释:

let URL = optionalize(url) ?? "" // works on both versions!

我们正在利用可选提升来摆脱调用站点上丑陋的条件编译。看,optionalize() 函数的作用是将你传入的任何内容转换为 Optional,除非它已经是 Optional,在这种情况下,它只是按原样返回参数。这样,无论 url 是可选的 (Xcode 8) 还是不是可选的 (Xcode 7),"可选"版本始终相同。

(更详细地解释:在 Swift 中,Foo 可以被认为是 Foo 的一个子类型?,因为您可以将 Foo 的任何值包装在 Optional 中而不会丢失信息。由于编译器知道这一点,它允许你传递一个非可选的参数来代替一个可选的参数——将Foo提升到Foo?

最新更新