2016-01-14 9 views
13

ho qualche codice legacy Objective-C, che dichiara metodo comeSwift non converte Objective-C NSError ** a tiri

- (void)doSomethingWithArgument:(ArgType)argument error:(NSError **)error 

Come scritto qui https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/AdoptingCocoaDesignPatterns.html

Swift si traduce automaticamente Obiettivo -C metodi che producono errori in metodi che generano un errore in base alla funzionalità di gestione dell'errore nativo di dell'errore nativo di Swift.

Ma nel mio progetto descritto metodi sono chiamati in questo modo:

object.doSomething(argument: ArgType, error: NSErrorPointer) 

Inoltre, viene generata un'eccezione di runtime quando si tenta di utilizzare loro come:

let errorPtr = NSErrorPointer() 
object.doSomething(argumentValue, error: errorPtr) 

ho bisogno di qualcosa di più convertire i metodi Objective-C "NSError **" in metodi "trow" di Swift?

+0

Quale versione di Swift stai usando? 'getta' è disponibile solo in Swift 2.0 e versioni successive. –

risposta

19

Solo i metodi Objective-C che restituiscono un oggetto (nullable) vengono convertiti in metodi di lancio in Swift.

La ragione è che i metodi di cacao utilizzano sempre un valore restituito NO o nil per indicare il fallimento di un metodo, e non sufficiente impostare un oggetto errore. Questo è documentato in Using and Creating Error Objects:

Importante: successo o il fallimento è indicato dal valore di ritorno del metodo. Anche se i metodi Cocoa che restituiscono indirettamente oggetti di errore nel dominio di Cocoa sono garantiti per restituire tali oggetti se il metodo indica un errore restituendo direttamente nil o NO, è necessario controllare sempre che il valore di reso sia nullo o NO prima di tentare di fare qualsiasi cosa con l'oggetto NSError.

Ad esempio, l'interfaccia Objective-C

@interface OClass : NSObject 

NS_ASSUME_NONNULL_BEGIN 

-(void)doSomethingWithArgument1:(int) x error:(NSError **)error; 
-(BOOL)doSomethingWithArgument2:(int) x error:(NSError **)error; 
-(NSString *)doSomethingWithArgument3:(int) x error:(NSError **)error; 
-(NSString * _Nullable)doSomethingWithArgument4:(int) x error:(NSError **)error; 

NS_ASSUME_NONNULL_END 

@end 

è mappato a Swift come

public class OClass : NSObject { 

    public func doSomethingWithArgument1(x: Int32, error: NSErrorPointer) 
    public func doSomethingWithArgument2(x: Int32) throws 
    public func doSomethingWithArgument3(x: Int32, error: NSErrorPointer) -> String 
    public func doSomethingWithArgument4(x: Int32) throws -> String 
} 

Se è possibile modificare l'interfaccia del metodo, allora si dovrebbe aggiungere un valore booleano ritorno valore per indicare il successo o il fallimento.

In caso contrario si potrebbe chiamare da Swift come

var error : NSError? 
object.doSomethingWithArgument(argumentValue, error: &error) 
if let theError = error { 
    print(theError) 
} 

Nota: A

ho scoperto che Clang ha un attributo che costringe una funzione di gettare un errore in Swift:

-(void)doSomethingWithArgument5:(int) x error:(NSError **)error 
    __attribute__((swift_error(nonnull_error))); 

è mappato a Swift come

public func doSomethingWithArgument5(x: Int32) throws 

e sembra funzionare "come previsto". Tuttavia, non ho trovato documentazione ufficiale su questo attributo, quindi potrebbe non essere una buona idea affidarsi a questo.

+0

Grazie, bella risposta –

+0

Bella scoperta! Ho trovato la documentazione per gli attributi qui: https://github.com/apple/swift-clang/blob/383859a9c4b964af3d127b5cc8abd0a8f11dd164/include/clang/Basic/AttrDocs.td#L1800-L1819 –

2

È necessario rendere il metodo restituito a BOOL, per indicare al runtime che è necessario o non deve essere generato un errore. Inoltre si dovrebbe aggiungere __autoreleasing al parametro errore, per assicurarsi ARC non accidentalmente rilasciare l'errore prima di avere la possibilità di usarla:

- (BOOL)doSomethingWithArgument:(ArgType)argument error:(NSError * __autoreleasing *)error 

È quindi possibile chiamare da Swift in questo modo:

do { 
    object.doSomethingWithArgument(someArgument) 
} catch let err as NSError { 
    print("Error: \(err)") 
} 
+0

'__autoreleasing' è in realtà assunto per impostazione predefinita per un parametro' NSError ** error'. Altrimenti hai ragione. –

+0

Grazie per il suggerimento ... un'altra cosa che ho imparato oggi :) Questo [post SO] (http://stackoverflow.com/a/13590696/1974224) e la [documentazione Clang] (http: //clang.llvm. org/docs/AutomaticReferenceCounting.html # indirect-parameters) conferma quello che hai detto :) – Cristik

Problemi correlati