Classe di protocollo Swift / restrizione AnyObject nell'estensione
Ho 2 protocolli, uno che dà un oggetto a serverId
e l'altro che gli dà un status
(aka è pubblicato sul server o meno). Entrambi mi consentono di gestire la sincronizzazione tra il mio modello di server e Core Data.
/// By conforming to this protocol, classes AND struct have an identifiable serverid `Int64`
protocol RemoteObject {
var serverId: ServerId { get set }
}
/// This can only be applied to class
protocol Syncable: class {
var syncStatus: SyncStatus { get set }
}
enum SyncStatus: Int64 {
case published
case local
}
L'idea alla base è che RemoteObject
può essere applicato a struct (cioè le strutture JSON che ricevo dal server) e class ( NSManagedObject
). D'altra parte, Syncable
può essere applicato solo a class ( NSManagedObject
).
Il prossimo passo per me è, quando syncStatus
è impostato su, .local
devo anche eliminare serverId
da RemoteObject sul mio oggetto impostandolo su -1, ma quando provo ottengo questo errore:
extension Syncable where Self: RemoteObject {
var syncStatus: SyncStatus {
get {
SyncStatus(rawValue: syncStatusValue) ?? .local
}
set {
syncStatusValue = newValue.rawValue
if newValue == .local { serverId = -1 } // 🛑 Cannot assign to property: 'self' is immutable
}
}
}
🛑 Impossibile assegnare alla proprietà: "self" è immutabile
Capisco che ricevo questo errore perché RemoteObject
può essere applicato a strutture, che sono immutabili.
Tuttavia , considerando che Syncable
può essere applicato solo ai tipi di classe, non forza RemoteObject
l'applicazione su una classe? e poi essere mutevole?
C'è un modo per forzare RemoteObject
di essere tipo di classe nella mia estensione? per esempio extension Syncable where Self: RemoteObject & class
?
Risposte
Alla fine ho trovato la soluzione. Secondo questo post posso farlo:
extension Syncable where Self: RemoteObject {
var syncStatus: SyncStatus {
get {
SyncStatus(rawValue: syncStatusValue) ?? .local
}
set {
syncStatusValue = newValue.rawValue
if newValue == .local {
var s = self
s.serverId = -1
}
}
}
}
Questo elimina l'errore e, per quanto ho capito, cambierà serverId
per le classi che sono tipi di riferimento e non muterà le strutture che sono tipi di valore ( comunque non possono essere conformi a questo protocollo ).
Per andare oltre, per chi potrebbe trovare utile questo post. La mia comprensione del problema non era accurata. All'inizio ho pensato che il problema fosse sul RemoteObject
protocollo, che poteva essere applicato a qualsiasi tipo.
Il problema sembra essere il contrario, secondo questa discussione . Quando si limita un procotol co :class
o :AnyObject
, fa sì che le sue forze setter
siano immutabili .
Quindi, quando provo a modificare il valore di serverId
, chiamo un setter mutabile da uno immutabile che fa lamentare il compilatore. Il work-around va bene per il mio utilizzo, tuttavia per ottenere una soluzione adeguata, dovrei sbarazzarmi di :class
in Syncable
e affrontare tutti i motivi che mi hanno costretto a farlo solo in classe in primo luogo.