Objective c 为什么是'@objc';是否需要在Swift中检查协议一致性?
苹果公司声明: 只有在协议已标记的情况下,才能检查协议一致性 使用Objective c 为什么是'@objc';是否需要在Swift中检查协议一致性?,objective-c,oop,swift,Objective C,Oop,Swift,苹果公司声明: 只有在协议已标记的情况下,才能检查协议一致性 使用@objc属性 如果我没有与Objective-C进行互操作,为什么需要这样做?Swift 1.2的更新 正如RyanM指出的那样,语言的变化已经消除了对@objc关键字的需要 实际上,下面的简单示例现在可以在不使用@objc关键字的情况下工作: protocol Ap { func hello() } class A: Ap { func hello() { println("hello,
@objc
属性
如果我没有与Objective-C进行互操作,为什么需要这样做?Swift 1.2的更新
- 正如RyanM指出的那样,语言的变化已经消除了对
关键字的需要@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
此外,链接现在看起来仅如下所示:
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)
原件:
让我们看一个例子。请注意,我还使用了额外的(varName作为AnyObject)
调用,否则编译器会抱怨'is'测试始终为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("")
。。。并且(在不取消断开代码测试用例注释的情况下),输出为:
swifty
swiftyClass
swiftyConformanceOnly
swiftyConformanceOnly is SwiftyConformance
scon
swiftyConformanceWithOptional
swiftyConformanceWithOptional is SwiftyConformance
sconwo
a: 1
因此,简单的答案正如文档中所述:您需要(和)的@objc
在Swift中,只是一个声明属性,通常表示对编译器的提示或修改代码生成方式
但是较长的答案引出了一个问题:“但是为什么语言或运行时是这样写的呢?”,这一点很难回答;我的猜测是@objc
属性将生成真正的Objective-C对象/协议引用,而一致性测试只是在运行时使用该属性实现的
您可以在上面示例中的代码中一次注释一条介于/*和*/之间的代码,并查看编译器何时何地投诉
更新:编译器和链接器更新
如果我们编译上面的:xcrun swiftc-sdk$(xcrun--show sdk path--sdk macosx)协议一致性。swift
并检查它与otool-L协议一致性的链接,我们会看到
协议一致性:
/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)
。。。因此,我认为更公平的说法是,要进行这些一致性测试,您需要与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)
。。。但如果只是尝试在没有其他更改的情况下实现@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 {
// ^~~~
。。。然后,如果我们导入基金会:
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)
我甚至会说SWIFT标准库和运行时完全使用Objut-C运行时,并期望访问事实上的核心Objy-C框架,例如核心特征的基础。
< P> SWIFT从接受的答案开始发展,现在的答案是:
事实并非如此
发件人:
您可以使用类型转换中描述的is和as运算符来检查协议一致性,并转换到特定协议。检查并强制转换到协议遵循与检查并强制转换到类型完全相同的语法
因此,TL;DR是因为协议一致性测试是在Objective-C运行时内实现的(不是在Swift中)?换句话说——这是关键——协议一致性检查确实与Objective-C相互作用(即使“我不是”)?@raxacoricofallapatorius——我在上面更新了我的观点,但答案基本上是“是”--您必须与Objective-C运行时交互。@RyanM:暂时不接受。@raxacoricofallapatorius感谢您的提醒--新的语言功能使事情变得更简单。我用一个简单的例子更新了我的答案以反映这一点。
protocol PersonBasedView {
var person: Person? {get set}
}
class EmployeeView : UIView, PersonBasedView {
var person: Person?
}
// Elsewhere
var view = ...
if view is PersonBasedView { ... }
// or
if let personView = view as? PersonBasedView { ... }