2016-04-17 7 views
2

Ich möchte eine Funktion in Swift, die eine Bool zurückgibt, aber das kann auch throw, wenn eine Ausnahme auftritt.Aufruf der Methode in Swift-Klasse, die löst und nicht void return von Obj-C

Zum Beispiel:

func doSomething(value: Int) throws -> Bool { 
    if (value > 0) { 
     return true 
    } else if (value == 0) { 
     throw NSError(domain: "SwiftClass", code: 0, userInfo: nil) 
    } 
    return false 
} 

Dies funktioniert gut, von Swift, aber wenn ich versuche, und verwenden Sie diese Funktion aus Objective-C, kann der Compiler nicht die Methode finden. Ich weiß, dass die throws die Objective-C-Funktion Unterschrift erfordert doSomething:x error:&error und das funktioniert zu ändern, wenn ich die Rückkehr Typ Void ändern -

func doSomething(value: Int) throws -> Void { 
    if (value == 0) { 
     throw NSError(domain: "SwiftClass", code: 0, userInfo: nil) 
    } else if (value < 0) { 
     throw NSError(domain: "SwiftClass", code: -1, userInfo: nil) 
    } 
} 

Das hat aber eine andere Semantik. Im ersten Beispiel muss ich mich nur mit der Ausnahme befassen (oder nicht-null NSError), wenn ein Problem vorliegt. Mit diesem Code muss ich die Ausnahme abfangen (oder den Fehler untersuchen) und feststellen, ob es sich um ein echtes Problem oder nur um den gültigen, "falschen" Fall handelt.

Ist es wirklich nicht möglich, eine Swift-Funktion mit einer nicht void-Rückgabe zu verwenden, die einen Objective-C-Kontext auslöst?

+0

Hmm, können Sie ein 'return' nach dem' throw' im ersten Beispiel hinzufügen? Wenn in Swift eine Methode ausgelöst wird, gibt sie nichts zurück. In Objective-C führt das Festlegen des Fehlerparameters nicht dazu, dass Sie einen gültigen Wert zurückgeben. – nhgrif

+0

Ich habe das getan (und die Frage aktualisiert, um die Änderung zu übernehmen). Kein Unterschied – Paulw11

+0

Dieses Makro beeinflusst die Sichtbarkeit von Objective-C-Methoden in Swift. Dies ist das Gegenteil; Swift-Methoden für Objective-C sichtbar machen Die "doSomething" -Methode fehlt einfach in der '-Swift.h'-Datei, wenn sie eine nicht void-Rückgabe hat – Paulw11

Antwort

4

Wie in meinen Kommentaren erwähnt, bin ich unklar, warum dies sollte nicht funktionieren. Die documentation gibt nichts zu empfehlen, dies sollte nicht funktionieren, aber es gibt auch nicht explizit, dass es sollte. Meine Lektüre der Dokumentation sagt, dass es funktionieren sollte.

dies gesagt wurde, wir könnte wickeln diese in einem Verfahren, das von Objective-C, indem die Rücklauftyp Void und unter Verwendung eines inout Parameter für das Ergebnis aufrufbar ist:

func doSomething(value: Int) throws -> Bool { 
    if (value > 0) { 
     return true 
    } else if (value < 0) { 
     return false 
    } else { 
     throw NSError(domain: "SwiftClass", code: 0, userInfo: nil) 
    } 
} 

func doSomething(value: Int, inout result: Bool) throws { 
    do { 
     result = try doSomething(value) 
    } catch let error { 
     // If need be, assign some default value to result. 
     throw error 
    } 
} 

Alternativ kann, wie pro Ihren Kommentar, scheint es der Compiler glücklich sein würde, wenn wir einen Wert zurückgeführt, die zu einer Objective-C-Klasse überbrücken kann (die offenbar nicht Bool nicht enthalten), so konnten wir sie als solche wickeln:

@objc func doSomething(value: Int) throws -> NSNumber { 
    do { 
     return try doSomething(value) 
    } catch let error { 
     throw error 
    } 
} 

Und beim Herumspielen wurde klar warum das funktioniert nur, wenn wir einen Wert zurückgeben, der einer Objective-C-Klasse zugeordnet werden kann.

Der Compiler lässt Sie keine optionale von einer mit @objc und throws gekennzeichneten Methode zurückgeben. Warum? Da wir auf der Swift-Seite try Semantik verwenden, um die Methode aufzurufen, ist der Ansatz in Objective-C völlig anders. nil wird verwendet, um einen Fehler anzuzeigen.

So versucht, eine Methode mit diese Signatur in Swift zu erstellen:

@objc func doSomething(value: Int) throws -> NSNumber? 

generiert diese Warnung:

Methode Werfen kann nicht @objc markiert werden, da sie einen Wert von optionalen Typ zurückgibt 'NSNummer?'; ‚Entfällt‘ zeigt einen Fehler in Objective-C


Am Ende aber ich immer noch sehr empfehlen, dass Sie die Swift-Methode als mit der Unterschrift Rückkehr Bool und schreiben eine Wrapper Methode Rückkehr NSNumber so schreiben, dass Wir haben immer noch unsere Swift-Methode mit dem genauesten möglichen Typ.

Auch, wenn Sie bemerken, Boolkann glücklich automatisch Box in NSNumber. Meine Wrappermethode wurde als zurückkehrender Typ NSNumber geschrieben, aber die Methode, die ich umschließe, gibt den Typ Bool zurück, aber Swift war vollkommen glücklich, Bool von einer Methode zurückzugeben, die NSNumber zurückgeben soll. Das Problem ist höchstwahrscheinlich, dass Swifts Bool standardmäßig in Objective-C BOOL übersetzt wird, was eine Nicht-Klasse ist.

Objective-C könnte zwischen den drei möglichen Fällen nicht unterscheiden, wenn Ihr Rückgabetyp BOOL lautet. Es hat nur zwei mögliche Rückgaben von einer BOOL Methode: YES oder NO. Mit Bool, das einem NSNumber zugeordnet ist, kann es @YES, @NO und nil zurückgeben.

Und wenn ich es bin, ist NSNumber nicht wirklich streng genug für mich. Ich könnte dazu ermutigt werden, dafür meine eigene eingewickelte Klasse zu schreiben.

@objc class BooleanObject: NSObject, BooleanType { 
    let boolValue: Bool 

    init(_ boolValue: Bool) { 
     self.boolValue = boolValue 
    } 
} 

Beachten Sie, dass die BooleanType Protokoll bedeutet, dass Swift würde immer noch vollkommen glücklich Variablen dieses Typs zu verwenden, als ob sie eine regelmäßige Bool waren.

let b = BooleanObject(true) 

if b { 
    // b's boolValue property is true 
} 
Verwandte Themen