仅当 iOS11 可用时才包含类的扩展
Posted
技术标签:
【中文标题】仅当 iOS11 可用时才包含类的扩展【英文标题】:Include an extension for a class only if iOS11 is available 【发布时间】:2017-12-11 23:14:37 【问题描述】:我正在尝试扩展一个用 Obj-C 编写的类,并包含一个用 Swift 编写的扩展,使其符合UIDropInteractionDelegate
,如下所示:
@available(ios 11.0, *)
extension NoteEditViewController: UIDropInteractionDelegate
@available(iOS 11.0, *)
public func dropInteraction(_ interaction: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal
let operation: UIDropOperation
if session.localDragSession == nil
operation = .forbidden
else
// If a local drag session exists, we only want to move an
// existing item in the pin board to a different location.
operation = .forbidden
return UIDropProposal(operation: operation)
@objc(setupDropInteractions)
@available(iOS 11.0, *)
func setupDropInteractions()
// Add drop interaction
self.view.addInteraction(UIDropInteraction(delegate: self))
我的问题是Project_Name-Swift.h
文件包含以下无法编译的代码:
@class UIDropInteraction;
@protocol UIDropSession;
@class UIDropProposal;
// This line is causing the issue saying "'UIDropInteractionDelegate' is partial: introduced in iOS 11.0"
@interface NoteEditViewController (SWIFT_EXTENSION(Bloomberg_Professional)) <UIDropInteractionDelegate>
- (UIDropProposal * _Nonnull)dropInteraction:(UIDropInteraction * _Nonnull)interaction sessionDidUpdate:(id <UIDropSession> _Nonnull)session SWIFT_WARN_UNUSED_RESULT SWIFT_AVAILABILITY(ios,introduced=11.0);
- (void)setupDropInteractions SWIFT_AVAILABILITY(ios,introduced=11.0);
@end
编译器抱怨该文件中的接口是部分的。
'UIDropInteractionDelegate' 是部分的:在 iOS 11.0 中引入
我以为包含@available(iOS 11.0, *)
会生成一个SWIFT_AVAILABILITY(ios,introduced=11.0)
来封装整个接口,但我错了。
有没有办法解决这个问题?
更新
我实现了一个玩具示例。
这是玩具 ViewController:
这里是快速扩展:
这里是生成的 dnd_toy-Swift.h 文件。
你说得对,它只是一个警告,但我的问题是我们必须将所有警告都视为项目中的错误。
关于如何从这里消除此警告的任何想法?
【问题讨论】:
【参考方案1】:你做的每件事都是正确的,如果不是非常迟钝,投诉是准确的。
基本上,由于您已(正确地)将该函数标记为在 iOS 11 中可用,编译器会警告您在任何针对 因此,您可以通过将部署目标设置为 iOS 11 来消除投诉,这意味着根本不允许 iOS 10 的用户安装它。或者,您可以使用新的(对 obj-c) Xcode 8 不支持此构造,因为它是 Swift 提供的 #available 构造的最新反向移植。 我在澄清我来自哪里。我似乎无法重现提问者所经历的情况,所以我正在展示我能够做到的事情。 我可以生成 2 个不同的编译器警告,它们相似但似乎与原始问题不同。 这是我从 有了更多信息来重现编译错误,我将能够提供更多帮助。 我发现我们之间的行为差异是由于我的项目是使用 Xcode 8.3 创建的,然后迁移到 9。在这些事情发生后,构建设置似乎有所不同。有问题的设置是 WWDC2017 - What's new in LLVM 中讨论了此设置,但他们所说的没有任何内容表明这种细微的行为差异。我猜这是clang的错误以及它如何处理两种设置之间的差异(但我欢迎其他输入)。我相信您已经知道,此代码在 iOS 10 上运行良好。此外,如果您将设置更改为简单的“是”,您仍然会收到有关 iOS 11 API 的正确警告。@available
构造来防范 API 的使用。if (@available(iOS 11, *))
[self setupDropInteractions];
更新
my_project-Swift.h
生成的objc接口:@interface NoteEditViewController (SWIFT_EXTENSION(conditional_class_declaration)) <UIDropInteractionDelegate>
- (UIDropProposal * _Nonnull)dropInteraction:(UIDropInteraction * _Nonnull)interaction sessionDidUpdate:(id <UIDropSession> _Nonnull)session SWIFT_WARN_UNUSED_RESULT SWIFT_AVAILABILITY(ios,introduced=11.0);
- (void)setupDropInteractions SWIFT_AVAILABILITY(ios,introduced=11.0);
@end
问题1:声明和objc属性符合协议
问题2:使用扩展中声明的方法
更新 2:希望是最后一个
CLANG_WARN_UNGUARDED_AVAILABILITY
,我认为这是 Xcode 9 的新设置。在迁移过程中,项目最终如下:
这映射到.pbxproject
文件中的术语YES
新建项目后:
这映射到术语YES_AGGRESSIVE
是.pbxproject
文件
【讨论】:
我正在防止在我的 obj-c 代码中使用 API,但错误仍然存在。如上所述,为Project_Name-Swift.h
文件中的扩展生成的接口不防版本,因此项目将无法编译。我需要构建与 iOS 10 兼容,因此您的第一个解决方案不是一个选项。
@Makaronodentro 您使用什么机制来防止使用?您是说这是一个“错误”,您是遇到运行时错误还是只是编译器警告?我提供了两种消除警告的解决方案,其中一种(使用if (@available(iOS 11, *))
与iOS 10 完全兼容,但需要Xcode 9。如果您需要使用Xcode 8 进行编译,那就另当别论了。
嘿,非常感谢您的调查!我目前正在使用 Xcode 9 Beta-2。我在 ViewController 中没有收到任何警告,因为我在界面中包含了 @available 保护和可用性宏。我在编译期间遇到“语义问题”。当“-Swift.h”文件被另一个文件导入时,我在界面中收到 warning 作为错误,它指向“中自动生成的 obj-c 界面” -Swift.h"
@Makaronodentro 如果您可以在示例项目中重现确切的问题或提供有关错误的更多详细信息,我可能会提供帮助。此外,请升级到 beta 3 以确保安全。
@Makaronodentro Nvm,我能够重现它,现在检查。【参考方案2】:
在 ObjC 中,将API_AVAILABLE(ios(11.0))
添加到函数定义的末尾将抑制警告。像这样:
- (nullable UISwipeActionsConfiguration *)tableView:(UITableView *)tableView leadingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath API_AVAILABLE(ios(11.0))
... function implementation ...
【讨论】:
有没有办法检查 iOS 11 不可用?【参考方案3】:Xcode 9 beta 4 将构建,如果 @available 添加到每个方法。如果仅在扩展级别添加 @available,构建仍然会失败。
【讨论】:
以上是关于仅当 iOS11 可用时才包含类的扩展的主要内容,如果未能解决你的问题,请参考以下文章
仅当 QProcess Stdout 包含子字符串时才打印它
仅当有要展示的特色产品时才包含自定义 slideshow.php