oro*_*ome 3 oop objective-c swift
Apple的Swift编程语言指南指出了这一点
仅当协议标记有
@objc
属性时,才能检查协议一致性
如果我不与Objective-C互操作,为什么这是必要的?
更新Swift 1.2
@objc
关键字的需求.实际上,以下简单示例现在无法使用@objc
关键字:
protocol Ap {
func hello()
}
class A: Ap {
func hello() {
println("hello, world")
}
}
var a = A()
if (a as AnyObject) is Ap {
a.hello()
} else {
println("nope")
}
// hello, world
Run Code Online (Sandbox Code Playgroud)
此外,链接现在只是这样:
protocol-conformance-1-2:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0)
/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
@rpath/libswiftCore.dylib (compatibility version 0.0.0, current version 0.0.0)
Run Code Online (Sandbox Code Playgroud)
原版的:
我们来看一个例子.请注意,我还使用了额外的(varName as AnyObject)
调用,否则编译器会抱怨'is' test is always true
- 因为它确切地知道编译时类型是什么.
import Foundation
protocol Swifty {
func s()
// protocol-conformance.swift:5:2: error: 'optional' can only be applied to members of an @objc protocol
// optional var a: Int { get }
// ^
/*
optional var a: Int { get }
*/
}
protocol SwiftyClass: class {
func scl()
// protocol-conformance.swift:13:2: error: 'optional' can only be applied to members of an @objc protocol
// optional var a: Int { get }
// ^
/*
optional var a: Int { get }
*/
}
@objc protocol SwiftyConformance {
func scon()
optional var a: Int { get }
}
class SwiftyOnly: Swifty {
func s() {
println("s")
}
}
class SwiftyClassOnly: SwiftyClass {
func scl() {
println("scl")
}
}
class SwiftyConformanceOnly: SwiftyConformance {
func scon() {
println("scon")
}
}
class SwiftyConformanceWithOptional: SwiftyConformance {
func scon() {
println("sconwo")
}
var a: Int {
get { return 1; }
}
}
println("swifty")
var swifty = SwiftyOnly()
//protocol-conformance.swift:49:26: error: cannot downcast from 'AnyObject' to non-@objc protocol type 'Swifty'
//if (swifty as AnyObject) is Swifty {
// ~~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~
/*
if (swifty as AnyObject) is Swifty {
println("swifty is Swifty")
}
*/
// protocol-conformance.swift:47:34: error: cannot downcast from 'AnyObject' to non-@objc protocol type 'Swifty'
// if let s = (swifty as AnyObject) as? Swifty {
// ~~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~
/*
if let s = (swifty as AnyObject) as? Swifty {
s.s()
}
*/
println("")
println("swiftyClass")
var swiftyClass = SwiftyClassOnly()
//protocol-conformance.swift:61:31: error: cannot downcast from 'AnyObject' to non-@objc protocol type 'SwiftyClass'
/*
if (swiftyClass as AnyObject) is SwiftyClass {
println("swiftyClass is SwiftyClass")
}
*/
//protocol-conformance.swift:80:39: error: cannot downcast from 'AnyObject' to non-@objc protocol type 'SwiftyClass'
//if let s = (swiftyClass as AnyObject) as? SwiftyClass {
// ~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~
/*
if let s = (swiftyClass as AnyObject) as? SwiftyClass {
s.scl()
}
*/
println("")
println("swiftyConformanceOnly")
var swiftyConformanceOnly = SwiftyConformanceOnly()
if (swiftyConformanceOnly as AnyObject) is SwiftyConformance {
println("swiftyConformanceOnly is SwiftyConformance")
}
if let s = (swiftyConformanceOnly as AnyObject) as? SwiftyConformance {
s.scon()
if let a = s.a? {
println("a: \(a)")
}
}
println("")
println("swiftyConformanceWithOptional")
var swiftyConformanceWithOptional = SwiftyConformanceWithOptional()
if (swiftyConformanceWithOptional as AnyObject) is SwiftyConformance {
println("swiftyConformanceWithOptional is SwiftyConformance")
}
if let s = (swiftyConformanceWithOptional as AnyObject) as? SwiftyConformance {
s.scon()
if let a = s.a? {
println("a: \(a)")
}
}
println("")
Run Code Online (Sandbox Code Playgroud)
...(并且(没有取消注释损坏的代码测试用例),输出是:
swifty
swiftyClass
swiftyConformanceOnly
swiftyConformanceOnly is SwiftyConformance
scon
swiftyConformanceWithOptional
swiftyConformanceWithOptional is SwiftyConformance
sconwo
a: 1
Run Code Online (Sandbox Code Playgroud)
所以,简单的答案是一样的文档状态:你需要@objc
的协议一致性测试(和自选).
在Swift中,objc只是一个声明属性,通常表示编译器的提示或修改代码的生成方式.
但是更长的答案就引出了一个问题:"但为什么语言或运行时以这种方式编写?",而且这很难解决; 我的猜测是该@objc
属性将生成真正的Objective-C对象/协议引用,并且在运行时内使用该属性简单地实现一致性测试.
您可以在上面的示例中对/*和*/one之间的代码进行注释,并查看编译器抱怨的时间和位置.
更新:编译器和链接器更新
如果我们编译上面的内容:xcrun swiftc -sdk $(xcrun --show-sdk-path --sdk macosx) protocol-conformance.swift
并检查它链接到什么otool -L protocol-conformance
,我们看到
协议一致性:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0)
/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
@rpath/libswiftCore.dylib (compatibility version 0.0.0, current version 0.0.0)
@rpath/libswiftCoreGraphics.dylib (compatibility version 0.0.0, current version 0.0.0)
@rpath/libswiftDarwin.dylib (compatibility version 0.0.0, current version 0.0.0)
@rpath/libswiftDispatch.dylib (compatibility version 0.0.0, current version 0.0.0)
@rpath/libswiftFoundation.dylib (compatibility version 0.0.0, current version 0.0.0)
@rpath/libswiftObjectiveC.dylib (compatibility version 0.0.0, current version 0.0.0)
@rpath/libswiftSecurity.dylib (compatibility version 0.0.0, current version 0.0.0)
Run Code Online (Sandbox Code Playgroud)
...所以我认为做这些一致性测试更公平,你需要与Objective-C运行时进行交互,但我不一定说你需要与Objective-C进行交互(这对我来说意味着你必须要写的一些objc代码.
看一个非常简单的协议使用程序:
protocol Ap {
func hello()
}
class A: Ap {
func hello() {
println("hello, world")
}
}
var a = A()
a.hello()
//$ otool -L hello-world
//hello-world:
// /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0)
// /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
// @rpath/libswiftCore.dylib (compatibility version 0.0.0, current version 0.0.0)
Run Code Online (Sandbox Code Playgroud)
...但是如果只是尝试实现@objc协议而没有其他更改:
@objc protocol Ap {
func hello()
}
class A: Ap {
func hello() {
println("hello, world")
}
}
var a = A()
a.hello()
//$ xcrun swiftc -sdk $(xcrun --show-sdk-path --sdk macosx) hello-world.swift
//hello-world.swift:1:2: error: @objc attribute used without importing module 'Foundation'
//@objc protocol Ap {
// ^~~~
Run Code Online (Sandbox Code Playgroud)
......然后如果我们导入基金会:
import Foundation
@objc protocol Ap {
func hello()
}
class A: Ap {
func hello() {
println("hello, world")
}
}
var a = A()
a.hello()
//$ otool -L hello-world
//hello-world:
// /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0)
// /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
// @rpath/libswiftCore.dylib (compatibility version 0.0.0, current version 0.0.0)
// @rpath/libswiftCoreGraphics.dylib (compatibility version 0.0.0, current version 0.0.0)
// @rpath/libswiftDarwin.dylib (compatibility version 0.0.0, current version 0.0.0)
// @rpath/libswiftDispatch.dylib (compatibility version 0.0.0, current version 0.0.0)
// @rpath/libswiftFoundation.dylib (compatibility version 0.0.0, current version 0.0.0)
// @rpath/libswiftObjectiveC.dylib (compatibility version 0.0.0, current version 0.0.0)
// @rpath/libswiftSecurity.dylib (compatibility version 0.0.0, current version 0.0.0)
Run Code Online (Sandbox Code Playgroud)
我甚至会说Swift标准库和运行时绝对使用Objective-C运行时,并且期望访问基础核心Objective-C框架,例如Foundation的核心功能.