2015-01-30 29 views
5

ho estensione per NSManagedObject che dovrebbe aiutarmi a trasferire gli oggetti tra i contesti:Come utilizzare tipi generici per ottenere l'oggetto con lo stesso tipo

extension NSManagedObject { 

    func transferTo(#context: NSManagedObjectContext) -> NSManagedObject? { 

     return context.objectWithID(objectID) 
    } 

} 

per ora è tornare oggetto di NSManagedObject e dovrei cast alla classe quello che voglio, in questo modo:

let someEntity: MyEntity = // ...create someEntity 
let entity: MyEntity = someEntity.transferTo(context: newContext) as? MyEntity 

c'è un modo in Swift per evitare che la fusione inutili e se chiamo transferTo(context: ...) da oggetto della classe MyEntity rendono tipo di ritorno a 012.?

risposta

2

Update: Per una soluzione migliore, vedo Rob's answer.


Allo stesso modo come in How can I create instances of managed object subclasses in a NSManagedObject Swift extension?, questo può essere fatto con un metodo di supporto generico:

extension NSManagedObject { 

    func transferTo(context context: NSManagedObjectContext) -> Self { 
     return transferToHelper(context: context) 
    } 

    private func transferToHelper<T>(context context: NSManagedObjectContext) -> T { 
     return context.objectWithID(objectID) as! T 
    } 
} 

Nota che ho cambiato il tipo di ritorno a Self. objectWithID() fa non restituiscono un optional (in contrasto con objectRegisteredForID(), quindi non c'è alcuna necessità di ritorno un optional qui

Aggiornamento:.Jean-Philippe Pellet's suggested per definire una funzione riutilizzabile globale invece del metodo di supporto per trasmettere il valore restituito al tipo appropriato

Vorrei suggerire di definire due versioni (sovraccariche), per fare in modo che questo funzioni con oggetti opzionali e non opzionali (senza uno 012 indesideratoavvolgimento automatico in un opzionale):

func objcast<T>(obj: AnyObject) -> T { 
    return obj as! T 
} 

func objcast<T>(obj: AnyObject?) -> T? { 
    return obj as! T? 
} 

extension NSManagedObject { 

    func transferTo(context context: NSManagedObjectContext) -> Self { 
     let result = context.objectWithID(objectID) // NSManagedObject 
     return objcast(result) // Self 
    } 

    func transferUsingRegisteredID(context context: NSManagedObjectContext) -> Self? { 
     let result = context.objectRegisteredForID(objectID) // NSManagedObject? 
     return objcast(result) // Self? 
    } 
} 

(Ho aggiornato il codice per Swift 2/Xcode 7. Il codice per precedenti versioni Swift può essere trovato nella storia di modifica)

+1

Interessante! Questo probabilmente giustificherebbe l'uso di una funzione globale come questa forse, invece di ricreare metodi di supporto quando si presenta la necessità? 'cast cast (oggetto: Qualsiasi, tipo: T.Type) -> T? { \t return obj as? T } 'Ho aggiornato la mia risposta per proporla. –

+0

@ Jean-PhilippePellet: Buona idea, ma l'argomento di 'obj' dovrebbe essere" Any? ", Altrimenti sembra non funzionare correttamente durante il cast di opzioni, come" NSManagedObject? "Restituito da' objectRegisteredForID() '. –

+0

Oh sì, hai ragione, certo. Sto ancora pensando troppo in Scala dove i non-optionals non sono automaticamente avvolti. –

2

questo farà il trucco:

func transferTo(#context: NSManagedObjectContext) -> Self? 

Al sito di chiamata, Self risolve al tipo noto staticamente dell'oggetto che si sta chiamando questo metodo su. Questo è anche particolarmente utile da usare nei protocolli quando non si conosce il tipo finale che si conformerà al protocollo ma si vorrà comunque fare riferimento ad esso.

Aggiornamento:Martin R's answer indica che non è possibile lanciare l'oggetto ottenuto immediatamente. Mi piacerebbe poi fare qualcosa di simile:

// top-level utility function 
func cast<T>(obj: Any?, type: T.Type) -> T? { 
    return obj as? T 
} 

extension NSManagedObject { 

    func transferTo(#context: NSManagedObjectContext) -> NSManagedObject? { 
     return cast(context.objectWithID(objectID), self.dynamicType) 
    } 

} 
+0

questo è quello che provato prima, ma si deve in qualche modo per lanciare il valore di ritorno. da 'co ntext.objectWithID (objectID) ', che è' NSManagedObject', al tipo di ritorno effettivo e 'as? Self' o simili non compila (o non riesco a capire come). –

+2

Ora abbiamo un ciclo di conservazione tra le nostre risposte :) In questo caso particolare in cui sappiamo * già * che l'oggetto è del tipo desiderato, funziona anche un unsafeBitCast(). –

+0

Nice !, ma IMO, il parametro dovrebbe essere 'AnyObject' per 2 motivi. 1) 'Any' occupa memoria a 32 bit, la conversione da un'istanza di classe a' Any' costa CPU e memoria. 2) A differenza di "Any", non possiamo passare "Optional" al parametro "AnyObject", è più sicuro di "Any". – rintaro

2

I'. La soluzione di Martin è piaciuta da molto tempo, ma di recente mi sono imbattuto in problemi. Se l'oggetto è stato osservato da KVO, questo si bloccherà. Self in questo caso è la sottoclasse KVO e il risultato di objectWithID non è tale sottoclasse, quindi si verificherà un arresto anomalo del tipo "Impossibile trasmettere il valore di tipo" myapp.Thing "(0xdeadbeef) a" myapp.Thing "(0xfdfdfdfd)."Ci sono due classi che si definiscono myapp.Thing, e as! utilizza l'oggetto classe reale. Quindi Swift non è ingannare dalle nobili bugie di classi KVO.

La soluzione è sostituire Self con un parametro di tipo statico spostando questo contesto:

extension NSManagedObjectContext { 
    func transferredObject<T: NSManagedObject>(object: T) -> T { 
     return objectWithID(object.objectID) as! T 
    } 
} 

T è puramente definito al momento della compilazione, quindi questo funziona anche se object è segretamente una sottoclasse di T

+0

@MartinR Per la versione leggermente più lunga, vedere https://gist.github.com/rnapier/5835b4014ec23663512e7daea61f217d –

+0

Posso confermare sia il problema che la soluzione! –

+0

Ho cercato di risolvere questo stesso problema, e sia il mio codice che il vostro, usando parametri statici, non "Auto", in un problema in build ottimizzati. Hai visto qualcosa di simile? http://stackoverflow.com/questions/39109373/core-data-swift-cast-failure-in-generic-function-in-optimized-builds –

Problemi correlati