Reputation: 7215
I've spent over a week reading various articles online & StackOverflow Q&A on memory management of Swift arrays within UIViewController
, I'm still getting crashes in my app. I hope you can help.
I have a parent class controller and multiple subclasses (simplified using examples) that inherit from the parent class, like this.
class ParentViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
lazy var results: [AnyObject] = [AnyObject]() //can contain various classes, such as Product, User, etc.
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return results.count
}
...
}
class SubViewController: ParentViewController {
... loads results Array via REST API, then then appends to array using
results.append(Product())
}
Randomly, I'd get crashes like this:
EXC_BAD_ACCESS KERN_INVALID_ADDRESS at 0x0000000a1abb4b17
Thread : Crashed: com.apple.main-thread
0 libobjc.A.dylib 0x000000019478fe10 cache_getImp + 16
1 libobjc.A.dylib 0x0000000194784a6c lookUpImpOrForward + 540
2 libobjc.A.dylib 0x000000019478fdb8 _objc_msgSend_uncached_impcache + 56
3 libswiftCore.dylib 0x00000001004d4e40 _ZN5swift12metadataimpl14ValueWitnessesINS0_17ObjCRetainableBoxEE18initializeWithCopyEPNS_11OpaqueValueES5_PKNS_8MetadataE + 24
4 libswiftCore.dylib 0x000000010036e3cc _TFSa6appendU__fRGSaQ__FQ_T_ + 92
Based on my understanding, I believe it's because results
is no longer in memory by the time results.append()
is called.
What's the best practice to instantiate arrays/collections in UIViewController, especially when there are subclasses? Here are some of my thoughts, any feedback would be appreciated.
1.Use lazy
in parent class. This is the base case and causes crashes
lazy var results: [AnyObject] = [AnyObject]()
2.Init in SubViewController
, this still causes crashes, also, should I deallocate the memory by using deinit()
?
in ParentViewController
var results: [AnyObject]
in SubViewController
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.results = [Product]()
}
3.Make results
optional in parent class, this would require all methods in parent class to check for optionals. Should I initialize the array in init
in the subclass or in the viewDidLoad()
? Also, should I deinit
results? to nil in parent class?
in ParentViewController
var results: [AnyObject]?
deinit {
results = nil
}
in SubViewController
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.results = [Product]()
}
Any suggestions would be appreciated!
Upvotes: 1
Views: 1142
Reputation: 66
Are you adding the result fetched from the rest api in the main thread? If not try this:
dispatch_async(dispatch_get_main_queue(), {
results.append(objectsFromApi)
})
Upvotes: 1
Reputation: 11555
I don't know what is the life time and relationship of your view controllers, but I one way to do this reliably is to place the "results" array to your AppDelegate. This is guaranteed to exists when you work with your view controllers and is accessible from them.
let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
appDelegate.results.append(...)
Upvotes: 1