Swift Protocol as Generic Parameter - swift

Given this class:
class ServiceRegistry {
var store = [String : AnyObject]()
var allRegisteredType: [String] {
return store.map { $0.0 }
}
func registerInstance<T>(instance:AnyObject, forType type: T.Type) {
store[String(type)] = instance
}
func instanceForType<T>(type: T.Type) -> T? {
return store[String(type)] as? T
}
}
Is there a way I can enforce that T must be a Protocol, without using the #obj?

This is a modified version of my type assertion technique. I added the "as? AnyClass" assert so that the type can only be of protocol type. There might be a more elegant way of doing this but going through my notes and research about class assertion this is what I came up with.
import Foundation
protocol IDescribable:class{}
class A:IDescribable{}
class B:A{}
let a = A()
let b = B()
func ofType<T>(instance:Any?,_ type:T.Type) -> T?{/*<--we use the ? char so that it can also return a nil*/
if(instance as? T != nil && type as? AnyClass == nil){return instance as? T}
return nil
}
Swift.print(ofType(a,A.self))//nil
Swift.print(ofType(a,IDescribable.self))//A
Swift.print(ofType(b,B.self))//nil

Related

Provide class metadata to the generic in swift (Codable)

I have a method that works on Codables and does, among other things, this:
func doWhatever<T>() -> T? where T: Codable {
var myName = String(describing: T.self)
return nil // or whatever
}
Then i can get myName as the class name at run time to get the right data to create an instance of T.
Now some of my Codable need to provide a custom name for this.
So while i could edit ALL of my codables (a few hundred models) to conform to some protocol that provides name, i really want to avoid doing it.
Since there are no custom attributes in Swift, i concocted this;
protocol MetadataProvidingCodable {
static func customName() -> String
}
Then in my generic i can check whether the T conforms to it:
func doWhatever<T>() -> T? where T: Codable {
var myName = String(describing: T.self)
if T.self is MetadataProvidingCodable.Type {
myName = ... // Get customName() from T without an instance???
}
return nil // or whatever
}
But my problem is that i need to be able to call my static func on the T type without having an instance of T. Is that possible?
You can type cast the T.self as MetadataProvidingCodable.Type like that:
func doWhatever<T>() -> T? where T: Codable {
var myName = String(describing: T.self)
if let type = T.self as? MetadataProvidingCodable.Type {
myName = type.customName()
}
return nil // or whatever
}
Edit: If you can somehow move the common logic to a separate function, you can override the doWhatever() function with another one that return a type that conforms to both Codable and MetadataProvidingCodable.
Then the compiler will figure out what function will call based on the return type:
func doWhatever<T>() -> T? where T: Codable {
print("doWhatever: Codable")
var myName = String(describing: T.self)
return nil
}
func doWhatever<T>() -> T? where T: Codable & MetadataProvidingCodable {
print("doWhatever: Codable & MetadataProvidingCodable")
var myName = T.customName()
return nil
}
struct Example1: Codable {}
struct Example2: Codable, MetadataProvidingCodable {
static func customName() -> String {
return "Example2"
}
}
let example1: Example1? = doWhatever()
let example2: Example2? = doWhatever()
// prints
// doWhatever: Codable
// doWhatever: Codable & MetadataProvidingCodable

Problem with swift polymorphism and dynamic type

