2015-04-21 2 views
1

Я столкнулся с очень странным поведением, и я действительно не могу сделать головы или хвосты. Я пытаюсь сохранить типы классов в массиве и хочу позвонить позже, но он не работает. Вот мой кодБыстрое downcasting не работает

class BaseClass { 

    class func getDetails() -> String { 
     return "aaaaaa" 
    } 
} 

class Foo: BaseClass { 

    override class func getDetails() ->String { 
     return "foo" 
    } 
} 


class Bar: BaseClass { 
    override class func getDetails() ->String { 
     return "bar" 
    } 
} 

var arr = [Foo.self, Bar.self] 
func test1() { 

    var x = Foo.self 
    println(x.getDetails()) //prints foo 
    if let y = arr[0] as? Foo.Type { 
     println(y.getDetails()) //doesn't execute 

    } 
    if let z = arr[0] as? BaseClass.Type { 
     println(z.getDetails()) //doesn't execute 
    } 
    if let t = arr[0] as? BaseClass { 
     println(t.dynamicType.getDetails()) //doesn't execute 
    } 
    // lets crash 
    var w = arr[0] as! Foo 
    //Could not cast value of type 'Test.Foo' (0x1085f17f0) to 'Test.Foo' (0x1085f1830). 

} 

Я особенно озадачило

Не удалось отбрасываемой значение типа 'Test.Foo' (0x1085f17f0) к 'Test.Foo' (0x1085f1830)

ошибка. Как я могу ссылаться на классы в массиве путем downcasting до BaseClass, чтобы я мог использовать его функцию getDetails

+0

Странная ваша реализация, я не знаю, как объяснить. Существует много проблем, например: вы объявляете getDetails как функцию класса, но, похоже, вы хотите вызвать функцию экземпляра. должен быть var 'w = arr [0] as! Foo.Type' быть законным –

+0

@HoaParis Там нет ничего незаконного, прочитайте его снова. – Sulthan

+0

@Sulthan: alinoz просто дал ответ, что я хочу сказать. –

ответ

1

Хм ... своеобразный. Это

var arr = [Foo.self, Bar.self] 
println(arr.count) 
println(arr) 

напечатает 2, то врезаться, но это работает отлично:

var arr: [BaseClass.Type] = [Foo.self, Bar.self] 
println(arr.count) 
println(arr) 

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

В разделе Определение иерархии классов для типа литья из The Swift Programming Language гида, мы находим

тип проверки Свифта может вывести, что фильм и песни имеют общий суперкласс MediaItem, и поэтому его выводит тип [MediaItem] для библиотеки массива:

let library = [ 
    Movie(name: "Casablanca", director: "Michael Curtiz"), 
    Song(name: "Blue Suede Shoes", artist: "Elvis Presley"), 
    Movie(name: "Citizen Kane", director: "Orson Welles"), 
    Song(name: "The One And Only", artist: "Chesney Hawkes"), 
    Song(name: "Never Gonna Give You Up", artist: "Rick Astley") 
] 
// the type of "library" is inferred to be [MediaItem] 

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

+0

Большое спасибо! Это была очень интересная ошибка. В качестве побочной заметки она также разбивала игровые площадки. Добавление '' ': [BaseClass.Type]' '' разрешило все мои проблемы. Меня действительно беспокоило, почему он не мог бросить BaseClass.Type. Во всяком случае, причиной, по которой я использовал функцию класса, является то, что я хочу получить статическую переменную класса, но получение переменных протоколов не выполняется, поэтому я перешел к подклассу. PS: Я думаю, '' ':' '' на первой строке вы разместили небольшую опечатку. – Meanteacher

+0

Ах, да, это была опечатка. Благодарю. Теперь это исправлено. – wltrup

0

Таким образом, Foo.self является эквивалентом [Object class] из объектива c. Так

var arr = [Foo.self, Bar.self] 

вы в основном создать массив типов классов (не объекты базового класса BaseClass - Foo, Bar)

На

var w = arr[0] as! Foo 

вы пытаетесь бросить класс type к объекту этого типа класса. Эта операция невозможна, но вы пытаетесь ее применять, используя! и это приведет к сбою.

Чтобы получить причину, почему другое понижающее приведение не работает попробуйте это в playgroung:

println("\(_stdlib_getDemangledTypeName(Foo.self))") 
println("\(_stdlib_getDemangledTypeName(Foo.Type))") 
+0

, мы знаем, что вопрос больше о случаях раньше. – Sulthan

+0

как @Sulthan упоминает, моя проблема была опусканием Foo на BaseClass. Последняя строка была там, потому что я пытался использовать все возможные комбинации. Извините, если он пропустил вас. – Meanteacher

+0

@Meanteacher вы попробовали последние 2 строки на своей игровой площадке? Каковы типы Foo.self? И каков тип Foo.Type? Вы не можете сбрасывать arr [0] в BaseClass, потому что arr [0] не является объектом типа Foo, а является объектом типа класса. – alinoz

0

Я подозреваю, что вы используете старую версию Swift. Я нахожу, что в 6.3 вам необходимо указать тип для arr (я подозреваю, что 6.2 решения это к чему-то не полезно, что, вероятно, является источником ваших проблем):

let arr: [BaseClass.Type] = [Foo.self, Bar.self] 

Давайте пройдемся по остальным:

let x = Foo.self 
println("x:" + x.getDetails()) //prints foo 

Yep; это следует ожидать.

if let y = arr[0] as? Foo.Type { 
    println("y" + y.getDetails()) //doesn't execute 
} 

Я нахожу, что оно выполнено в 6.3. Тем не менее, это не нужно, поскольку BaseClass включает в себя метод getDetails. Следующие работает точно также:

let y2 = arr[0] 
println("y2:" + y2.getDetails()) 

Следующая:

if let z = arr[0] as? BaseClass.Type { 
    println("z:" + z.getDetails()) //doesn't execute 
} 

Я считаю, что это выполнить, как и следовало ожидать, хотя это не нужно.

if let t = arr[0] as? BaseClass { 
    println(t.dynamicType.getDetails()) //doesn't execute 
} 

Это не может работать (и вы получите предупреждение). Класс не является экземпляром.

let w = arr[0] as! Foo 

И это сбой, как ожидалось, поскольку класс не является экземпляром.

Поэтому, если вы сделаете это правильно, не требуется литье типа. Вы можете просто иметь массив классов и называть их. Тем не менее, вы всегда должны думать о Swift о том, действительно ли вам нужен класс. Часто лучшим решением является структура и протокол.

+1

'[AnyObject.Type]' тоже будет работать. Я думаю, что Swift выводил этот тип на '[AnyObject]', а затем отбрасывания приходилось терпеть неудачу, потому что он думает, что массив фактически содержит экземпляры, а не классы. – Sulthan

+0

Я использую версию 6.3 (6D570) с Swift 1.2. Мне не потребовалось указать тип массива. Интересно, если на вашей стороне разные. @wltrup предоставил правильный ответ, который работал на меня. Я использовал протокол, но доступ к членам типа протокола не реализован. – Meanteacher

Смежные вопросы