2016-03-28 5 views
3

ein Protokoll entspricht Ich habe folgendes ProtokollIn swift, wie kehre ich ein Objekt des gleichen Typs, die

protocol JSONInitializable { 
    static func initialize(fromJSON: NSDictionary) throws -> Self? 
} 

nun auf das Protokoll Ich versuche, diese Funktion Rückkehr zu machen, was auch immer Klasse angepasst hat . I.e. Wenn ich die Klasse Foo konform zum Protokoll habe, möchte ich ein Objekt Foo von der Methode zurückgeben. Wie kann ich das machen?

extension Foo: JSONInitializable { 
    static func initialize(fromJSON: NSDictionary) throws -> Foo? { 
    } 
} 

ich den Fehler:

Method 'initialize' in non-final class 'Foo' must return 'Self' to conform to protocol 'JSONInitializable'

Antwort

3

automatische Vervollständigung wird Ihnen helfen, aber im Grunde, wenn Foo eine Klasse ist, müssen Sie nur eine Methode, die die genaue Signatur der Methode in Ihrem Protokoll übereinstimmt:

class Foo {} 

protocol JSONInitializable { 
    static func initialize(fromJSON: [String : AnyObject]) throws -> Self? 
} 

extension Foo: JSONInitializable { 
    static func initialize(fromJSON: [String : AnyObject]) throws -> Self? { 
     return nil 
    } 
} 

als Notiz hier, müssen Sie innerhalb dieser Methode ersetzen alle Instanzen Foo mit Self. Wenn Sie einen Konstruktor verwenden möchten, muss dieser entsprechend markiert sein.

Vor diesem Hintergrund ist es wahrscheinlich sinnvoller, das Protokoll so zu ändern, dass statt einer statischen Methode initialize ein Initialisierer erforderlich ist. In diesem Fall sollten Sie sich Blake Lockley's answer ansehen. Diese Antwort beantwortet jedoch die Frage, wie mit Self in Protokollen umzugehen ist, da es sicherlich Fälle gibt, in denen wir eine Methode wünschen, die Self zurückgibt, die kein Initialisierer ist.


Wenn Foo keine Klasse ist, ist es ein Werttyp, der nicht Subklassen sein kann, und als solche, kehren wir den Namen des Typs:

struct Foo: JSONInitializable { 
    static func initialize(fromJSON: [String : AnyObject]) throws -> Foo? { 
     return nil 
    } 
} 
enum Foo: JSONInitializable { 
    case One, Two, Three 

    static func initialize(fromJSON: [String : AnyObject]) throws -> Foo? { 
     return nil 
    } 
} 

Der Grund, warum Sie im Fall einer Klasse Self? von der Methode zurückgeben müssen, ist die Vererbung. Das Protokoll erklärt, dass Sie eine Methode namens initialize haben, deren Rückgabetyp eine optionale Version dessen ist, was auch immer Sie sind.

Wenn wir Foo ‚s initialize Methode schreiben, wie Sie es geschrieben hat, dann, wenn wir Foo mit Bar Unterklasse, dann jetzt haben wir unsere Übereinstimmung mit dem Protokoll gebrochen. Bar hat die Konformität mit dem Protokoll von Foo geerbt, aber es hat keine Methode, die initialize heißt und Bar? zurückgibt. Es hat einen, der Foo zurückgibt.

Mit Self bedeutet hier, dass, wenn unsere Unterklassen diese Methode erben, es zurückgibt, welcher Typ auch immer sie sind. Self ist Swifts Äquivalent Objective-C's instancetype.

+0

So würde das ich Objekt vom Typ 'foo' aus dem Verfahren zurückkehren lassen? – smac89

+0

Es gibt 'Foo' zurück, wenn Sie es auf einer Instanz von' Foo' aufrufen. Wenn Sie 'Foo' von der Klasse' Bar: Foo' ableiten, wird 'Bar' zurückgegeben. – nhgrif

+0

Ich habe es gerade versucht und es gibt mir einen Fehler, wenn ich versuche, ein Objekt vom Typ 'Foo' von der Methode zurückzugeben. Es heißt 'Kann den Ausdruck des Typs 'Foo' nicht konvertieren, um den Typ 'Self' zurückzugeben. 'Ich benutze xcode 7.3, wenn das irgendwas hilft. – smac89

1

Wie in der nhgrif-Antwort erwähnt, ändern Sie den Rückgabetyp von Foo? in self?.

Alternativ

In Swift Sie init s in Protokoll erklären können, so etwas wie dies versuchen:

protocol JSONInitializable { 
    init?(fromJSON: NSDictionary) throws 
} 

extension Foo: JSONInitializable { 
    required init?(fromJSON: NSDictionary) throws { 
     //Possibly throws or returns nil 
    } 
} 
+0

Ich denke, Sie brauchen "Bequemlichkeit" und "erforderlich" in dieser Erweiterung – smac89

+0

Sie brauchen 'erforderlich'. Sie brauchen nicht unbedingt "Bequemlichkeit". Erwähnenswert ist auch, dass Objective-C-Protokolle initialisieren können und haben, dass sie Teil des Protokolls sind. Weitere Informationen finden Sie im NSCoding-Protokoll (https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Protocols/NSCoding_Protocol/). – nhgrif

+0

Ich habe gerade so versucht, und der Fehler sagt, dass ich dies nur in der Definition einer nicht-endgültigen Klasse tun kann, dh Erweiterungen funktionieren nicht – smac89