I just encountered a strange behavior in swift's inheritance handling, when it comes to polymorphism and dynamic types. The following code shows the problem I encounter, which basically is: The dynamic type is recognized correctly (printed by print("type(of: self) = \(classType)")), but the generic function testGeneric uses the wrong type.
class Global {
static func testGeneric<T: TestSuperClass>(of type: T.Type) {
print("T.Type = \(T.self)")
}
}
class TestSuperClass {
func run() {
let classType = type(of: self)
print("type(of: self) = \(classType)")
Global.testGeneric(of: classType)
}
}
class TestClass: TestSuperClass {
}
class TestClass2: TestSuperClass {
override func run() {
let classType = type(of: self)
print("type(of: self) = \(classType)")
Global.testGeneric(of: classType)
}
}
let testClass = TestClass()
let testClass2 = TestClass2()
testClass.run()
testClass2.run()
the printed output is
type(of: self) = TestClass
T.Type = TestSuperClass
type(of: self) = TestClass2
T.Type = TestClass2
So basically when calling testClass.run(), type(of: self) yields TestClass, which I would expect. The problem then is that the generic function testGeneric, which is called immediately afterwards, somehow does not work with type TestClass, but uses TestSuperClass instead.
What I personally would expect is
type(of: self) = TestClass
T.Type = TestClass
type(of: self) = TestClass2
T.Type = TestClass2
i.e., the generic function testGeneric using the type TestClass instead of TestSuperClass when called via testClass.run().
Questions:
- Do you have an explanation for that?
- How can I obtain the behavior I had in mind?
In Swift, the compiler want's to know at compile time which generic type to "infer". Therefore, the type system will bind to the static type. There is no such thing as dynamic type inference.
Therefore the compiler generates the following (see comments):
class TestSuperClass {
func run() {
let classType = type(of: self) // static MetaType TestSuperClass.Type
print("type(of: self) = \(classType)") // dynamic type: TestClass
Global.testGeneric(of: classType) // infer to static type, i.e. testGeneric<TestSuperClass>
}
}
As a result, T.self is TestSuperClass in your case, because that's what the compiler is able to see:
static func testGeneric<T: TestSuperClass>(of type: T.Type) {
print("T.Type = \(T.self)")
}
What you maybe want is the following:
static func testGeneric<T: TestSuperClass>(of type: T.Type) {
print("T.Type = \(type)")
}
Here, you do not print the type of T, but the (dynamic) value of the parameter type, which in your case is TestClass
To answer the second question: You will not be able to change the dynamic type of the retured array; it will always be [TestSuperClass] - although it will contain TestClass objects:
class Global {
static func testGeneric<T: TestSuperClass>(of type: T.Type) {
print("T.Type = \(T.self)")
}
static func returnObjects<T: TestSuperClass>(of theType: T.Type) -> [T] {
let newObj = theType.init()
let newObjType = type(of:newObj)
print("type(of: newObj) = \(newObjType)")
return [newObj]
}
}
class TestSuperClass {
required init() {
print ("TestSuperClass.init")
}
func run() {
let classType = type(of: self)
print("type(of: self) = \(classType)")
Global.testGeneric(of: classType)
let array = Global.returnObjects(of: classType)
let arrayType = type(of:array)
print("type(of: self) = \(arrayType)")
print (array)
}
}
class TestClass: TestSuperClass {
required init() {
super.init()
print("TestClass.init")
}
}
let testClass = TestClass()
testClass.run()
TestSuperClass.init
TestClass.init
type(of: self) = TestClass
T.Type = TestSuperClass
TestSuperClass.init
TestClass.init
type(of: newObj) = TestClass
type(of: self) = Array < TestSuperClass >
[__lldb_expr_21.TestClass]

Generic Return Type Based on Class

I'm trying to create factory method on a class that automatically casts to the class it's on.
extension NSObject {
// how can I get the return type to be the current NSObject subclass
// instead of NSObject?
class func create() -> NSObject {
return self.init()
}
// example: create(type: NSArray.self)
class func create<T:NSObject>(type:T.Type) -> T {
return T()
}
}
Example two works, but gets NO advantage from being a class method:
let result = NSArray.create(type: NSArray.self)
But I'd love to be able to just call:
let result = NSArray.create()
without having to cast afterwards. Is there a way to do this in Swift?
You can use the class-level Self for this:
extension NSObject {
class func create() -> Self {
return self.init()
}
}
let array = NSArray.create()
But I don't really see why you would, since you might as well just add an initializer.
The accepted answer does the trick, thanks!
However, I needed this for a case where I wasn't calling the init directly. Instead, I had an object that was of type NSObject and needed a forced downcast
As #Hamish pointed out from this other SO answer, you can use the generic inference on a class method if you're another layer deep (a method called by a class method).
class func create() -> Self {
return createInner()
}
class func createInner<T>() -> T {
// upcasting to NSObject to show that we can downcast
let b = self.init() as NSObject
return b as! T
}
let array = NSArray.create() // gives me an NSArray
An Example with CoreData
I still can't figure out how to get the fetch part to compile, so I'm using an external function still.
import CoreData
// callers use
// try fetch(type: SomeMO.self, moc: moc)
func fetch<T:NSManagedObject>(type:T.Type, moc:NSManagedObjectContext) throws -> [T] {
return try T.fetch(moc: moc) as! [T]
}
extension NSManagedObject {
class func makeOne(moc:NSManagedObjectContext) -> Self {
return makeOneInner(moc: moc)
}
private class func makeOneInner<T>(moc:NSManagedObjectContext) -> T {
let name = "\(self)"
let retVal = NSEntityDescription.insertNewObject(forEntityName: name, into: moc)
return retVal as! T
}
class func fetch(moc:NSManagedObjectContext) throws -> [NSManagedObject] {
let fetchReq:NSFetchRequest<NSManagedObject> = self.fetchRequest() as! NSFetchRequest<NSManagedObject>
let retVal = try moc.fetch(fetchReq) as [NSManagedObject]
return retVal
}
}

