Conforming to a static function that returns "Self" - swift

When trying to conform to NSItemProviderReading, I get the following error:
The protocol definition for this method is as follows:
public static func object(withItemProviderData data: Data, typeIdentifier: String) throws -> Self
The protocol static function returns type "Self", I've tried to change it to the name of the actual class, but then it won't conform to NSItemProviderReading anymore.
How does one return "Self" ?
Update:
This is what happens when I ask Xcode to fix it:
It appends as! Self, but then shows 2 errors and this warning, it looks confusing cause it seems that it wants to revert back to how it was before, returning the instance of the class in this case NameData

Self in a protocol is a requirement that conformance of the protocol use their own type. So you need to change Self to NameData in the return type of the method when you conform this in your class extension.
extension NameData: NSItemProviderReading {
static func object(withItemProviderData data: Data, typeIdentifier: String) throws -> NameData {
return NameData(name: "Test")
}
}
And one more thing, you need to make your NameData class final.

Related

Why do I have to cast an instance of a class to Self to match the return type? [duplicate]

This code produces Xcode error messages that lead you in a circle. Let's say I have a protocol called Marker and I'd like Markers to copy themselves. Here's a first guess...
protocol Marker {
func copy() -> Self
}
class Marker1 : Marker {
func copy() -> Self {
return Marker1() // error here
}
}
(I'm not sure how to use Self correctly, because I can't find it in the The Swift Programming Language document. If you know where it's documented, please include that in answer.)
That code gives an error on the marked line: Cannot convert return expression of type 'Marker1' to return type 'Self' and it suggests a fix: Insert ' as! Self'.
I accept the fix:
...
return Marker1() as! Self
...
This leads to another compiler error: 'Self' is only available in a protocol or as the result of a method in a class; did you mean 'Marker1'?
If I accept that "fix" it goes back to the original error. I'd call that a bug in Xcode. Let's try something else:
func copy() -> Marker1 {
return Marker1()
}
Another error: Method 'copy()' in non-final class 'Marker1' must return `Self` to conform to protocol 'Marker'
Making the class final does fix the error. But is there a way to do this without making a class final? And where is Self documented?
With such a hierarchy, you would have to make the class conforming to the protocol final:
protocol Marker {
func copy() -> Self
}
final class Marker1 : Marker {
func copy() -> Marker1 {
return Marker1()
}
}
The final is needed because when you don't apply final and you create a subclass Marker2: Marker1 then copy would not return the correct class Self any more.
You can workaround that by creating a required initializer and always create the correct instance:
protocol Marker {
init()
func copy() -> Self
}
class Marker1 : Marker {
required init() {
}
func copy() -> Self {
let copy = type(of: self).init()
return copy
}
}
(original code removed because does not work)
Related: Implementing copy() in Swift
The issue with your current implementation is that Self is an abstract type, so you cannot simply return a concrete type, such as Marker1 from a function with a return type of Self. If you changed the return type to Marker1, you'd need to make your class final to ensure that no subclass can override the method, since in a subclass, Self would correspond to the subclass type. However, this is still not good since in this case the subclass won't conform to the protocol, since in a subclass of Marker1, the return type of Marker1 is not the same as self.
You can solve this problem by getting the metatype of your current class using type(of: self), then calling a designated initializer on the metatype, which will indeed return an instance of type Self. The final step is to create a required initializer for your class to ensure that all subclasses need to implement the same initializer that's called in your copy() method in order to make copy work for subclasses as well.
protocol Marker {
func copy() -> Self
}
class Marker1 : Marker {
func copy() -> Self {
let result = type(of: self).init()
return result
}
required init() {}
}

Swift: Generic Protocols

I have some swift structs for which protocol compliance is generated with individual extensions with equal methods names which just differ in their return types which are struct dependent. On top of That I want to use them in a generic function which Calls a protocol conforming function for a generic type).
I tried to accomplish this like that:
//: Playground - noun: a place where people can play
import UIKit
protocol FooProt {
typealias T;
static func createMe<T>()->T;
}
struct FooStruct{
}
extension FooStruct: FooProt{
typealias T = FooStruct;
static func createMe () -> FooStruct{
return FooStruct();
}
}
class Creator{
fun createOne<T where T:FooProt>(type:T.Type){
let instance = T.createMe();
}
}
Unfortunately I get the following error :
/var/folders/sn/78_zvfd15d74dzn01mdv258h0000gq/T/./lldb/3741/playground6.swift:7 :17: note: protocol requires function 'createMe()' with type ' () -> T' (aka '<τ_1_0> () -> τ_1_0')
static func createMe()->T;
What exactly doesn't comply here and is there a workaround ?
There are several problems with your code. On the one hand you have defined a protocol with an associated type. However, you define your createMe() method as a generic which uses some other type. I don't think that was your intent. I think your intent was to have a createMe() method that returns the same type as the protocol's associated type. In this case you need to remove the from the createMe() method. Also, the name createMe() implies that you aren't just returning any type, but the type of the object on which this method is being called. In this case, you don't even need an associated type protocol. You just need a protocol with a Self constraint which allows your code to be a bit simpler. In your Creator's createOne method, your type constraint is more complex than needed.
I think you want the following code:
protocol FooProt {
static func createMe()->Self;
}
struct FooStruct{
}
extension FooStruct: FooProt {
static func createMe() -> FooStruct {
return FooStruct();
}
}
class Creator{
func createOne<T:FooProt>(type: T.Type) -> T {
return T.createMe()
}
}
let foo = Creator().createOne(FooStruct.self)
Here is an alternate solution using an initializer in the protocol instead of a static method.
protocol FooProt {
init()
}
struct FooStruct{
}
extension FooStruct: FooProt {
}
class Creator{
func createOne<T:FooProt>(type: T.Type) -> T {
return T.init()
}
}
let foo = Creator().createOne(FooStruct.self)

