How do I correctly release memory in Swift? - swift

UserManagerViewController is a class that manages user objects (creates/release) for the rest of my view controllers (so that I don't create multiple User objects), I have:
var resources = Dictionary<Int, T>()
Whenever I need a resource, I do this:
let id = data["id"].intValue
self.resources[id] = User(data: data) //Create a User object and set it to the dictionary
I have other ViewControllers that "hang on" to this object when it wants to use it:
var users = [User]()
users.insert(<The pointer to resources[id]>, atIndex: 99)
//later on...
users.removeAtIndex(99) //this should release its hold
Later, when I need to release the final created object, I do this:
resources.removeValueForKey(id)
Will this method correctly ensure that the User instance simply goes away, since both its parents released it?

Yes, the user instance goes away. Swift uses automatic reference counting to manage memory. In your case, when you insert a user into a resource dict, the dict holds a reference to that user. When you later add user into users list, it also holds a reference to the user. It has two references to the same instance, therefore, when you remove user from those data structure, you have no reference to the instance, which means the user instance will be removed.

Related

Adding a deleted or invalidated object to a Realm is not permitted

I am trying to delete(truncate table) object and than adding it again, but getting this exception at runtime:
Adding a deleted or invalidated object to a Realm is not permitted
My code:
let realm = try! Realm()
let objFolder = realm.objects(FolderColor.self)
do{
try realm.write {
realm.delete(objFolder)
for obj in arrFolderColors {
realm.add(obj)
}
}
}
catch{}
I like the other answer but I think what's going on here is you have a class var
#objc dynamic var folderColorResults = Results<FolderColor>
and at some point you've populated that var with some FolderColor objects
self.folderColorResults = realm.objects(FolderColor.self).filter("color == 'blue'")
So then, when you call the code in the question, it's deleting all of the FolderColor objects from Realm - when that happens, the folderColorResults results var is also getting updated (all objects removed).
Therefore there are no objects to write back out to disk.
Remember that Realm is a live database and Results objects are always keep in sync with the actual data; change an object on one place, it changes it everywhere that object is being used.
A suggested fix is to cast the folderColorResults to an Array.
let myArray = Array(self.folderColorResults)
which disconnects those objects from Realm and they will not be updated.
Of course, I could be totally wrong on this assumption so I can update further if more information is provided.
Realm objects are simply pointers to their data in the Realm database. When you call realm.delete, you completely delete the contents from memory and disk. The Realm object itself is still in memory, but you can’t call any properties or try and re-add it.
There’s a object.invalidated property you can use to check if an object has been deleted before you try and add it to Realm to avoid accidentally triggering that exception.
I’d recommend you rethink your logic to not need to call ‘realm.delete’. If it’s in an array, you can just remove it from the array but keep it in the database.

Reference type inside value type in swift?

I have a struct User and Class account
struct User
{
var name: string
var account: Account
}
Class Account
{
var balance: Double
var accountNumber: String
init(bal: Double, accNum: String)
{
self.balance = bal
self.accountNumber: accNum
}
}
I am creating an instance for User and passing to multiple methods. It is clear that a copy will be created for the user but what about the account property inside the user object.
Questions:
1. Every time the user instance is passed to someother method the retain count of the account instance will be incremented?
2. At the end of the method ie before exiting the method the user instance will be deallocated and the retain count of the account will be reduced?
Every time the user instance is passed to someother method the retain count of the account instance will be incremented?
Correct.
At the end of the method ie before exiting the method the user instance will be deallocated and the retain count of the account will be reduced?
You have the right idea, but this isn't necessarily true. The User object may be destroyed much earlier than when the method exits. But you're correct that whenever it is destroyed, the retain count will be reduced.
That said, retain counts are an internal implementation detail that mean basically nothing. The better way to say all of the above is "a strong reference will be made to..." and " a strong reference will be removed from." I know that sound almost exactly like "retain count" but it may or may not actually result in the retainCount field in the underlying data structure literally being incremented or decremented. There are a lots of ways that expensive operation might be dodged. But your basic understanding is correct.

NSManagedObject in temporary context gets faulted

I've got a list of elements where editing/creation is possible, I do this in a new context and save it only if the user presses save.
My problem is now that when I'd like to handle the object to an other view controller, the properties are all nil, i.e. the user presses "new element", gets the form provided, a new ManagedObject is created in a new context and properties are set. If I provide that object to another view controller, the object is fault and all properties are nil - how can I prevent this? I don't like to save and delete it if the user presses cancel, I would prefer creation/editing on a "scratchpad context" and save it only if the user really presses save.
The most likely scenario is that your scratchpad managed object context is deallocated, and this is wiping out the managed object. Managed objects are dependent on their context but don't retain them (to avoid retain cycles), so if the context ever disappears, they stop working. Nil values for properties is the most common symptom of a missing context. For possible future reference, this is also true when the managed object has already been saved, and is not still a temporary object.

How to update the NSMutableArray if its initialized with other NSMutableArray

We have address book feature in our application, contacts are stored in NSMutableArray. I
have a separate class which is accessing contacts from outside, so I have initialized like
below in new class...
self.newListdata = [address_book_window listData];
Now my new class is able to access all contact using newListdata, number of contacts also
matching. In one situation if any contacts deleted from address book at run time, new
class newListdata also need to be updated, but it is not updating as I thought. Count is
also not updating. Am I doing anything wrong, Do I need to manually delete the contact in
newListdata also. Why it is not synchronized with address book contact as I am pointing to
address book list data.I have been learning objective C, so if anyone can help it will be
useful. thanks.
compare if newListdata and [address_book_window listData] are the same pointer (the same object).
printf("compare %f and %f", newlistdata, [address_book_window listData])
They should be the same address storage.
Note: since i don't know how you have implemented your code, since listData is encapsulated, address_book_window doesn't guaranty listData will always be at the same address storage (if you use a new list data by example). So newListData will could potentially point to a dangling pointer.
Best way to keep track of an object like this is by observer pattern, or KVO if you can. Since they are long to explain, google it ;)
if you have 2 NSMutableArrays they have strong references to the same objects, but they are 2 unique objects (they are 2 MutableArrays), this is the case when for example you create a NSMutableArray arrayWithArray:
if you have 1 Array, and 2 references to it when you remove or add object to it, it's a single object so it does not matter which reference you use to access it, it will be in "sync" as you mention (saying in sync is not correct because in fact they are 1 single object)
In your case maybe listData return a new array that contains references to the same objects, in such a case when you remove an object from one array, the second will still retain it (the object will not be deallocated then) and the 2 arrays will be different.

