2015-04-24 2 views
1

Я пытаюсь создать общую функцию, которая принимает закрытие в качестве параметра. У меня проблема, поэтому, чтобы изолировать проблему, я создал следующий код, который можно запустить на игровой площадке.Swift создает экземпляр неправильного типа при использовании общей функции с закрытием

class BaseClass { 
    init(message: String) { 
     println("Base class says: " + message) 
    } 

    func getMyName() -> String { 
     return "BaseClass" 
    } 
} 

class SubClass: BaseClass { 
    override init(message: String) { 
     println("Subclass says: " + message) 
     super.init(message: message) 
    } 

    override func getMyName() -> String { 
     return "SubClass" 
    } 

    func specialAbility() { 
     println("only I can do this!") 
    } 
} 

func makeInstance<T: BaseClass>(callback: (T -> Void)?) { 
    callback?(T(message: "hello")) 
} 

makeInstance() { 
    (instance: SubClass) in 
    println("makeInstance1 built a " + instance.getMyName()) 
    println("I think it is a \(_stdlib_getDemangledTypeName(instance))") 

    //instance.specialAbility() - uncommenting this throws EXC_BAD_ACCESS at runtime 
} 

makeInstance() { 
    (instance: BaseClass) in 
    println("makeInstance2 built a " + instance.getMyName()) 
    println("I think it is a \(_stdlib_getDemangledTypeName(instance))") 
} 

Этот код производит следующий вывод:

Base class says: hello 
makeInstance1 built a BaseClass 
I think it is a __lldb_expr_89.SubClass 
Base class says: hello 
makeInstance2 built a BaseClass 
I think it is a __lldb_expr_89.BaseClass 

Swift не позволяет явно указать тип в вызове функции (например, makeInstance), поэтому я ожидал компилятор умозаключениях от типа закрытия в вызове. Кажется, что каждый раз создается экземпляр BaseClass. Инициализатор SubClass не вызывается, а его члены, как и элементы BaseClass.

Я полагаю, это похоже на ошибку в Swift; если вы попытаетесь получить доступ к члену SubClass в первом закрытии, у компилятора нет проблем с ним, но во время выполнения возникает исключение (см. мой комментарий в коде).

Любые идеи, как я могу обойти это? Если это не ясно, я хотел бы создать подкласс BaseClass, когда его ожидает.

+0

На самом деле, более играя вокруг показал, что закрытие не имеет ничего общего с ним. Проблему можно увидеть, как это тоже (извините за плохое форматирование): 'FUNC makeInstance () -> T { возврата T (сообщение: "привет") } пусть инст: SubClass = makeInstance() println ("makeInstance() make (inst.getMyName())") // показывает BaseClass' Я думаю, что проблема связана с этой проблемой (http://stackoverflow.com/questions/ 27117921/неспособный к вызову-initializer-for-subclass-of-generic-type), однако я не могу заставить это решение работать для меня здесь. –

ответ

2

Я на самом деле просто менял инициализаторы к необходимости, как это:

class BaseClass { 
    required init(message: String) { 
     println("Base class says: " + message) 
    } 

    func getMyName() -> String { 
     return "BaseClass" 
    } 
} 

class SubClass: BaseClass { 
    required init(message: String) { 
     println("Subclass says: " + message) 
     super.init(message: message) 
    } 
    ... 
} 

и работает без каких-либо проблем

+0

Вау, ты совершенно прав. Большое спасибо за помощь! –

+0

Я мог ошибаться в этом, я все еще изучаю Swift, но если я не ошибаюсь, причина этого заключается в следующем: тег 'required' означает, что каждый подкласс должен реализовать этот инициализатор. Если вы не сделали свой инициализатор «обязательным», у вас может быть подкласс с дополнительными свойствами, который не имеет этого инициализатора. Это означает, что могут быть некоторые свойства, которые еще не инициализированы, но Swift не позволяет оставить какое-либо свойство без инициализации после вызова init. – SnyersK

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