Crash while calling class initializer via generic method in Swift
| Originator: | BokkusuNoTegami | ||
| Number: | rdar://19142368 | Date Originated: | 04-Dec-2014 |
| Status: | Open | Resolved: | |
| Product: | Developer Tools | Product Version: | |
| Classification: | Crash | Reproducible: | Always |
Summary:
App crashes when trying to create class via convenience initializer.
Requirements :
• Use Swift
• initializer should be described in protocol
• convenience initializer described in protocol should be implemented in class extension
• initializer should be called with a help of generic method
• class should be marked with @objc
Crash happens with Xcode 6.1.1 (6A2008a) and Xcode 6.2 (6C86e). But perfectly works with Xcode 6.1 (6A1052d)
Example:
protocol P {
init(name: String)
}
@objc
final class C {
var name = "John Doe";
required init() {
}
}
extension C: P {
convenience init(name: String) {
self.init()
self.name = name;
}
}
func create<T: P>(name: String) -> T {
return T(name: name)
}
create("Bob") as C // Crash !!!
Steps to Reproduce:
1. Implement protocol:
protocol P {
init(name: String)
}
2. Implement class:
@objc
final class C {
var name = "John Doe";
required init() {
}
}
extension C: P {
convenience init(name: String) {
self.init()
self.name = name;
}
}
3.Implement generic method:
func create<T: P>(name: String) -> T {
return T(name: name)
}
4. call method described on step [3]:
let person = create("Bob") as C
Expected Results:
person variable should contain class C with name Bob
Actual Results:
Crash:
NSForwarding: warning: object 0x10c699c20 of class 'MyApp.C' does not implement methodSignatureForSelector: -- trouble ahead
Unrecognized selector +[MyApp.C initWithName:]
Version:
OS X 10.10.2 (14C68m)
Xcode 6.1.1 (6A2008a)
Xcode 6.2 (6C86e)
Notes:
Tested in iOS app with 8.x simulator.
Workarounds:
1. Use Xcode 6.1 (6A1052d)
2. Don't implement convenience initializer in class extension:
@objc
final class C: P {
var name = "John Doe";
required init() {
}
convenience init(name: String) {
self.init()
self.name = name;
}
}
3. Use class factory method instead:
protocol P {
class func create(name: String) -> Self
}
@objc
final class C {
var name = "John Doe";
required init() {
}
}
extension C: P {
class func create(name: String) -> C {
let c = C()
c.name = name
return c
}
}
func create<T: P>(name: String) -> T {
return T.create(name)
}
4. Don't use @objc mark, if you don't want objective-c support for your class
Comments
Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!