Unwrapping generic type

Let's say I have some variable with type
let someVariable: SomeType<AnotherType?>
and I am sure that this concrete instance not contain any nil of AnotherType?. Is there is general way to convert it to SomeType<AnotherType>? For example, I need this convert for use someVariable in some function.
It could go along these lines:
protocol _Optional {
associatedtype _Wrapped
func unveil() -> _Wrapped?
}
extension Optional: _Optional {
typealias _Wrapped = Wrapped
func unveil() -> _Wrapped? { return self }
}
extension SomeType where T: _Optional {
func rewrap() -> SomeType<T._Wrapped>? {
guard let _value = value.unveil() else { return nil }
return SomeType<T._Wrapped>(value: _value)
}
}
struct SomeType<T> {
let value: T
}
let someValue = SomeType<Int?>(value: 42) // SomeType<Int?>
let rewrappedValue = someValue.rewrap() // SomeType<Int>?
let forceUnwrappedValue = someValue.rewrap()! // SomeType<Int>
Specifics depend on details of the particular implementation for SomeType (I use a simplest assumption in my example).

Swift 2.0: Protocol Extension Class Method returning Self

In order to extend some functionalities of my NSManagedObject subclasses, I have defined a series of protocols:
protocol ManagedObjectFindable {
static func find(format:String, arguments: [AnyObject]?, inContext context:NSManagedObjectContext, entityName:String?) -> Self?
}
protocol UniquelyIdentifiable: ManagedObjectFindable {
var identifier: NSNumber? { get }
static func findWithIdentifier(identifier: Int, inContext context:NSManagedObjectContext) -> Self?
}
So then every NSManagedObject that has identifier in its data model entity can conform to UniquelyIdentifiable.
For that purpose I am utilising Swift 2.0 Protocol Extensions, where:
extension UniquelyIdentifiable {
static func findWithIdentifier(identifier: Int, inContext context:NSManagedObjectContext) -> Self? {
return self.find("identifier == %lld", arguments: [NSNumber(longLong: Int64(identifier))], inContext: context, entityName:nil)
}
}
Where find is defined as:
extension NSManagedObject: ManagedObjectFindable {
/** returns single entity if found, nil otherwise */
class func find(format:String, arguments: [AnyObject]?, inContext context:NSManagedObjectContext, entityName:String? = nil) -> Self? {
let objectEntityName:String
if let name = entityName {
objectEntityName = name
} else {
objectEntityName = String(self)
}
let fetchRequest = NSFetchRequest()
fetchRequest.entity = NSEntityDescription.entityForName(objectEntityName, inManagedObjectContext: context)
fetchRequest.fetchLimit = 1
fetchRequest.predicate = NSPredicate(format: format, argumentArray: arguments)
var persistentEntityº:NSManagedObject?
context.performBlockAndWait {
do {
let fetchResults = try context.executeFetchRequest(fetchRequest)
if (fetchResults.count != 0){
persistentEntityº = fetchResults.first as? NSManagedObject
}
} catch {}
}
if let persistentEntity = persistentEntityº {
return _safeObjectSelfCast(persistentEntity)
} else {
return nil
}
}
}
func _unsafeObjectSelfCast<T>(obj: AnyObject!) -> T { return obj as! T }
func _safeObjectSelfCast<T>(obj: AnyObject) -> T? { return obj as? T }
Now these methods correctly return Self? and compiler is silent on the coding time, however when compiling it gives me that error Method 'findWithIdentifier(_:inContext:)' in non-final class must return 'Self' to conform to protocol 'UniquelyIdentifiable'
Now the thing is that if instead of implementing that method in a protocol extension I would just extend my NSManagedObject subclass, it will go fine, but that kills the purpose of protocol extensions, when you are completely duplicating the same code across dozens of your NSManagedObject subclasses.
Any workaround, or I am really missing something?
Short answer:
Change Self? in extension to the NSManagedObject?.
Long answer: Self in protocol requirement acts as a placeholder for the class that will implement that protocol. So if you have
protocol SomeProtocol {
func returnSomething() -> Self
}
That means that if you implement it on Int, function returnSomething() should return Int, and if you implement it on Double it should return Double.
Since you are implementing UniquelyIdentifiable on NSManagedObject and your protocol has Self? requirement, you should return NSManagedObject?.