Подтвердить что ты не робот

Какая разница между протоколом, распространяемым от AnyObject и протоколом только для классов?

Оба этого объявления

protocol SomeProtocol : AnyObject {
}

и это объявление

protocol SomeProtocol : class {
}

похоже, делает это так, что только классы могут соответствовать этому протоколу (то есть, что экземпляры протокола являются ссылками на объекты) и не имеют других эффектов.

Есть ли разница между ними? Должен ли быть предпочтительнее другого? Если нет, то почему есть два способа сделать одно и то же?

Я использую последний выпущенный Xcode 6.3.1.

4b9b3361

Ответ 1

Что касается ответа https://forums.swift.org/t/class-only-protocols-class-vs-anyobject/11507/4, этот ответ не рекомендуется. Эти слова сейчас одинаковы.

DEPRECATED

Обновление: после консультации с полномочиями, эти два определения, как предполагается, эквивалентны, с AnyObject, используемым в качестве AnyObject, в то время как class был закончен. В будущем последние откажутся от первых, но пока они представляют некоторые незначительные различия.

Разница заключается в семантике объявлений @objc. В AnyObject, что соответствующие классы могут быть или не быть собственными объектами Objective-C, но язык все равно обрабатывает их как таковые (в этом случае иногда вы теряете статическую диспетчеризацию). Вывод из этого заключается в том, что вы можете лечить AnyObject et al. ограничение протокола как способ @objc функций-членов @objc как показано в примере в документации для AnyObject в STL:

import Foundation
class C {
     @objc func getCValue() -> Int { return 42 }
}

// If x has a method @objc getValue()->Int, call it and
// return the result.  Otherwise, return nil.
func getCValue1(x: AnyObject) -> Int? {
    if let f: ()->Int = x.getCValue { // <===
        return f()
    }
    return nil
}
 // A more idiomatic implementation using "optional chaining"
func getCValue2(x: AnyObject) -> Int? {
    return x.getCValue?() // <===
}
 // An implementation that assumes the required method is present
func getCValue3(x: AnyObject) -> Int { // <===
    return x.getCValue() // x.getCValue is implicitly unwrapped. // <===
}

Тот же пример сразу падает, если вы измените его на протокол class -deriving:

import Foundation

protocol SomeClass : class {}

class C : SomeClass {
    @objc func getCValue() -> Int { return 42 }
}

// If x has a method @objc getValue()->Int, call it and
// return the result.  Otherwise, return nil.
func getCValue1(x: SomeClass) -> Int? {
    if let f: ()->Int = x.getCValue { // <=== SomeClass has no member 'getCValue'
        return f()
    }
    return nil
}

// A more idiomatic implementation using "optional chaining"
func getCValue2(x: SomeClass) -> Int? {
    return x.getCValue?() // <=== SomeClass has no member 'getCValue'
}

// An implementation that assumes the required method is present
func getCValue3(x: SomeClass) -> Int { // <===
    return x.getCValue() // <=== SomeClass has no member 'getCValue'
}

Таким образом, кажется, class - это более консервативная версия AnyObject которую следует использовать, когда вы заботитесь только о ссылочной семантике, а не о динамическом поиске членов или соединении Objective-C.

Ответ 2

AnyObject - это протокол, к которому все классы неявно соответствуют (источник). Поэтому я бы сказал, что нет никакой разницы: вы можете использовать либо требование ограничения класса.

Ответ 3

В руководстве по языкам программирования Swift для протоколов, в разделе " Протоколы только для класса ". Здесь упоминается только AnyObject, но не class.

Вы можете ограничить принятие протокола типами классов (а не структурами или перечислениями), добавив протокол AnyObject в список наследования протоколов.

protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
    // class-only protocol definition goes here
}

По этой причине я предлагаю использовать AnyObject над class для нового кода или нового проекта. Кроме этого, я не вижу никакой очевидной разницы между ними.

Ответ 4

На это ответил официальный разработчик Swift (Slava_Pestov) на форумах Swift. Вот резюме:

  • Вы должны использовать AnyObject (protocol SomeProtocol: AnyObject).

  • AnyObject и class эквивалентны. Нет никакой разницы.

  • class со временем станет устаревшим.

Ответ 5

Я заранее оговорился. @MartinR должен действительно ответить на это, так как он тот, кто исправил меня и предоставил правильную информацию.

Реальное различие заключается в том, что протокол с квалификатором класса может применяться только к классу, а не к структуре или перечислению.

Мартин, почему бы вам не ответить, и OP может принять ваш ответ?

Ответ 6

Если вы откроете справку (alt-click) в Xcode 9 для class в строке, такой как protocol P: class {}, вы получите typealias AnyObject.

Таким образом, скомпилированный код (в Swift 4) будет одинаковым независимо от того, ограничиваете ли вы протокол class или AnyObject.

Тем не менее, есть также вопрос стиля и будущих опций - будущая версия Swift может захотеть по-разному относиться к class и AnyObject, даже если сейчас это не так.