2017-02-14 2 views
1
let f:() -> Void = { } 

let array = ["a", 1, false, f] as [Any] 

if array[3] is AnyObject { 
    print(array[3]) 
} 

Почему элемент, оценивающий значение true для AnyObject, даже если массив настроен на сохранение Any?Сохранение массива Любые объекты также имеют тип AnyObject

Почему функция оценивает значение true как объект AnyObject, хотя AnyObject по определению может быть только классами?

В качестве другого примера:

let f:() -> Bool = { return true } 
let ff = f as AnyObject 
(ff as() -> Bool)() 

Это противоречит определению AnyObject в API doc, в котором говорится, что:

AnyObject может быть использован в качестве конкретного типа для экземпляра любого класс, класс или протокол только для классов.

или официальный Swift Programming Language Guide:

• Любой может представлять собой экземпляр любого типа на всех, в том числе функции типов.

• AnyObject может представлять экземпляр любого типа класса.

В приведенном выше примере это выглядит как функция может быть представлена ​​как AnyObject.

В другом месте SO (как указано @hamish) есть объяснение, что внутренне, поскольку используется класс SwiftValue, все можно подключить к AnyObject. Логика объяснения кажется ошибочной/обратной, так как мы должны сделать реализацию соответствующей определению языка, а не наоборот, так что реализация неверна или определение оператора AnyObject и typecheck неверно?

+2

Потому что * все * является мостом в 'AnyObject' в Swift 3. См. [AnyObject не работает в Xcode8 beta6?] (http://stackoverflow.com/q/39033194/2976878) – Hamish

+1

Почему и как функция может быть сменена для AnyObject? Разве это не нарушает определение AnyObject? Такое поведение кажется неправильным, даже если это возможно. – Boon

+2

Прочтите связанные вопросы и ответы - вещи, которые несовместимы с Obj-C, помещаются в поле совместимого с Objc-C '_SwiftValue'. Причиной этого является тот факт, что 'id' теперь подключен к Swift как' Any', поэтому 'Any' нужно снова подключить к' id'. – Hamish

ответ

1

Во-первых, руководство по быстрому программированию не является языковой спецификацией в том смысле, что ISO 9899 определяет C. (И даже с учетом стандарта ISO не каждый компилятор реализует C одинаково или даже в 100% соответствии со стандартом .) Если вы обнаружите несогласие между компилятором и документацией, он также будет ошибкой документации как ошибка компилятора.

То есть, я считаю, вы умалчиваетесь важной частью спецификации вы ссылаетесь:

AnyObject также может быть использован в качестве конкретного типа для экземпляра типа, что мосты к объективно- C. Многие типы значений в Swift-мосте для сопоставлений Objective-C, например String и Int.

() -> Void эквивалентно dispatch_block_t, что мосты к ObjC как dispatch_object (см dispatch/object.h и os/object.h):

/* 
* By default, dispatch objects are declared as Objective-C types when building 
* with an Objective-C compiler. This allows them to participate in ARC, in RR 
* management by the Blocks runtime and in leaks checking by the static 
* analyzer, and enables them to be added to Cocoa collections. 
* See <os/object.h> for details. 
*/ 
OS_OBJECT_DECL_CLASS(dispatch_object); 

Так что нет ничего удивительного в том, что здесь () -> Void может быть принужден к AnyObject.

На практике довольно много ничего теперь может соединить в AnyObject (опять же, из спецификации языка точки зрения, все, что может быть NSValue может быть AnyObject, несмотря на то, что это не совсем, как это реализовано).

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

let b = true       // true 
let bany = true as Any    // true 
let banyobj = true as AnyObject  // 1 <=== (because it's NSNumber) 

MemoryLayout.size(ofValue: b)  // 1 (size of a bool) 
MemoryLayout.size(ofValue: bany)  // 32 (size of a protocol box) 
MemoryLayout.size(ofValue: banyobj) // 8 (size of a reference pointer) 

type(of: b)       // Bool.Type 
type(of: bany)      // Bool.Type 
type(of: banyobj)     // __NSCFBoolean.Type 

(Попробуйте то же самое для {}, чтобы увидеть, как замыкания обрабатываются.)

Разумно, чтобы открыть дефект против AnyObject документов, чтобы включить более явное объяснение, что любой тип может быть преобразован в ссылочный тип с использованием as AnyObject, но это просто упущение, а не противоречие с тем, что уже существует. (И если это было противоречие, или вы считаете, что это сбивает с толку, то снова правильный ответ заключается в том, чтобы открыть дефект, чтобы улучшить документы для соответствия Swift, а не Swift, чтобы соответствовать документам.)

+0

Очень проницательный, спасибо Роб! – Boon