I'm tackling with generics in Swift. I've got extension to NSManagedObject
class and wanted to create initializer which is only available for classes which implements some protocol I defined. Now I've got something like below but this is not working and even not compiling. Could you help me make it working?
public extension NSManagedObject {
public convenience init<Self: Nameable>(context: NSManagedObjectContext) {
let entity = NSEntityDescription.entityForName(Self.entityName(), inManagedObjectContext: context)!
self.init(entity: entity, insertIntoManagedObjectContext: context)
}
}
public protocol Nameable {
static func entityName() -> String
}
Xcode says: "Generic parameter 'Self' is not used in function signature".
Swift Generic Function // create a generic function func displayData<T>(data: T){ ... } Here, We have created a generic function named displayData() . T used inside the angle bracket <> is called the type parameter.
Convenience initializers are secondary, supporting initializers for a class. You can define a convenience initializer to call a designated initializer from the same class as the convenience initializer with some of the designated initializer's parameters set to default values.
You write a failable initializer by placing a question mark after the init keyword ( init? ). Note: You cannot define a failable and a nonfailable initializer with the same parameter types and names. A failable initializer creates an optional value of the type it initializes.
An initializer is a special type of function that is used to create an object of a class or struct. In Swift, we use the init() method to create an initializer. For example, class Wall { ... // create an initializer init() { // perform initialization ... } }
As matt already explained, you cannot define an initializer which is restricted to types implementing a protocol. Alternatively, you could define a global function instead:
public protocol Nameable {
static func entityName() -> String
}
func createInstance<T : NSManagedObject>(type : T.Type, context : NSManagedObjectContext) -> T where T: Nameable {
let entity = NSEntityDescription.entity(forEntityName: T.entityName(), in: context)!
return T(entity: entity, insertInto: context)
}
which is then used as
let obj = createInstance(Entity.self, context)
You can avoid the additional type parameter if you define the method as
func createInstance<T : NSManagedObject>(context : NSManagedObjectContext) -> T where T: Nameable { ... }
and use it as
let obj : Entity = createInstance(context)
or
let obj = createInstance(context) as Entity
where the type is now inferred from the context.
It seems to me that you are describing something like this:
class Thing {}
func makeANewThing<T:ThingMaker>(caller:T) -> Thing {
let t = Thing()
return t
}
protocol ThingMaker {
}
class Dog : ThingMaker {
}
class Cat { // not a ThingMaker
}
let t = makeANewThing(Dog()) // ok
let t2 = makeANewThing(Cat()) // illegal
In real life, I presume that makeANewThing
would actually do something with its caller
, but the point is that it can only be called by passing a caller
that has adopted ThingMaker.
That is probably the best you can do in Swift 1. If you want to inject a method into only classes that adopt a certain protocol, then what you want is a protocol extension — but that is available only in Swift 2.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With