Swift 2: understanding AnyObject and Self

I couldn't find any good explanation to my questions so I'd like to ask you directly. First of all I'd like to refine my code in this post.
My problem is the protocol AnyObject and the Self type. I didn't implement AnyObject into my code because it is marked with #objc and I don't want any Objective-C stuff involved in my code (don't judge me for that). I also couldn't find any explanation about the Self type. It just worked as expected, but Xcode does not replace Self with the type the static function is called at.
Here is some example:
extension Int : Instance {}
Int.singleton { (customInstanceName) -> Self in 0 } // Self shall be replaced with Int
As you can see Xcode produces a Self instead an Int. Is there any chance I could fix this? Am I right that Self does return the dynamicType and my implementation is fine as it is in my post above? I would really appreciate any good explanation about the Self type.
As you have seen in my code. I am using a custom protocol to check whether my instance is a class or not. Is there any other shiny implementation to check my instances if they are classes or structure types, or am I forced to use AnyObject if I want to get rid of my ClassInstance protocol?
Thank you for your time.
UPDATE:
protocol Test {}
class A : Test {}
struct B : Test {}
let aClass : Test = A()
let aStruct : Test = B()
if let someClass = aClass as? AnyObject {
print(someClass) // only this will print
}
if let someStruct = aStruct as? AnyObject {
print(someStruct)
}
This will work, but AnyObject is still marked as an #objc protocol.
The Self type can be only used in protocols where it is a implicit typealias of the type which conforms to it:
protocol Testable {
func test() -> Self
}
If you want to conform to this protocol you than have to replace Self with the name of the type. For instance:
struct Product: Testable {
func test() -> Product {
return Product()
}
}
Important Edit:
As DevAndArtist pointed out in the comments there is a working class check in Swift 1.2 (without automatic bridging to Objective C) but not Swift 2 (Xcode 7 beta 3; probably a bug):
if instance.dynamicType is AnyClass {
// instance is a class
} else {
// instance is not a class
}
You can see workaround (mainly) for Swift 2 below.
End Edit
With respect to classes you should use AnyObject if you want to keep it simple but you can also use reflection which would be much more effort.
Below you can see some reflection results of string interpolations (only the first few characters):
"\(reflect(classType))" // Swift._ClassMirror
"\(reflect(0))" // Swift._LeafMirror
"\(reflect(enumType))" // Swift._EnumMirror
"\(reflect(structure))" // Swift._StructMirror
"\(reflect([0, 4]))" // Swift._ArrayTypeMirror
"\(reflect(NSDate()))" // Foundation._NSDateMirror
"\(reflect(NSURLRelationship.Contains))" // Swift._EnumMirror
"\(reflect(Int?(2)))" // Swift._OptionalMirror
As you can see enums are consistent if they are not defined in the Swift standard library (unfortunately also Optional...). So you can distinguish also structs and enums:
public enum Type {
case Enum, Class, Struct
}
public func getType<T>(anything: T) -> Type {
if anything is AnyObject {
return .Class
}
if "\(reflect(anything))".hasPrefix("Swift._EnumMirror") {
return .Enum
}
return .Struct
}
So for a better result you have to put some effort into it to differentiate between all the different cases.
But the easiest way to distinguish only between reference types and value types (aka classes and structs/enums) is still (unfortunately only works for own declared structs and not built in types because they can be bridged to Objective C; I'm working on it...):
if instance is AnyObject {}
// or: if instance is of type Any
if let classInstance = instance as? AnyObject {}

Call Class Methods From Protocol As Parameter

I want to be able to pass a class (not an initialized object) of a certain protocol type to a method, then call the class functions of that class in the method. Code below.
I am using Swift and have an protocol defined like this
//Protocol for any object to be used with an FAUAPIConnection
protocol FAUAPIModel{
//Used to parse the object from a given dictionary to an object
class func parseFromJSON(JSON:AnyObject) -> Self
//Required default init
init()
}
What I would like to do is have a method like this
func getSomeParsingDone<T:FAUAPIModel>(model:T.Type? = nil, getPath:path, callingObj:CallingClass) -> Void
{
//GetIt is inconsequential, just logic to get an object from a certain path
var returnObj:AnyObject = GetIt.get(path)
if(model != nil){
returnObj = model!.parseFromJSON() <<<<<< Type 'T' does not conform to protocol 'AnyObject'
}
callingObj.done(returnObj)
}
Object that implements the protocol
import Foundation
class MyObj: FAUAPIModel{
var neededVal:String
var nonneededVal:String
required convenience init(){
self.init(neededVal:"VALUE")
}
init(neededVal:String, nonneededVal:String = ""){
self.neededVal = neededVal
self.nonneededVal = nonneededVal
}
class func parseFromJSON(JSON:AnyObject) -> WGMPart
{
return WGMPart() <<<<<<<< Method 'parseFromJSON' in non-final class 'WGMPart' must return 'Self' to conform to protocol 'FAUAPIModel'
}
}
However, I keep getting two errors. I have indicated these above with '<<<<<<<<<<<<'
compile error.
Lots of little things to consider here, but let's get to the heart of your question. The signature you want looks like this:
func getSomeParsingDone<T:FAUAPIModel>(model:T.Type, path:String) -> T?
I'm making the return optional beause there are a lot of things that could fail here, and you really shouldn't turn all of those into crashes.
I'd recommend your protocol look like this:
protocol FAUAPIModel {
class func parseFromJSON(JSON:AnyObject) -> Self
}
That way, you're promising that your return your own class, not just anything that is parseable. That does tend to mean that you need to make your classes final. If you don't want them to be final, you'll need to promise some init method in order to construct it. See Protocol func returning Self for more details on how to deal with that if you need it.
So putting it together, it might look something like this in practice:
protocol FAUAPIModel {
class func parseFromJSON(JSON:AnyObject) -> Self
}
func createObjectOfClass<T: FAUAPIModel>(model: T.Type, path: String) -> T? {
if let json: AnyObject = GetJSON(path) {
return model.parseFromJSON(json)
}
return nil
}
// Bogus JSON reader
func GetJSON(path: String) -> AnyObject? {
let json: AnyObject? = NSJSONSerialization.JSONObjectWithData(path.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!, options: NSJSONReadingOptions(0), error: nil)
return json
}
// Bogus model class that returns trivial version of itself
final class Something: FAUAPIModel {
class func parseFromJSON(JSON:AnyObject) -> Something {
return Something()
}
}
// Using it
let something = createObjectOfClass(Something.self, "/path/to/file")
I just want to note that the answer to your exact question would be to declare your function like this:
func getSomeParsingDone(model:FAUAPIModel.Type? = nil, getPath:path) -> FAUAPIModel

Obtaining a string representation of a protocol dynamically

I'm looking for a way to obtain a protocol name dynamically from the protocol type, without having to use the #objc attribute in the protocol declaration.
I know that this works:
func keyForProtocol(aProtocol: Protocol) -> String {
return NSStringFromProtocol(aProtocol)
}
but only if the protocol has the #obj attribute:
#objc protocol Test {}
var key = keyForProtocol(Test.self) // Key contains "TestApp.Test"
however as soon as I remove the #objc attribute, compilation fails with this error:
'Test.Protocol' is not convertible to 'Protocol'
Is there any way to achieve that?
Note: the reason why I want to avoid #objc is that it doesn't allow usage of associated types (i.e. generics in protocol) - in those cases compilation fails with this error: Method cannot be marked #objc because the type of parameter xx cannot be represented in Objective-C
I recently found a solution by implementing the keyForProtocol method as follows:
func keyForProtocol<P>(aProtocol: P.Type) -> String {
return ("\(aProtocol)")
}
It works with any type, not just for protocols, but I'm ok with that.
Some examples from a playground:
protocol Test {}
keyForProtocol(Test.self) // Prints "__lldb_expr_92.Test"
class MyClass {}
keyForProtocol(MyClass.self) // Prints "__lldb_expr_92.MyClass"
keyForProtocol(Int.self) // Prints "Swift.Int"
keyForProtocol(UIView.self) // Prints "UIView"
As Antonio said:
let protocolDescription = "\(aProtocol)"
will return a (sometime strange) protocol name.
I finally completed my task converting back this string to a protocol with:
let protocolReference = NSProtocolFromString(protocolDescription)
This technique is perfect if you need to retrieve the protocol type from a generic parameter like in this example (a lightweight/homemade dependency manager):
class DependencyManager<T> {
private static func inject(_ aProtocol: T.Type) -> T {
let application = UIApplication.shared.delegate as! LMApplication
let dependencies = application.applicationDependencies
let protocolReference = NSProtocolFromString("\(aProtocol)")
let dependency = dependencies!.object(for: protocolReference)
return dependency! as! T
}
}
Usage:
let object: Protocol = DependencyManager.inject(Protocol.self)