2014-10-24 4 views
3

компании Apple Swift Programming Language Guide утверждает, чтоПочему «@objc» требуется для проверки соответствия протокола в Swift?

Вы можете проверить для протокола соответствия, только если протокол помечается с @objc атрибутом

Почему это необходимо, если я не взаимодействующими с Objective-C?

ответ

8

UPDATE для 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) 

ORIGINAL:

Давайте посмотрим на пример. Обратите внимание, что я также использовал дополнительные вызовы (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 [email protected] 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 [email protected] 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 [email protected] protocol type 'SwiftyClass' 
/* 
if (swiftyClass as AnyObject) is SwiftyClass { 
    println("swiftyClass is SwiftyClass") 
} 
*/ 
//protocol-conformance.swift:80:39: error: cannot downcast from 'AnyObject' to [email protected] 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 для protocol conformance testingoptionals).

В Swift objc - это всего лишь атрибут объявления, который обычно представляет собой намеки на компилятор или модифицирует способ генерации кода.

Но более длинный ответ затем задает вопрос: «но почему язык или время исполнения написаны таким образом?», И это сложнее обратиться; я предполагаю, что атрибут @objc будет генерировать добросовестные ссылки Object/C Objective-C, а тестирование соответствия просто реализуется с использованием в течение времени выполнения.

Вы можете прокомментировать код в приведенном выше примере, который находится между/* и */по одному, и посмотреть, когда и где компилятор жалуется.

UPDATE: компилятор и компоновщик обновления

Если мы собираем выше: 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) 

... поэтому я считаю, что более справедливо сказать, что для выполнения этих тестов соответствия вам необходимо взаимодействовать со средой 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 и среда исполнения абсолютно u отлаживает время выполнения Objective-C и ожидает доступа к базовым объектно-ориентированным объектам, таким как Foundation для основных функций.

+0

Так TL; DR, что это потому, что протокол испытаний соответствия осуществляется в Objective-C время выполнения (не в Swift)? Другими словами - и это проверка соответствия протоколов crux - * * взаимодействует с Objective-C (даже если «я не»)? – orome

+0

@raxacoricofallapatorius несколько - я обновил выше с моим мнением, но ответ в основном «да» - вам нужно взаимодействовать со временем выполнения Objective-C. – greymouser

+0

@ RyanM: Предположительно неприемлемо в свете [(сообщается) изменений языка] (http://stackoverflow.com/a/29655235/656912). – orome

1

Swift развивалась с принятым ответ, и ответ сейчас:

Это не так.

The Swift Programming Language От:

Вы можете использовать есть и как операторы, описанные в типе литья для проверки протокола соответствия, а также приведение к определенному протоколу. Проверка и приведение к протоколу следует точно такой же синтаксис, как проверка и приведение к типу ...

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 { ... } 
Смежные вопросы