各位老铁们好,相信很多人对【译】:目标实现策略解析都不是特别的了解,因此呢,今天就来为大家分享下关于【译】:目标实现策略解析以及的问题知识,还望可以帮助大家,解决大家的一些困惑,下面一起来看看吧!
2016 年10 月12 日
Objective-C 中的id和 Swift 中的Any
使用Objective-C API 时,Swift 3 的接口比以前的版本更强大。例如,Swift 2 将Objective-C 中的id 类型映射到Swift 中的AnyObject 类型,并且通常只能保存该类型的值。 Swift 2 还为AnyObject 提供了一些桥接值类型(如String、Array、Dictionary、Set 和一些数字)的隐式转换,以便我们可以像NSString、NSArray 或其他基本集合类一样轻松使用它。 Swift 中的原生类型。这些转换与语言的其余部分不一致,导致很难理解什么可以用作AnyObject,从而导致错误。
在Swift 3 中,Objective-C 中的id 类型现在映射到Swift 中的Any 类型,它可以表示任何类型的值,无论是类、枚举、结构还是任何其他Swift 类型。这一变化使得Swift 中的Objective-C API 更加灵活,因为Swift 定义的值类型可以传递给Objective-C API 并作为Swift 中的类型获取,从而无需手动“装箱”类型(我理解为转换,解袋)。这些好处也扩展到了集合类:Objective-C 中的集合类型NSArray、NSDictionary 和NSSet 以前只接受AnyObject 类型的元素,现在可以保存任何类型的元素。对于Swift 中的哈希类集合,例如Dictionary 和Set,有一个新类型AnyHashable,它可以保存Swift 中遵守Hashable 协议的任何类型的值。简而言之,某些类型从Swift 2 到Swift 3 的映射关系发生了如下变化:
图片取自Apple 官方博客通常情况下,您的代码不需要进行大量更改来适应此更改。 Swift 2 代码中存在的AnyObject 值类型可以通过隐式转换转换为Any,并继续在Swift 3 中工作。但是,有些地方需要更改声明的变量和方法类型才能在Swift 3 中进行编译。此外,如果您的代码显式使用AnyObject 或Cocoa 中的类(例如NSString、NSArray 或NSDictionary),则由于对象和值类型之间的隐式差异,您将需要引入更显式的转换以用作NSString 或字符串。 Swift 3 中不允许进行转换。Xcode 中的自动迁移器将进行最小的更改,以确保您的代码从Swift 2 成功编译到3,但情况并不总是有利的。本文将指出您可能需要进行的一些更改,以及更改代码以使用id 作为Any 时需要注意的一些问题。
重写方法和遵守协议
创建一个继承自Objective-C 类的新子类并重写其方法,或遵守Objective-C 中的协议。当父类的方法使用Objective-C 中的id 类型时,此时应该修改子类方法的类型。一个常见的例子是NSObject 类的isEqual: 方法和NSCopying 协议的copyWithZone: 方法。在Swift 2 中,您可以创建一个遵守NSCopying 协议并继承自NSObject 的新子类,如下所示:
//斯威夫特2
类Foo: NSObject, NSCopying {
覆盖func isEqual(_ x: AnyObject?) -Bool { . }
func copyWithZone(_ zone: NSZone?) -AnyObject { . }
}在Swift 3 中,除了将方法的命名从copyWithZone (_ :) 更改为copy (with :) 之外,您还需要将这些方法接受的参数类型从AnyObject 更改为Any。如下图:
//斯威夫特3
类Foo: NSObject, NSCopying {
override func isEqual(_ x: Any?) -Bool { . }
func copy(with zone: NSZone?) -Any { . }
非类型集合
属性列表、JSON 和用户信息字典在Cocoa 框架中很常见,它将这些表示为非类型化集合。在Swift 2 中处理此类数据需要使用AnyObject 或NSObject 构造Array、Dictionary 或Set,并依赖隐式桥接转换来处理值类型:
//斯威夫特2
结构体状态{
var name: 字符串
var abbreviation: 字符串
varpopulation: 整数
var asPropertyList: [NSObject: AnyObject] {
var result: [NSObject: AnyObject]=[:]
//隐式转换在这里将String 转换为NSString.
结果["姓名"]=self.姓名
结果["缩写"]=self.缩写
//.这里将Int 转换为NSNumber。
结果["人口"]=self.population
返回结果
}
}
让加利福尼亚=州(name:"加利福尼亚",
缩写: "CA",
人口: 39_000_000)
NSNotification(name: "foo", object: nil,
userInfo: california.asPropertyList) 或者,您可以使用Cocoa 框架中的集合类,例如NSDictionary:
//斯威夫特2
结构体状态{
var name: 字符串
var abbreviation: 字符串
varpopulation: 整数
var asPropertyList: NSDictionary {
var 结果=NSMutableDictionary()
//隐式转换在这里将String 转换为NSString.
结果["姓名"]=self.姓名
结果["缩写"]=self.缩写
//.这里将Int 转换为NSNumber。
结果["人口"]=self.population
返回结果.copy()
}
}
让加利福尼亚=州(name:"加利福尼亚",
缩写: "CA",
人口: 39_000_000)
//NSDictionary 然后在这里隐式转换为[NSObject: AnyObject]。
NSNotification(name: "foo", object: nil,
userInfo: california.asPropertyList) 在Swift 3 中,不再支持隐式转换,因此上述两段代码都无法按原样工作。 Xcode中的迁移器可能会建议你使用as来一一进行类型转换,以确保这段代码能够正常工作,但还有更好的解决方案。 Swift 现在导入Cocoa API 来接受Any 或AnyHashable 类型的集合,因此我们可以使用[AnyHashable:Any] 而不是[NSObject:AnyObject] 或NSDictionary 声明集合类型,而无需更改任何其他代码:
//斯威夫特3
结构体状态{
var name: 字符串
var abbreviation: 字符串
varpopulation: 整数
//此处将字典类型更改为[AnyHashable: Any].
var asPropertyList: [AnyHashable: 任何] {
var result: [AnyHashable: 任何]=[:]
//不需要隐式转换,因为String 和Int 是子类型
//Any 和AnyHashable
结果["姓名"]=self.姓名
结果["缩写"]=self.缩写
结果["人口"]=self.population
返回结果
}
}
让加利福尼亚=州(name:"加利福尼亚",
缩写: "CA",
人口: 39_000_000)
//.您仍然可以在此处将其与Cocoa API 一起使用
通知(name: "foo",object: nil,
userInfo: california.asPropertyList)
AnyHashable类型
Swift 的Any 类型可以保存任意类型,但是Dictionary 和Set 需要的键类型是需要遵守Hashable 协议的类型,因此Any 代表的过于宽泛。从Swift 3 开始,Swift 标准库提供了一个新类型AnyHashable。与Any类似,它充当所有Hashable类型的父类,因此String、Int和其他Hashable类型的值可以隐式用作AnyHashable值。 AnyHashable 类型的值可以使用is, as! 动态检查或动态使用as?转换运算符。 AnyHashable 可以在从Objective-C 导入无类型NSDictionary 或NSSet 对象时使用,并且在纯Swift 中构建异构集合或字典时也很有用。
未链接上下文的显式转换
在某些特定情况下,Swift 无法自动桥接C 和Objective-C。例如,一些C 和Cocoa API 使用id* 指针作为“out”或“in-out”参数,而由于Swift 无法静态确定指针的使用方式,因此它无法自动对内存中的值执行桥接转换。在这种情况下,指针仍将显示为UnsafePointer。如果您需要使用这些无法自动桥接转换的API,您可以使用显式桥接转换,并在代码中使用as Type 或as AnyObject 显式转换。
//对象C
@interfaceFoo
- (void)updateString:(NSString **)字符串;
- (void)updateObject:(id *)obj;
@end //斯威夫特
func interactWith(foo: Foo) -(String, Any) {
var string="string" as NSString //显式转换
foo.updateString(string) //参数导入为UnsafeMutablePointerlet finishString=string as String
var object="string" 作为AnyObject
foo.updateObject(object) //参数导入为UnsafeMutablePointerlet finishObject=object as Any
返回(完成字符串,完成对象)
另外,Objective-C中的协议在Swift中仍然是类约束(只有类才能遵守协议),所以你不能让Swift中的结构体或枚举直接遵守Objective-C中的协议或使用轻量级的Magnitude泛型类。当你需要使用这些协议和API时,你应该像这样显式地将String转换为NSString,将Array转换为NSArray。
AnyObject属性查找
Any 没有与AnyObject 相同的方法来返回对象的描述信息。在Any 对象上查找属性或向非类型化Objective-C 对象发送消息可能会导致Swift 2 崩溃。例如,以下代码使用Swift 2 语法:
//斯威夫特2
func foo(x: NSArray) {
//通过魔法AnyObject 查找调用-description
打印(x[0].描述)
}在Swift 3中,description不再是Any类型对象的方法(通常我们会重写这个方法来获取对象的一些描述信息)。您可以执行x[0] as AnyObject 将x[0] 的值转换为AnyObject 类型以获取其描述:
//斯威夫特3
func foo(x: NSArray) {
//下标的结果现在是Any,需要强制获取方法查找
print((x[0] as AnyObject).description)
或者,将值转换为您期望的特定类型:
func foo(x: NSArray) {
//转换为您期望的具体对象类型
print((x[0] as!NSObject).description)
Objective-C中的Swift中的值类型
Any 可以包含您定义的任何结构、枚举、元组或其他Swift 类型。 Swift 3 中的Objective-C 桥可以将任何Swift 类型的值转换为Objective-C id 类型的兼容对象。这使得在Cocoa 集合中存储userInfo、字典和其他自定义Swift 类型对象变得更加容易。例如,在Swift 2 中,您需要将数据类型更改为类,或者手动加载它们,以将它们的值附加到NSNotification:
//斯威夫特2
struct CreditCard { number: UInt64,expiration: NSDate }
让PaymentMade="PaymentMade"
//我们不能将信用卡直接附加到通知中,因为它
//不是一个类,也不是桥接的。
//将其包装在Box 类中。
类框{
让值: T
init(value: T) { self.value=值}
}
让付款通知=
NSNotification(name: PaymentMade,
object: 盒子(value: 信用卡(number: 1234_0000_0000_0000,
Expiration: NSDate()))) 使用Swift 3,我们不需要Box 类,可以直接将对象附加到通知:
//斯威夫特3
让PaymentMade=Notification.Name("PaymentMade")
//我们可以将信用卡值直接与通知关联起来
让付款通知=
通知(name: PaymentMade,
object: 信用卡(number: 1234_0000_0000_0000,
过期: Date())) 在Objective-C 中,CreditCard 值将显示为id 兼容的NSObject 对象(此处存疑),使用Swift 的Equatable、Hashable 和CustomStringConvertible。如果原始Swift 类型存在,它将实现isEqual:散列和描述。在Swift 中,可以通过动态地将值转换回其原始类型来检索该值:
//斯威夫特3
让paymentCard=paymentNotification.object 作为!信用卡
print( paymentCard.number ) //1234000000000000 请注意,在Swift 3.0 中,一些常见的Swift 和Objective-C 结构类型将桥接为不透明对象(不透明对象到底是什么?),而不是Cocoa 中惯用的对象。例如,Int、UInt、Double 和Bool 桥接到NSNumber。其他大小的数字类型,例如Int8、UInt16 等仅桥接为不透明对象。尽管大多数Cocoa API 使用NSValue 包装的实例,但可变结构(例如CGRect、CGPoint 和CGSize)也桥接为不透明对象。如果您看到一些错误,例如发送到_SwiftValue 的无法识别的选择器,这表明Objective-C 代码正在尝试调用不透明Swift 值类型上的方法,您可能需要手动包装该类的实例,而不是使用Objective-C转换后的类型实例。
选项还有一个特殊问题。 Swift 中的Any 可以容纳任何内容,包括可选的,因此可以将可选类型的对象传递给Objective-C API,而无需先检查它,即使该API 是使用非空id 声明的,很可能会导致A涉及_SwiftValue 的运行时错误,而不是编译时错误。 Xcode 8.1 beta 中包含的Swift 3.0.1 对Objective-C 中的结构和可选值进行数字输入,以解决NSNumber、NSValue 和可选桥接中的上述限制:
* SE0139: 将数字类型桥接到NSNumber 并将Cocoa 结构桥接到NSValue
* SE0140: 当Optional转换为Any时发出警告,并将Optional桥接为其有效负载或NSNull
(以上两篇文章是Github上讲解swift-evolution中Swift类型转换的文章,有兴趣的同学可以阅读)
为了避免向前兼容性问题,您不应依赖_SwiftValue 类对不透明对象的实现,因为Swift 的未来版本可能允许更多Swift 类型桥接到惯用的Objective-C 类。
Linux可移植性
使用Swift Core 在Linux 上运行的Swift 库Swift 使用以Swift 原生编写的Foundation 版本,没有Objective-C 运行时桥。将id 映射到Any 允许核心库直接使用本机SwiftAny 和标准库值类型,同时使用Objective-C Foundation 实现来保持与Apple 平台上的代码兼容。由于Swift 不与Linux 上的Objective-C 互操作,因此不支持桥接转换,例如字符串到NSString 或值到AnyObject。希望在Cocoa 和Swift 核心库之间移植的Swift 代码应该只使用值类型。
学习更多
id 映射到Any 是Swift 语言改进的一个很好的例子,其灵感来自于用户对Swift 早期版本的反馈,并通过开放Swift Evolution 流程的回顾进行了改进。如果您想了解有关id 映射Any 背后的动机和设计决策的更多信息,可以在GitHub 上的swift-evolution 存储库中找到原始Swift Evolution 提案:
* SE-0072: 完全消除Swift 的隐式桥接转换
* SE0116: 将Objective-C id 导入为Swift Any 类型
* SE0131: 将AnyHashable 添加到标准库
最后,Swift 是一种更加一致的语言,并且使用Swift 时Cocoa API 变得更加强大。
所有博客文章
【【译】:目标实现策略解析】相关文章:
2.米颠拜石
3.王羲之临池学书
8.郑板桥轶事十则
用户评论
这篇博客看来很有深度!
有14位网友表示赞同!
感觉像是要探讨一些关于目标设置的哲学问题。
有11位网友表示赞同!
好想知道作者究竟是从哪个角度来解释 "Objective"?
有20位网友表示赞同!
一些人觉得设定目标会让人压力大,这篇文章里可能会讲到怎么避免这种情况?
有20位网友表示赞同!
目标是人生的关键所在,希望这篇博客能给带来一些启发。
有18位网友表示赞同!
从标题看,文章内容应该很实用,可以帮助我们更好地制定和实现目标。
有5位网友表示赞同!
我一直以来都对如何设定有效的目标比较困惑,期待看看这篇文章有什么新的观点。
有9位网友表示赞同!
目标是什么?它意味着什么? 这篇文章正好能解答我的疑问。
有19位网友表示赞同!
人生需要很多不同的目标, 这篇文章可能会涵盖生活的各个方面?
有5位网友表示赞同!
从 "Objective" 这个词来看,应该会深入探讨目标的本质和意义。
有20位网友表示赞同!
希望这篇文章能激发我思考,去明确自己的目标和方向。
有9位网友表示赞同!
文章或许会分享一些优秀的案例分析,让我们学习如何设定和实现目标?
有18位网友表示赞同!
感觉像是一篇学术性的文章,应该会有很专业的论述和分析。
有10位网友表示赞同!
越来越多人重视目标管理,这篇文章正好可以帮助我提升自己在这个方面的技能。
有16位网友表示赞同!
在这个竞争激烈的社会中,设定目标非常重要,这篇文章或许能给我一些指引。
有12位网友表示赞同!
读完这篇博客之后,我希望能够更有清晰的目标和计划去行动。
有8位网友表示赞同!
目标不是终点而是旅程的过程,希望能从文章里了解到更深刻的道理。
有14位网友表示赞同!
文章标题很吸引人,期待能学习到更多关于目标相关的知识!
有18位网友表示赞同!
“Objective”这个词语很有意思,也让我对这篇文章产生好奇心 。
有6位网友表示赞同!