Qui, stavo giocando con perdite, quindi ho fatto un ciclo di riferimento forte intenzionalmente per vedere se gli strumenti rileveranno qualcosa, e io ha ottenuto risultati inaspettati. La perdita mostrata in Strumenti ha sicuramente senso, ma il crash casuale è un po 'misterioso (a causa di due fatti che menzionerò più avanti).L'utilizzo di un interno sconosciuto di una lista di cattura causa un crash anche il blocco stesso non viene eseguito
Quello che abbiamo qui è una classe chiamata SomeClass
:
class SomeClass{
//As you can guess, I will use this shady property to make a strong cycle :)
var closure:(()->())?
init(){}
func method(){}
deinit {print("SomeClass deinited")}
}
Anche io ho due scene, il GameScene
:
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
backgroundColor = .blackColor()
let someInstance = SomeClass()
let closure = {[unowned self] in
someInstance.method() //This causes the strong reference cycle...
self.method()
}
someInstance.closure = closure
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if let nextScene = MenuScene(fileNamed: "MenuScene"){
nextScene.scaleMode = .AspectFill
let transition = SKTransition.fadeWithDuration(1)
view?.presentScene(nextScene, transition: transition)
}
}
deinit {print("GameScene deinited")}
func method(){}
}
E, infine, la MenuScene
, che è identico al GameScene
, basta con un metodo vuoto didMoveToView
(ha implementato solo il metodo touchesBegan
).
riproduzione dei Crash
L'incidente può essere riproducono per la transizione tra le scene per un paio di volte. In questo modo, la perdita si verificherà perché la variabile closure
viene trattenuta dalla variabile closure
e la variabile someInstance
viene mantenuta, quindi abbiamo un ciclo. Ma ancora, questo non produrrà il crash (sarà solo una perdita). Quando sono in realtà provo ad aggiungere self.method()
all'interno di una chiusura, l'applicazione si blocca e ottengo questo:
e questo:
Lo stesso incidente esatto posso produrre se io prova ad accedere ad un riferimento unowned
quando l'oggetto a cui si fa riferimento è deallocato, ad es. quando la chiusura sopravvive all'istanza catturata. Questo ha senso, ma non è questo il caso (la chiusura non viene mai eseguita).
The Mysterious Parte
La parte misteriosa è che questo incidente accade solo su iOS 9.1 e non su iOS9.3. Un'altra cosa misteriosa è il fatto che l'app si arresta in modo anomalo a in modo casuale, ma per lo più entro le prime dieci transizioni. Inoltre, la parte strana è il motivo per cui si blocca se la chiusura non viene mai eseguita, o l'istanza che cattura non è accessibile (almeno non da me).
soluzione al problema, ma non è la risposta alla domanda
Naturalmente l'incidente può essere risolto in un paio di modi per rompere il ciclo, e mi rendo conto che dovrei usare unowned
solo quando sono completamente sicuro che l'istanza catturata non diventerà mai nulla dopo l'inizializzazione. Ma ancora, a causa del fatto che non ho eseguito questa chiusura, dopo che è sopravvissuta alla scena, questo incidente è piuttosto imbarazzante per me. Inoltre, potrebbe valere la pena menzionare che le scene sono deinite con successo dopo ogni transizione.
Interessante
Se uso weak self
all'interno di una lista di acquisizione, l'applicazione non vada in crash (la perdita esiste ancora, ovviamente). Il che ha senso, perché se la scena diventa nil
prima che il blocco venga deallocato, l'accesso alla scena attraverso il concatenamento opzionale preverrà l'arresto anomalo. Ma la parte interessante è che, anche se io uso forced unwrapping
come questo, non vada in crash:
let closure = {[weak self] in
someInstance.method()
self!.method()
}
Il che mi fa pensare ... Apprezziamo qualsiasi suggerimenti su come eseguire il debug di questo o spiegazione su ciò che causa l'incidente .. .
EDIT:
Ecco la Github repo
Se non si arresta in modo anomalo su 9.3, probabilmente è un bug. A proposito, questo è il tuo rapporto? [SR-1006] (https://bugs.swift.org/browse/SR-1006) Sembra lo stesso problema. – Sulthan
@Sulthan No, non è il mio bug report ... Beh, ho iniziato una taglia per vedere se qualcuno può davvero dimostrare che si tratta di un bug o no, e spiegare quale dovrebbe essere il comportamento previsto in questa situazione. Personalmente, penso che dovrebbe perdere, ma non dovrebbe andare in crash, ma vedremo ... – Whirlwind
Sono abbastanza sicuro che non dovrebbe bloccarsi se non si esegue il blocco. – Sulthan