Open CeccoCQ opened 9 years ago
Yeah, definitely don't use contextForCurrentThread
— it has been removed in MR3.
Two things:
localContext
— remove [localContext saveToPersistentStoreAndWait];
from your storeFriends:
methodHi Tony, thanks for your response. I don't want to use the contextForCurrentThread, but I can't find any solution for my problem.
Let me answer for point:
Thanks for the info. So [MagicalRecord saveWithBlock:…];
lets you make changes to localContext
, which are then saved back to your default context. You don't need to call save on localContext
yourself, we do that for you once your block has been executed.
I've removed the [localContext saveToPersistentStoreAndWait]
line but still not works :(
News.
I've removed [self getFriends] from viewDidLoad and I've moved this method in viewDidLoad with Truncate method (only for testing).
- (void)viewDidAppear:(BOOL)animated {
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
[SPUserModel truncateAllInContext:localContext];
} completion:^(BOOL success, NSError *error) {
[self getFriends];
}];
}
all works correctly. O.O
Another info: if I invoke [SPUserModel truncateAllInContext:localContext];
on viewDidLoad the app crashes.
Why???
Where are you setting self.context
, and what are you setting it to?
Sorry, the self.context is localContext.
This is a copy&paste problem.
So does it crash or not when you call -truncateAllInContext:
? It sounds like you are saying both...
Hi Alydyn,
If I invoke -truncateAllInContext within viewDidLoad the app crashes:
2014-10-02 14:37:04.134 SPapp[57195:922753] *** Terminating app due to uncaught exception 'NSObjectInaccessibleException', reason: 'CoreData could not fulfill a fault for '0xd000000003980000 <x-coredata://AD716A5B-C11D-46B7-BDDD-739E2FA208E1/SPUserModel/p230>''
If I move -truncateAllInContext within viewDidAppear all works correctly also without the localContext = [NSManagedObjectContext contextForCurrentThread];
statement (read my first post).
@CeccoCQ can you comment out your call to [self getFriends]
in the completion and see if it still crashes?
If I remove [self getFriends] method, the app still crashes. I've missed another info, the table User has a relationship (below the Entity diagram)
So I've changed the method within viewDidLoad:
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
[SPReservationModel truncateAllInContext:localContext];
[SPUserModel truncateAllInContext:localContext];
[SPContentModel truncateAllInContext:localContext];
[SPEventModel truncateAllInContext:localContext];
} completion:^(BOOL success, NSError *error) {
//[self getFriends];
}];
but the app works only within viewDidAppear.
The think that I don't undestand is because the refreshing of TableView after a HTTP Request works correctly only if I use the truncate method at viewDidAppear...
It sounds to me like something isn't completely set up when you are calling -viewDidLoad
, and has had a chance to finish by the time -viewWillAppear:
is called.
Maybe @tonyarnold has more info?
I also think so. But why the controllerWillChangeContent is called only if I execute a truncate operation or only if into storeFriends I use [NSManagedObjectContext contextForCurrentThread] ??
Another test. I've added this method:
- (IBAction)didChangeSomething:(id)sender {
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
SPUserModel *userDB = [SPUserModel findFirstByAttribute:@"uid" withValue:@"1234567890abc" inContext:localContext];
userDB.isFriend = [userDB.isFriend boolValue] ? [NSNumber numberWithBool:NO] : [NSNumber numberWithBool:YES];
[localContext saveToPersistentStoreAndWait];
}];
}
But nothing happens :(
Again, you do not need to call -saveToPersistentStoreAndWait
. MagicalRecord calls that for you after the block completes.
And also, try using +MR_fetchAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending withPredicate:(NSPredicate *)searchTerm groupBy:(NSString *)groupingKeyPath inContext:(NSManagedObjectContext *)context
and specifying [NSManagedObjectContext MR_defaultContext]
.
I just checked the method implementation, and I think that the problem you are seeing is that the variants of that method that do NOT specify a context are using [NSManagedObjectContext MR_contextForCurrentThread]
. @tonyarnold I assume that should be changed?
I've checked, if I remove -saveToPersistentStoreAndWait method, nothing works. Looking into database the value for isFriend remains always to 0.
Make sure you set up your fetched results controller with the default context like I mentioned above. Also, what version of MagicalRecord are you using?
I've changed with: self.fetchedResultsController = [SPUserModel fetchAllSortedBy:@"fullName" ascending:YES withPredicate:nil groupBy:nil delegate:self inContext:[NSManagedObjectContext MR_defaultContext]]; But nothing.
I'm using pod 'MagicalRecord/Shorthand'
I believe that pulls version 2.2. I suggest you pull it from Cocoapods and get the latest beta of version 2.3
I've tried but on cocoapods there is only version 2.2. Is there a way to pull the 2.3 version?
I am not sure, I try not to use Cocoapods. I would remove it from your pod file, re-run pod install, and then download and manually import version 2.3
Try this
pod "MagicalRecord", :git => 'https://github.com/magicalpanda/MagicalRecord.git', :branch => 'develop'
@waltermvp thanks! @Alydyn bad news, also with version 2.3 I've same behaviour.
Is the issue that savewithblock's completion block is not getting called?
The main issue is that his NSFetchedResultsController
is not updating his tableView.
@CeccoCQ in the completion block call [self.fetchedResultsController performFetch:nil]
.
That should work. Keep in mind that the delegate updates get called when data in the moc changes. It's easy to expect a update when the predicate changed but that's not intended. Changing the predicate will not call the delegates you must perform fetch anytime you set the predicate. One nice way would be to subclass override the setpredicate method of that fetch request and call Perform fetch there.
IMHO I think that the context was wrong. Is it possible that if I change the localContext returned from saveWithBlock is different from the context used in fetchAllSortedBy... ??
I think that because if I set localContext with contextForCurrentThread all works.
Shouldn't matter the save with block context should save all the way to the persistent store. Which is probably being observed from your main thread context
I'm also thinking so but still remain the problem of use of contextForCurrentThread and why this works...
@CeccoCQ When you call +saveWithBlock:
, MagicalRecord creates a new child context with MR_rootSavingContext
as the parent. MR_defaultContext
is already configured to listen for save notifications from MR_rootSavingContext
, but NSFetchedResultsController uses the notification generated by -processPendingChanges
.
Interestingly I just noticed that +MR_fetchAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending withPredicate:(NSPredicate *)searchTerm groupBy:(NSString *)groupingKeyPath inContext:(NSManagedObjectContext *)context
actually ignores the passed in context. It uses it to create the fetch request but still uses +MR_contextForCurrentThread
when it creates the NSFetchedResultsController
.
Contextforcurrentthread "may work" but is not guaranteed, I believe
@waltermvp This is my fear... @Alydyn I've a news, this is a simple code that I added today:
- (IBAction)didChangeSomething:(id)sender {
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
SPUserModel *userDB = [SPUserModel findFirstByAttribute:@"uid" withValue:@"a3535ee6-645a-4f6e-9970-4df65120353e" inContext:localContext];
userDB.isFriend = [userDB.isFriend boolValue] ? [NSNumber numberWithBool:NO] : [NSNumber numberWithBool:YES];
[localContext saveToPersistentStoreAndWait];
}];
}
and nothing happens on the TableView, but into the database the value of isFriend is correctly updated. Now, if I change this code with:
- (IBAction)didChangeSomething:(id)sender {
SPUserModel *userDB = [SPUserModel findFirstByAttribute:@"uid" withValue:@"a3535ee6-645a-4f6e-9970-4df65120353e"];
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
[userDB inContext:localContext];
userDB.isFriend = [userDB.isFriend boolValue] ? [NSNumber numberWithBool:NO] : [NSNumber numberWithBool:YES];
[localContext saveToPersistentStoreAndWait];
}];
}
then works!!!!! For "works" I mean that the TableView show and hide the record.
Bah....
And you still need to call [localContext saveToPersistentStoreAndWait]
to get it to work? Have you tried commenting that out?
@Alydyn If I comment this line, nothing works... the app doesn't update the database field. Anyway I've already tried to delete saveToPersistentStoreAndWait but with no luck.
I see what you mean now. I've run into the same issue. For some reason unknown to me, fetching from the main thread then fetching the same object using in context from the local context works. It should work in both scenarios but does not. Dunno why
Stupid question...
Is it possible that I have these problems because I execute an insert/update entity out of ViewController? In my example, storeFriends was executed in a different class....
It's very hard to say without seeing all of the code. When debugging issues like this I like to eliminate any variables that I can. Certainly, reducing the logic to the minimum necessary would help troubleshoot what is happening.
If your main issue is that the NSFetchedResultsController
does not automatically refresh with your current implementation then I think you need to create the simplest possible scenario where you can reproduce it. Then you can place multiple breakpoints and see what is being called and when. You are dealing with multiple contexts running in multiple threads so it is possible that things are not happening when you think they are.
I have some news. If I add the completion block, all works correctly (see code below). I'm wondering, if I execute a new [self.fetchedResultsController performFetch:nil];, could I have some problems when user scrolls the list or could I have some freezes within tableview?
- (void) getFriends {
PMKPromise *getFriends = [self.userManager getFriendsWithPage:0 withLimit:1000];
getFriends.then(^(OVCResponse *response) {
[self.userManager storeFriends:response.result completion:^(BOOL success, NSError *error) {
[self updatePredicate];
}];
}).catch(^(NSError *error) {
}).finally(^{
[self.tableView.pullToRefreshView stopAnimating];
});
}
@CeccoCQ yes, calling performFetch:
could cause stutters or small pauses in your UI.
I've a big refresh problem in my app, in particular I follow these simple steps:
I expect that the a View with UITableView will be refreshed with new added records. But this not happens, I think that there is a problem with Context objects, because if I use the [NSManagedObjectContext contextForCurrentThread] all works correctly. But this is not recommended by Magical Record docs.
I have attached my code below with small description.
I've a UITableView with following code in lifecycle:
and in NSFetchedResultControllerDelegate:
The method [self updatePredicate] where I try to fetch all my friends:
The method [self getFriends] :
The method [self storeFriends]:
Why?!?!?!?!? Please help me.