updates to global object not reflecting by changing value of local object in iOS - ios

Today I faced a very strange issue in Objective C, if anybody can help me figure out, i would really appreciate it. Let me explain the scenario.
Below is the case:
I make a webservice call and get NSArray of Objects and cached in Global class.
I have a local NSArray in view controller which is nothing but assigned from Global class array. Like this
self.listOfObjects = [GlobalCache sharedInstance].listOfObjects
self.listOfObjects is strong and nonatomic.
In a scenario I updated an object in self.listofobjects, lets say nameProperty of the object in array. Its updated in self.listOfObjects and when i print object using command
po ((ObjectType*)self.listOfObjects[0]).name
its fine and printing the updated value.
But when i see the value in GlobalCache of the same objects, Its not reflecting sometimes its still having old values.
self.listOfObjects is just reference to the GlobalCache listOfobject. (No where it is copied from global cache to local object)
Could it be a memory problem?

Related

How to avoid Fetching Core data Entity as Fault?

During my screen transitions I have a Core data model class object which passes from one to other class. But during this sometimes its "nil" and when I try to log it I find it has returned a fault. While fetching it I have set :
fetchRequestObject.returnsObjectsAsFaults = false
I am new to core data. Below is the log when I tried to print the Object :
Optional<"MyEntity">
- some : <ProjectName.MyEntity: 0x2822acdc0> (entity: "MyEntity"; id: 0x9ddeded1ada58e31 <x-coredata://27FC66FC-4FDF-4B40-9541-F4E90622906C/MyEntity/p34705> ; data: <fault>)
Many times it prints and works fine with its attributes and values. But other times it is "nil".
I have faced similar issue
Faults are in general not something to worry about (CoreData will automatically fire the fault and populate the object as soon as you access any of its attributes).
But in this instance I suspect something more nefarious is happening: the CoreData is instantiated locally in that fetch method, and I fear it is being deallocated (together with the associated managedObjectContext) as soon as the method completes. Your return array consequently contains NSManagedObjects from a context which has been deallocated. To check, try making managedObjectContext a property (a global var) rather than a local variable. That should be enough to keep a permanent reference to the context (which in turn will have strong references to the underlying stack) and prevent it being deallocated.

iOS - Appending element to list in realm does not persist element

I am adding a song to a List in my Playlist object with the following code:
func addSongsForPlaylist(songs: [Song], list: Playlist) {
try! realm!.write {
for song in songs {
list.RLMsongs.append(song)
}
}
}
Where songs is just an array of the songs that I want to add. The songs in songs are non persisted objects (not in realm yet), but list is already persisted in Realm.
I have found quite a few questions here on stackoverflow that seem to ask the same question but all their solutions were having to do with wrapping the append in a write transaction which I am already doing as you can see.
I have also tried the following:
try! realm!.write {
list.RLMsongs.appendContentsOf(songs)
}
What is happening is that if I enter po list.RLMsongs in the console the new song is there and it looks great, but if I enter po list its RLMsongs property is missing the new song. How can both be true? It seems to contradict itself and seems like there is something fundamental that I am missing about RealmSwift.
It looks like it is updating the list in memory but not actually committing to Realm. Therefore, I thought maybe the write block was not committing properly and wrapped it in a do catch but the catch is never run so the write transaction should be successfully committing.
EDIT:
Also, I noticed that I am able to remove the write transaction and it DOES NOT give me an error. I think this could be a clue as to what is going on here. Is it possible that the List is considered non persisted and therefore does not update properly in realm at all even though the contents of the list (the songs) are persisted objects?
That's because po list shows the contents of the instance variables of the Realm object, not the contents of the Realm. Realm doesn't duplicate all the contents of the database into the instance variables of the object instances because that would be quite wasteful.
Realm provides an LLDB plugin (rlm_lldb.py) that teaches the debugger to show actual Realm-backed contents rather than the unused instance variables. However, it only works with Objective-C stack frames due to limitations in the LLDB Python API for Swift language support.
Turns out that my issue was that I had to re-fetch the Playlist from realm...somehow the Playlist as it was passed into the function was not being considered a valid persisted object in realm. (Even though I have other update functions that work the same way that update other properties instead of appending objects to the song list and those update functions work fine)
My only guess is that something to do with appending to a list inside of a persisted object somehow works differently and the list must be explicitly fetched within the local scope and not just passed in as a function parameter. I could be wrong about this however. I just know this is how I got it to work on my end.

ARC. Object from array points to nil

I have one ViewController that takes objects from CoreData and build with them a UITableView.
When a user press a row, I get the reportage object and pass it to the next view controller using:
Reportage *reportage = [self.reportages objectAtIndex:indexPath.row];
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
ReportageTeaserPanelViewController *rightController = (ReportageTeaserPanelViewController*)self.menuContainerViewController.rightMenuViewController;
rightController.reportage = reportage;
[self.menuContainerViewController toggleRightSideMenuCompletion:nil];
The variable reportage is declared as strong in the controller ReportageTeaserPanelViewController.
The problem is the following. If I have to reload asynchronously the objects in the array of the parent view controller because of there is an update in my web service, the variable reportage gets nil in the controller ReportageTeaserPanelViewController. I thought that using a strong reference, the controller ReportageTeaserPanelViewController should be keep the "old" reportage object although it disappears from the array.
Is the any explanation for this behaviour?
Thanks
From what I can gather, you start with self.reportages not being nil, but since it's reloaded asynchronously after that initial load, when the user selects the table during an asynchronous reload, you're in danger of self.reportages being nil or potentially incomplete.
To prevent initializing your local reportage variable with a nil value, I'd recommend NOT directly reloading your self.reportages array in the asynchronously block in your parent view controller, but instead creating a local array within that block and then, once that array contains the full and proper contents, setting self.reportages to contain the contents of that local array. That way as long as your web service returns the proper "reportage," self.reportages will never equal nil.
I thought that using a strong reference, the controller ReportageTeaserPanelViewController should be keep the "old" reportage object.
Strong references are irrevelant. Nothing in this code is "kept" - these are all local, automatic variables, so they go out of existence as soon as the code runs. Only persistent references can make an object persist. An instance variable / property is an example of a persistent reference; it lives as long as the instance itself, unless of course you change its value. So the place to look is you instance variable, reportages.
You are saying:
Reportage *reportage = [self.reportages objectAtIndex:indexPath.row];
If there is no object at that index, there is no object at that index. It has nothing do with strong references. You need to think about where reportages is supposed to get its value.
It sounds from your use of the word "asynchronously" as if you might be setting reportages on a different thread from, and possibly actually later than, this code is running. That would be the issue. You need to get your threading and order of events sorted out.

CoreData fault - how to get data

I've researched tons of questions and documents about CoreData returning faults instead of actual values:
Relationship 'whiskers' fault on managed object (0xb7abab0)
This happens when I'm trying to get the count for the number of whiskers, such as:
self.numWhiskersLabel.text = [NSString stringWithFormat:#"%d", cat.whiskers.count];
Even if I try to log the whiskers set directly I still get a fault:
NSLog(#"whiskers: %#", cat.whiskers);
I understand that "Core data will not return full object until there is a need to access the actual value of that object. Each of your returned objects will be a 'fault' until this point." That's great, but there is a need to access the actual value at this point. I need the value right now! So how do I get out of this oxymoron? How can accessing the count of a Set not be considered needing the value?
I didn't get any feedback from my comment so I'm just going to assume whiskers is a set of NSManagedObjects
The set wont be loaded initially because internally it's coming from another table in the db. When you access .whiskers.count it still doesn't need to go and get the data yet, because all you're wanting is the number of whiskers in the set.
When you pull a whisker out of the set, then it will be faulted, try doing
NSLog(#"whiskers: %#", [cat.whiskers.anyObject anyProperty]);
That should give you a loaded NSManagedObject.
This is an error condition. Something is wrong with that NSManagedObject instance. Either it was deleted before you accessed it or you are trying to touch it from the wrong thread.
Please edit your question and show the code that is accessing that NSManagedObject.
Also, what happens when, in the debugger, you just do a po cat? Do you see the full Cat object or is that giving a fault error as well?

Deleting Core Data objects from in-memory store turns them into faults but does not erase them

I have a Core Data stack based on the NSInMemoryStoreType store. And I've noticed that deleting objects doesn't really remove them or make them nil, bur rather simply turns them into faults.
For example, (MyManagedObjectEntityClass as well as the <> identifier are placeholders):
MyManagedObjectEntityClass *o = [NSEntityDescription insertNewObjectForEntityForName:#"<MyManagedObjectEntityClass Entity Name>" inManagedObjectContext:self.localContext];
NSLog(#"\n%#", o);
[self.localContext deleteObject:o];
NSLog(#"\n%#", o);
Will log that the object is still there only that it's data is a fault.
And adding [self.localContext save:nil]; after the delete doesn't change this either.
I was hoping I could at some point test the o variable for nil, in which case I'd reload the object - but it seems I can't.
Just in case, yes, I know I could instead test o for -isFault. But thing is, extrapolate this test to an NSSet and I can't just rely on [[set anyObject] isFault] to conclude that all objects in that set have been removed (Ideally the set's count would be 0, but all objects are still there as faults).
So I'm wondering if it's possible at all or what alternate approach could I take to be able to test that objects have been deleted in a way transparent to the fact that they are managed objects.
This is not actually a Core Data issue. C (and by extension Objective-C) doesn't work like that.
The deleteObject: method takes one argument, a pointer to an object. It can change the object (like setting its isDeleted flag), or it can do other things related to the object (like deleting it from its managed object context). It cannot change the value of the pointer itself. So whatever it does or should do, C says that once it's done, the pointer that you pass in still points to the same location in memory. As a result it's actually impossible for that method to force that pointer to be nil in this language. If you want it to be nil, you have to change that yourself. (As an aside, it would have been possible to implement the method to take a pointer to pointer argument, which could modify your pointer. This would have no effect on other references such as those in arrays, though, so it would be kind of pointless).
This is why the isDeleted method is public, so that if you have a pointer to this object in some other location, you can check whether it has been deleted before attempting to use it.
If that's not convenient enough (and it often isn't), Core Data also provides NSManagedObjectContextObjectsDidChangeNotification and NSManagedObjectContextDidSaveNotification. You can use these anywhere in your app to get notified of changes to the context and respond in whatever way is appropriate (updating an array, for example). These notifications both try to help you out by providing lists of inserted, updated, and deleted objects. Use those when possible to check whether you actually need to update your references.

Resources