iPhone Core Data - cannot fulfill a fault error

I have three classes, A, B and C. A is the main class.
When the user wants to see the list of all objects that were purchased, Class B is called from A and shows the list of objects in a core data entity.
Inside class B, the user can buy new objects (in-app purchase). When the user wants to buy another object, class C is called.
When class C is called, a new object is created on the core data entity using
anObject = [NSEntityDescription insertNewObjectForEntityForName:#"Objects" inManagedObjectContext:context];
this object is then assigned to a local reference on Class C, using something like
self.object = anObject;
this object variable was declared like this:
.h
MyObjects *object;
#property (nonatomic, retain) MyObjects *object;
and #synthesized on .m
MyObjects is a core data class representing the entity.
In theory, object will retain anything assigned to it, so the line self.object = anObject I typed previously will retain anObject reference on self.object, right?
The problem is that when I try to access self.object in the same class after buying the new object, I receive an error "CoreData could not fulfill a fault for XXX", where XXX is exactly self.object.
At no point in the code there's any object removal from the database. The only operation to the database I could identify was a saving operation done by another class moments before the crash. The save is done by something like
if (![self.managedObjectContext save:&error]) ...
Is there any relation? what may be causing that?
CoreData manages the lifetime of managed objects and you should not retain and release them. If you want to keep a reference to the object so that it can be retrieved later then you have to store the object's id (obtained using -[NSManagedObject objectID]). Then use that to retrieve the object later using -[NSManagedObjectContext objectWithID:].
Make sure you understand about CoreData faulting. Read the documentation.
I had a similar issue a few days ago (using NSFetchedResultsController) where I was placing my fetchedObjects into an array and gathering attributes to populate tables from the array objects. It seems that if the objects in the array are faulted, you cannot unfault it unless you are acting on the direct object. In my case, I solved the issue by taking the lines of code in question and calling [[_fetchedResultsController objectAtIndexPath:indexPath] someAttribute]. I would assume that doing something similar would fix your problem as well. It seems a bit tedious to need to fetch from the managedObjectContext to obtain a faulted value, but this was the only way I could personally get past the issue.
Core Data is responsible for managing the lifetime of managed objects in memory. It's really important to understand Managed Object Contexts - Read the documentation.
Apple also provides an entire troubleshooting section here, and it contains among other things the causes for your error. But it's really only useful if you understand how core data works.
Most likely error is that the object you are saving does not belong to the managed object context.
Say you use the same object on different threads and those different threads use different managed object context, then this will happen.