- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在尝试从 Objective-C 切换到 Swift。我不明白声明函数以返回 AnyObject!
而不是 AnyObject?
的意义。
例如:
func instantiateViewControllerWithIdentifier(identifier: String) -> AnyObject!
为什么这个方法返回一个隐式展开的可选而不是一个简单的可选?我得到了 AnyObject 部分,但是允许我们避免使用 !
解包可选的(如果它可能为 nil)有什么意义呢? (因此使应用程序崩溃,即使这种情况极不可能发生)
我错过了什么?
这只是一种使用此方法的返回值而无需使用 !
的便捷方式,还是有其他我看不到的东西?在这种情况下,如果程序返回 nil
就注定要崩溃吗?
我觉得:
AnyObject
意味着 100% 的机会返回一些东西AnyObject?
表示有 50% 的机会返回 nil,您应该始终检查 nil AnyObject!
意味着 99% 的机会返回非 nil 的东西,不需要检查 nil此外,我假设与 Objective-C/NSObject 类有某种联系,但无法弄清楚是什么......
谢谢
最佳答案
Cocoa API 中隐式解包选项 (IUO) 的频率是将这些 API 从 ObjC 导入 Swift 的产物。
在 ObjC 中,所有对对象的引用都只是内存指针。就语言/编译器所知,任何指针在技术上总是可能为零。在实践中,一个接受对象参数的方法可能被实现为永远不允许传递 nil,或者一个返回对象的方法永远不会返回 nil。但是 ObjC 没有提供在 API 的 header 声明中断言这一点的方法,因此编译器必须假定 nil 指针对任何对象引用都是有效的。
在 Swift 中,对象引用不仅仅是指向内存的指针;相反,它们是一种语言结构。通过允许我们断言给定的引用总是指向一个对象,或者使用可选值来允许这种可能性并要求考虑到它,这会获得额外的安全性。
但是在引用很可能永远不会为 nil 的情况下,处理可选的展开可能会很痛苦。所以我们还有 IUO 类型,它允许您使用可选值而不用检查它们是否为 nil(风险自负)。
因为编译器不知道 ObjC API 中的哪些引用可以或不可以安全地为空,所以它必须使用某种可选类型导入 ObjC API(Apple 的或您自己的)中的所有对象引用。无论出于何种原因,Apple 选择对所有导入的 API 使用 IUO。可能是因为许多(但重要的是不是全部!)导入的 API 实际上是不可空的,或者可能是因为它允许您像在 ObjC 中一样编写链接代码(self.view.scene.rootNode
等)。
在某些 API(包括大部分 Foundation 和 UIKit)中,Apple 已手动审核导入的声明以使用完整的可选(例如 UIView?
)或非可选引用(UIView
) 在语义适当时代替 IUO。但并非所有 API 都经过审核,有些 API 仍在使用 IUO,因为这仍然是这些 API 最适合做的事情。 (例如,他们非常一致地总是将 id
导入为 AnyObject!
。)
因此,回到您问题中的表格:最好不要从概率的角度思考。在处理返回的 API 时...
AnyObject
:总是有一个值,不能为零。 AnyObject?
:可能为 nil,必须检查是否为 nilAnyObject!
:没有保证。阅读该 API 的 header 、文档或源代码(如果可用),以了解它是否真的适合您的情况并相应地处理它。或者只是假设它可以为零并进行防御性编码。在instantiateViewControllerWithIdentifier
的情况下, 有两个选项你可能认为同样有效:
假设您保证永远不会得到 nil,因为您知道您在 Storyboard中放置了一个带有该标识符的 View Controller 并且您知道它是什么类。
let vc = storyboard.instantiateViewControllerWithIdentifier("vc") as MyViewController
// do stuff with vc
假设您的 Storyboard将来可能会发生变化,并为自己设置一个有意义的调试错误,以防万一您破坏了某些东西。
if let vc = storyboard.instantiateViewControllerWithIdentifier("vc") as? MyViewController {
// do something with vc
} else {
fatalError("missing expected storyboard content")
}
关于ios - 在 Apple 方法中隐式解包可选,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26019929/
考虑以下两个应用程序: 1: public partial class MainWindow : Window { public MainWindow() { Init
我写了一些被https://github.com/protobuf-c/protobuf-c/wiki/Examples引用的c代码 Operation msg = OPERATION__INIT;
我在使用 SwiftyJSON 正确解开字符串时遇到问题 output: ["AAPL"] stockData = try Data(contentsOf: url!)
我有一个只包含属性的类,我想对其进行打包/解包。我应该实现什么 collections.abc 才能获得此行为? class Item(object): def __init__(self,
考虑以下表达式。请注意,某些表达式被重复以呈现“上下文”。 (这是一个很长的 list ) a, b = 1, 2 # simple sequence
我正在尝试将变量表作为参数解包到函数调用中。简而言之,我正在考虑通过这样做将依赖项注入(inject)到我的过程中。当我在 https://www.lua.org/cgi-bin/demo 执行此操作
我正在尝试弄清楚如何赋予对象解包值的能力。 我想出的用例如下: 让我们有一个 Interval 类,我们将使用它来评估实值函数。 我们想问 成员资格,因此 __contains__。 通过调用特定步骤
所以我知道有一些库可以为我做到这一点,但我想学习打包/解包。 我的目标是让用户输入 IP 地址/子网掩码,然后验证其是否有效。 我想到的一种方法是“sprintf”并获得一个二进制值,比如说 192.
所以我知道有一些库可以为我做到这一点,但我想学习打包/解包。 我的目标是让用户输入 IP 地址/子网掩码,然后验证其是否有效。 我想到的一种方法是“sprintf”并获得一个二进制值,比如说 192.
我正在通过Go v1.13 Go v1.14中的错误跟踪进行检查。为什么看起来只有errors.Is()才能找到没有参数或带有值接收器的错误实现?这意味着能够包装的错误实现必须具有一个值接收器,以便能
我需要解包由其他开发人员创建的 Oracle 包。我在我的数据库中创建了 Prackage,但采用加密格式。 我需要的原因是,原来的开发人员已经离开了组织,现在包中定义的过程需要重新定义,以更新 DB
我打算在文件中使用 unpack。首先我用一个字符串测试。当我在字符串中嵌入空格时,下面的脚本将其显示为空。当我测试文件空间时,它正在被正确读取。不确定为什么在我处理字符串时将其更改为 null。我可
我在 Perl 中遇到这个问题已经有几天了,在搜索了无数的手册页、perldocs 和谷歌搜索了太多的搜索词之后,希望这里有人能帮助我。 我得到两个表示十六进制值的字符串,即“FFFF”,而不是 Pe
在 Python 中解压 SequenceMatcher 循环结果以便轻松访问和处理值的最佳方法是什么? from difflib import * orig = "1234567890" comme
假设,我有一个列表, [(1,2), (3, 4)]. 如果列表中的所有元素都是元组,我将打印 1 + 2 和 3 + 4。但是,如果任何一个元素也是一个列表,那么我将 1 加到内部列表的每个元素,并
我有这样的字典列表。 rows = [ {'user': staff_user, 'grade': [u'0.0', u'N/A', u'N/A', u'N/A', u'N/A']}, {'user'
我有这个代码... function a(options) { for (var item in options) { if ( ! options.hasOwnProperty
我试图通过 std::tie 解压一个 std::array: #include #include int main() { std::array arr = {1, 2, 3};
我的数据包嗅探器有问题。目标端口和源端口在我的嗅探器中似乎是错误的。在 wireshark 中,端口与我的嗅探器完全不同。没有结果包含预期来自 TLS 的端口 443。 (整个 tcp 片段可能是错误
如何使用 php 以大端字节顺序打包/解包 float ?我通过解包功能走到了这一步,但我不确定这是否可行。 function unpackFloat ($float) { $n = unpa
我是一名优秀的程序员,十分优秀!