SwiftOSC
SwiftOSC copied to clipboard
How to avoid retain cycles when using OSCServer
Hi Devin,
Swift isn't my main language, I'm hoping you could make this clearer for me.
I'm instantiating an OSCServer inside a VC, which I only need while I'm inside that VC. I want to close that connection and deallocate the server when I leave the VC and return to the parent VC.
By making the server.delegate = self I cause a retain cycle even if I try setting server.delegate = nil in viewWilDisappear()
I've tried declaring my server as weak and unowned
What am I missing?
In OSCServer.swift,
open class OSCServer {
// ...
open var delegate: OSCServerDelegate?
// ...
}
delegate is holding a strong reference here.
open var delegate should be open weak var delegate
Thanks for the speedy response @orchetect - I had this suspicion, nice to have that confirmed! I'm still getting a retain cycle after adding weak there. I can't understand what I'm doing wrong here :|
There could still be retain cycles elsewhere in SwiftOSC or in your code.
That was just the most obvious one I spotted.
Thanks @orchetect - think i've tried every variation of weak and unowned in every reference to the delegate I can. Removing the instantiation of the OSCServer in this view controller stops the memory leak. I can't figure out how to deallocate it. The VC is deiniting but the OSCServer stays allocated even when setting it to nil - so every time the VC is pushed, a new OSCServer ends up on the stack
As a workaround I'm instantiating the OSCServer at the top level in appDelegate like one of Devin's examples and setting that VC to the delegate (using self). I can't deallocate it but I can stop it and start it. I'm working on an app that's sensitive to memory so I'm hoping for a fix!
I'm sure this is something very obvious to Devin that I just can't see :)
Don't rule out the possibility that I screwed up somewhere.
In OSCServer.swift line 44.
func run() {
DispatchQueue.global().async{
while true {
let (data,_,_) = self.server.recv(9216)
if let data = data {
if self.running {
let data = Data(data)
self.decodePacket(data)
}
}
}
}
}
Probably shouldn't be while true. Try changing that to while self.running. Then open func start() needs to have run() in it .Or something like that.
I don't have time to dig into this right now.
Wow. That was some bad programming.
Awesome, thanks for the quick response Devin - I'll test this and make a PR if it works
It might not completely solve the issue. But there are definitely issues with that block.
Also be aware that async { } closure is holding a strong reference to self.
I'd start by adding [weak self] to the closure.
Maybe I should just pitch @orchetect 's OSC library. https://github.com/orchetect/OSCKit
He doesn't include the network layer so it's not plug and play but if you're good with that stuff it should be pretty easy. I know he's done some pretty extensive testing and uses it daily.
Also, If you check out the dev branch, I was working on using a different Swift Network framework. Maybe try giving that a spin. Full disclosure it's been a while and I'm not sure how well it works.
Cheers, had a quick look - couldn’t see exactly where the network framework changed, i’ll keep an eye on the dev branch if you become active on there again :)
On 28 Jan 2021, at 18:37, Devin Roth [email protected] wrote:
Also, If you check out the dev branch, I was working on using a different Swift Network framework. Maybe try giving that a spin. Full disclosure it's been a while and I'm not sure how well it works.
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.
Pretty much the entire OSCServer is completely different.