Trouble with reloading data into NSArray (maybe because of ARC) - iphone

I have the following method called when my UITableView reloads:
-(NSArray *)theAccounts {
if (__theAccounts != nil) {
return __theAccounts;
}
// Create an account store object.
ACAccountStore *accountStore = [[ACAccountStore alloc] init];
// Create an account type that ensures Twitter accounts are retrieved.
ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
// Request access from the user to use their Twitter accounts.
[accountStore requestAccessToAccountsWithType:accountType withCompletionHandler:^(BOOL granted, NSError *error) {
if(granted) {
// Get the list of Twitter accounts.
NSArray *accountsArray = [[NSArray alloc] initWithArray:[accountStore accountsWithAccountType:accountType]];
self.theAccounts = accountsArray;
}
}];
return __theAccounts;
}
Setter Methods in .h:
#property (strong, nonatomic) NSArray *theAccounts;
and in the .m:
#synthesize theAccounts = __theAccounts;
I would like to be able to effectively empty self.theAccounts and reload. So I created a resync method, but it never returns any values after I reload the table:
-(void)resyncAccounts {
self.theAccounts = nil;
[self.tableView reloadData];
}
I am using ARC on iOS 5 SDK. Could this be an issue? I've done similar before with fetchedResultsController and had no issues, but that was not ARC. Worth noting that it does return data the first time it is called, and returns __TheAccounts after that, until I try to -(void)resyncAccounts{}.

Why don't you reload the tableView after setting "theAccounts" in the completion handler? Also, shouldn't you call "self.theAccounts" after setting it to nil?

in the getter, you are returning nil the first time because the block has not yet executed

Related

Fetching using NSFetchedResultsController vs NSManagedObjectContext directly

I had faced a problem and could resolve it, but I am curious to find out what exactly was the reason.
I have a shared class which should give me leave / vacation information of an employee. I have a fetch request in my utility class which provides the information of leave to fetch the objects.
This part of the code is responsible for fetching leaves:
#define FETCH_DIRECTLY 1
-(NSArray*)targetHoursArrayOnDate:(NSDate*)inDate
{
#if FETCH_DIRECTLY
NSFetchRequest *targetHoursFR = [CSUtilities fetchRequestForVacationOrLeave];
CSAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSArray *arrayOfTargetHours = [[appDelegate managedObjectContext] executeFetchRequest:targetHoursFR
error:NULL];
#else
NSArray *arrayOfTargetHours = [self.targetHoursFRC fetchedObjects];
#endif
NSPredicate *checkDatePredicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings)
{
BOOL dateExists = NO;
if ([evaluatedObject isKindOfClass:[CSTargetHours class]])
{
CSTargetHours *aTargetHour = (CSTargetHours*)evaluatedObject;
if ([aTargetHour.leaveDate isEqualToDate:inDate])
dateExists = YES;
}
return dateExists;
}];
NSArray *targetHoursOnQueriedDate = [arrayOfTargetHours filteredArrayUsingPredicate:checkDatePredicate];
if (0==[targetHoursOnQueriedDate count])
targetHoursOnQueriedDate = nil;
return targetHoursOnQueriedDate;
}
Please note, FETCH_DIRECTLY is the scenario where my doubts are. If I use the FRC to fetch leaves, it fails. Whereas if I use the App delegate's managedObjectContext directly, it fetches objects successfully! This is puzzling me.
The way am creating my FRC is here:
#synthesize targetHoursFRC = targetHoursFRC_;
-(NSFetchedResultsController*)targetHoursFRC
{
if (nil==targetHoursFRC_)
{
NSFetchRequest *targetHoursFR = [CSUtilities fetchRequestForVacationOrLeave];
CSAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
targetHoursFRC_ = [[NSFetchedResultsController alloc] initWithFetchRequest:targetHoursFR
managedObjectContext:appDelegate.managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
}
return targetHoursFRC_;
}
- (id)init
{
self = [super init];
if (self) {
[self.targetHoursFRC performFetch:NULL];
}
return self;
}
The only thing I am missing out here is, am not setting delegate to the FRC. But I dont need it since I am not interested in listening to the changes. Rather the leaves / vacation information should be ready when it is asked from some other module.
Is the internals of coredata somehow designed to inform FRC about the changes only if it has any delegates? Failing which, no matter when we trigger the -fetchedObjects call on FRC, it would give some old set of results?
Thanks,
Raj
If you don't set a delegate for the FRC, and implement at least one of the FRC delegate functions (e.g. controllerDidChangeContent:), then the FRC runs in the "no tracking mode".
That means that fetchedObjects will always return the result set of the initial performFetch: operation.
(See "Overview" section in the NSFetchedResultsController documentation).

Strange behaviour when trying to use Twitter ACAccount

I've been playing a bit with the new Social.Framework and in particular with SLRequest, both available on iOS 6 and upwards. Thing is, I got really surprised by a crash I've been getting when trying to post such request.
I've been getting the crash with both Facebook and Twitter accounts, so that's why I knew it wasn't related to any particular issue with one of them. It had to be related to the ACAccount object, which I'm getting in this way:
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"6.0")) {
//iOS 6
if (_twitterEnabled) {
if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeTwitter]) {
//Set up account
[accountStore requestAccessToAccountsWithType:accountTypeTwitter options:nil completion:^(BOOL granted, NSError *error) {
if (granted && !error) {
//Get account and get ready to post.
NSArray *arrayOfAccounts = [accountStore accountsWithAccountType:accountTypeTwitter];
if ([arrayOfAccounts count] > 0) {
_twitterAccount = [arrayOfAccounts lastObject];
}
}
}];
}
}
if (!_facebookEnabled) {
ACAccountType *accountTypeFacebook = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) {
NSArray *permissions = #[#"user_about_me",#"user_likes",#"email"];
NSMutableDictionary *options = [NSMutableDictionary dictionaryWithObjectsAndKeys:kFacebookAppIDString, ACFacebookAppIdKey, permissions, ACFacebookPermissionsKey, ACFacebookAudienceFriends, ACFacebookAudienceKey, nil];
[accountStore requestAccessToAccountsWithType:accountTypeFacebook options:options completion:^(BOOL granted, NSError *error) {
if (granted && !error) {
[options setObject:#[#"publish_stream",#"publish_actions"] forKey:ACFacebookPermissionsKey];
[accountStore requestAccessToAccountsWithType:accountTypeFacebook options:options completion:^(BOOL granted, NSError *error) {
if (granted && !error) {
NSArray *arrayOfAccounts = [accountStore accountsWithAccountType:accountTypeFacebook];
if ([arrayOfAccounts count] > 0) {
_fbAccount = [arrayOfAccounts lastObject];
}
}
}];
}
}];
}
}
}
Both _twitterAccount and _fbAccount are ACAccount objects in which I store the relevant account when retrieved from the Account Store.
The problem came when later I tried to use such objects (I'll just post the twitter method for brevity's sake):
NSDictionary *twitterMsg = #{#"status" : message};
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"6.0")) {
SLRequest *postRequest = [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodPOST URL:kTwitterUpdateStatusURL parameters:twitterMsg];
[postRequest setAccount:_twitterAccount];
[postRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
NSLog(#"Twitter HTTP response: %d", [urlResponse statusCode]);
}];
}
When calling setAccount: on postRequest I was getting an exception with the message: "Invalid account type for this request", which was obviously false. I also tried to debug the code and strangely the accountType on _twitterAccount was set to nil right before being sent to the ACAccount object. More strangely, if I put
NSLog(#"%#",_twitterAccount);
right under
_twitterAccount = [arrayOfAccounts lastObject]
on the first section of code, it works with no problem.
I've reviewed my code and I don't think I'm doing anything wrong so that I think it can be a bug on the framework? It looks like the ACAccountType is being released when it shouldn't, but I wanted to check if anyone of you could see anything wrong with my code that was provoking it and/or find an explanation for the issue, which I'm unable to solve by myself.
Thank you
UPDATE
It seems some other people have the same issue, I'm accepting one of the answers because it actually solves the issue, but I'll be looking forward to anyone that can find an explanation for the issue.
I was also getting "Invalid account type for this request" when using SLRequest on accounts retrieved via both of the following
ACAccountStore *account_store = [[ACAccountStore alloc] init];
ACAccountType *account_type_twitter = [account_store accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
// A.
NSArray *accounts = [account_store accountsWithAccountType:account_type_twitter];
// B.
NSString *account_id = #"id from doing account.identifier on one of the above";
ACAccount *account = [account_store accountWithIdentifier:account_id];
NSLog on the account had everything populated as expected but the type was set as null. Guessing this is a bug with Apple's SDK. Doing the following fixed the accounts for me so I could use them with SLRequest:
ACAccountType *account_type_twitter = [account_store accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
account.accountType = account_type_twitter;
You have to retain ACAccountStore:
#property (nonatomic, strong) ACAccountStore *accountStore;
The ACAccount documentation never states specifically that you must retain ACAccountStore, but it does state that
"To create and retrieve accounts from the Accounts database, you must
create an ACAccountStore object. Each ACAccount object belongs to a
single ACAccountStore object."
When you call:
NSArray *accounts = [accountStore accountsWithAccountType:accountType]
Those accountStore objects in the array don't necessarily have all of their properties fetched from the database. Some properties (like accountType) are only retrieved from the Accounts database if needed. This caused the strange behavior that you saw when you logged the account and everything magically worked. When you logged the account, the ACAccountStore object was still in memory and the logging caused the retrieval of the AccountType property. At that point, the AccountType was retained with the ACAccount and everything was able to work later even after ACAccountStore was released.
Are you retaining the ACAccountStore you used to fetch the arraryOfAccounts?
I use this code without problem. (Twitter only)
ACAccountStore *accountStore = [[ACAccountStore alloc] init];
ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
[accountStore requestAccessToAccountsWithType:accountType options:nil completion:^(BOOL granted, NSError *error) {
if (!granted) {
NSLog(#"Access denied.");
}
else {
NSArray *accounts = [accountStore accountsWithAccountType:accountType];
if (accounts.count > 0) {
twitterAccount = [accounts objectAtIndex:0];
}
}
}];
I think something about accountStore init issue?
Twitter's official reference is here.
Twitter: API requests with TWRequest

iphone: unable to copy instance of an array to other array

Dont why this is happening I have a method getOutage which returns an array of managed objects
NSArray *fetchedOutages = [context executeFetchRequest:fetchRequest error:&error];
if (error) {
NSLog(#"Error in Core Data: %#", [error description]);
}
return fetchedOutages;
when I try to copy this array to listOutage (this is a property)
#property (nonatomic, retain) NSArray *listOutage
I tried to copy this array like this in didRowSelectMethod like this
if (listOutage) {
NSLog(#"Its there");
[listOutage release];
}
listOutage=[[NSArray alloc] initWithArray:[self getOutage]];
I tried various other methods but all of then are failing.
This getoutage method returns 5 objects five objects got copied in listOutage but when I try to access the listOutage elements they are displayed as 'out of scope'
Please help me to overcome this I have to pass this to next ViewController.
Thanks in advance
when there is a property, use 'self.property' instead of 'property' that way, when somebody else reads your code it is more obvious if you mean an ivar or a property.
if you use self.property, you do not need to write
if (listOutage) {
NSLog(#"Its there");
[listOutage release];
}
listOutage=[[NSArray alloc] initWithArray:[self getOutage]];
instead, just write
NSArray newListOutage=[[NSArray alloc] initWithArray:[self getOutage]];
self.listOutage = newListOutage;
[newListOutage release];
the release and retain will be handled by the get/set method generated by the #synthesize property.

fetchedresults won't display rows contents, only titleforheaders and rowsinSection in UITableView

I can't figure out how come the row count is correct but the uitableview won't load the row contents the NSLog shows carresults=(null), but the row count is correct, on the simulator if I relaunch, the carresults get filled. It seems like I'm missing my first fetchedResultsController teh first time through, but how can it get the row count if it doesn't know what' there?
Help!! any Ideas? Thanks, Mike
The titleForHeaderInSection works fine, brings back the correct titles:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [[[fetchedResultsController1 sections] objectAtIndex:section] name];
}
This brings back the correct row count:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController1 sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
This does not populate the cells until a rebuild on simulator, never populates the iPhone.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *FirstViewIdentifier = #"FirstViewIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:FirstViewIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"Cell" owner:self options:nil];
cell = firstviewCell;
self.firstviewCell = nil;
}
Cars *carresults = (Cars *)[fetchedResultsController1 objectAtIndexPath:indexPath];
NSLog(#"carresults %#", carresults.make);
EDIT: Here is the FRC:
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[[[UIApplication sharedApplication] delegate] managedObjectContext] sectionNameKeyPath:#"key" cacheName:#"Root1"];
self.fetchedResultsController = aFetchedResultsController;
fetchedResultsController.delegate = self;
Since you haven't provided any debug info I can only guess as to what's wrong, so I'll ask you some questions. Does it in fact instantiate the firstviewCell property with the nib. If the cell is not connected to the firstviewCell property of the File Owner (in the nib) it won't work. Otherwise if the fetchedResultsController doesn't have anything in it you'll get an error if you try to access the data. If the nslog fires then you probably didn't get an error, which means that your Cars objects are being fetched theres just nothing in them. to see whats in the fetchedResultsController call NSLog(#"Fetched Objects: %#",[[fetchedResultsController fetchedObjects] description]); Keep in mind though, that fetchedObjects is only updated when you call performFetch. Since you say carresults gets filled when you restart the app it may be possible that you need to call saveContext for the results to get loaded. The only reason for this is if you create the data at runtime, before the table view gets loaded. Otherwise I would assume you have the table view set as the fetched results controller's delegate so that it gets informed of any changes and responds appropriately. The app delegate usually does this on applicationWillResign active or applicationWillTerminate (applicationWillTerminate doesn't seem to get called by iOS4 during normal closing).The only other thing I could think of is that maybe your SectionInfo object might contain the wrong information, try debugging that too.
Good Luck,
Rich
Edit: I appologize, the save context method is a method added to your appdelegate when you create an app based on core data. a good way to make a core data stack is to wrap it in an NSObject, it can be useful to make it a singleton ,unless of course you need concurrency in which case it gets really complicated. This is the implementation including the save context function:
// CoreDataStack.h
// do not call alloc, retain, release, copy or especially copyWithZone: (because I didn't bother to override it since you shouldn't try to create this in anything but the main thread, and definatly don't dispatchasync this object's methods)
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#define kYourAppName #"This should be replaced by the name of your datamodel"
#interface CoreDataStack : NSObject {
#private
NSManagedObjectContext *managedObjectContext_;
NSManagedObjectModel *managedObjectModel_;
NSPersistentStoreCoordinator *persistentStoreCoordinator_;
}
#property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
#property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
+ (CoreDataStack *)sharedManager;
+ (void)sharedManagerDestroy;
// call this in your app delegate in applicationWillTerminate and applicationWillResignActive
- (void)saveContext;
- (NSURL *)applicationLibraryDirectory;
#end
// CoreDataStack.m
#import "CoreDataStack.h"
#interface CoreDataStack ()
- (oneway void)priv_release;
#end
#implementation CoreDataStack
static CoreDataStack *sharedManager = nil;
+ (CoreDataStack *)sharedManager {
if (sharedManager != nil) {
return sharedManager;
}
sharedManager = [[CoreDataStack alloc] init];
return sharedManager;
}
+ (void)sharedManagerDestroy {
if (sharedManager) {
[sharedManager priv_release];
sharedManager = nil;
}
}
- (id)retain {
return self;
}
- (id)copy {return self;}
- (oneway void)release{}
- (oneway void)priv_release {
[super release];
}
- (void)saveContext {
NSError *error = nil;
if (managedObjectContext_ != nil) {
if ([managedObjectContext_ hasChanges] && ![managedObjectContext_ save:&error]) {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
*/
//abort();
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"The app has run into an error trying to save, please exit the App and contact the developers. Exit the program by double-clicking the home button, then tap and hold the iMean icon in the task manager until the icons wiggle, then tap iMean again to terminate it"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
}
}
}
#pragma mark -
#pragma mark Core Data stack
/**
Returns the managed object context for the application.
If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
*/
- (NSManagedObjectContext *)managedObjectContext {
if (managedObjectContext_ != nil) {
return managedObjectContext_;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext_ = [[NSManagedObjectContext alloc] init];
[managedObjectContext_ setPersistentStoreCoordinator:coordinator];
}
return managedObjectContext_;
}
/**
Returns the managed object model for the application.
If the model doesn't already exist, it is created from the application's model.
*/
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel_ != nil) {
return managedObjectModel_;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"kYourAppName" withExtension:#"momd"];
managedObjectModel_ = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return managedObjectModel_;
}
/**
Returns the persistent store coordinator for the application.
If the coordinator doesn't already exist, it is created and the application's store added to it.
*/
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator_ != nil) {
return persistentStoreCoordinator_;
}
NSString *yourAppName = [[NSString stringWithFormat:#"%#.sqlite",kYourAppName] autorelease];
NSURL *storeURL = [[self applicationLibraryDirectory] URLByAppendingPathComponent:yourAppName];
NSError *error = nil;
persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
Typical reasons for an error here include:
* The persistent store is not accessible;
* The schema for the persistent store is incompatible with current managed object model.
Check the error message to determine what the actual problem was.
If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory.
If you encounter schema incompatibility errors during development, you can reduce their frequency by:
* Simply deleting the existing store:
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil]
* Performing automatic lightweight migration by passing the following dictionary as the options parameter:
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.
*/
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
// abort();
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"The app has run into an error trying to load it's data model, please exit the App and contact the developers. Exit the program by double-clicking the home button, then tap and hold the iMean icon in the task manager until the icons wiggle, then tap iMean again to terminate it"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
}
return persistentStoreCoordinator_;
}
#pragma mark -
#pragma mark Application's Library directory
/**
Returns the URL to the application's Documents directory.
*/
// returns the url of the application's Library directory.
- (NSURL *)applicationLibraryDirectory {
return [[[NSFileManager defaultManager] URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] lastObject];
}
#pragma mark -
#pragma mark Memory management
- (void)dealloc {
// release and set all pointers to nil to avoid static issues
[managedObjectContext_ release];
managedObjectContext_ = nil;
[managedObjectModel_ release];
managedObjectModel_ = nil;
[persistentStoreCoordinator_ release];
persistentStoreCoordinator_ = nil;
[super dealloc];
}
#end

Core Data - accessing objects returned from fetch EXC_BAD_ACCESS

The following is implemented as a class method in a category on one of my managed object entities, with a bunch of other operations:
+ (NSArray*)newArrayOfAllOtherBibs
{
NSManagedObjectContext* moc = [(MyAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
NSString* entityName = NSStringFromClass([self class]);
NSEntityDescription* entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:moc];
[fetchRequest setEntity:entity];
NSError* error;
NSArray* items = [moc executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];
NSMutableArray* bibArray = [NSMutableArray array];
for(int i = 0; i < [items count]; i++)
{
Person* person = [items objectAtIndex:i];
if(![person.isSelf isEqualToString:#"YES"])
{
// crash here!
if([person.bib length] > 0)
// crash here!
[bibArray addObject:person.bib];
}
}
return [bibArray retain];
}
So it is supposed to look at all entities for Person, returned for a very simple fetch, and add all that are not marked as "self" (attribute isSelf, type NSString) to a new array which is returned to the caller. All the other methods for add/delete/find matching are working well.
Using
NSString* entityName = NSStringFromClass([self class]);
is an attempt to make the function more generic so I can cut&paste these functions for other entities as required with less editing.
Person looks like this:
#interface Person : NSManagedObject
{
}
#property (nonatomic, retain) NSString * bib;
#property (nonatomic, retain) NSString * isSelf;
[...]
#end
Question is, what could explain EXC_BAD_ACCESS on the line marked? Analyzer shows nothing. At that point person is clearly OK or I would expect it to die earlier, on accessing .isSelf. (It could be made a boolean but I find having two kinds of boolean, one BOOL and one NSNumber, error prone). If person.bib is nil then calling length on it should still return 0 right? But it can't be nil anyway since "bib" is the key for these entities and one is never created without it. At this stage nothing has been deleted from the store, it's a fresh store that has been saved since last addition.
The cause of the problem:
NSDictionary *resultDict = [responseString JSONValue];
NSString* bib = [resultDict objectForKey:#"bib"];
person = [NSEntityDescription insertNewObjectForEntityForName:#"Person" inManagedObjectContext:moc];
person.bib = bib;
[... lots of stuff setting up relationships for person etc.]
NSError *error;
if (![moc save:&error])
{
NSLog(#"Core Data Save error %#, %#", error, [error userInfo]);
}
The fix:
person.bib = [bib copy];
seems like the bib string was not valid at the time the Person entity was saved.
The best thing to do is set NSZombieEnabled in the executable and debug it from there. This way you'll be able to see what is causing the problem.
If you are loading some vars lazily make sure you set them to nil when you release them because if not next time when accessed them. They will not be "skipped", you app will try to use them but since they are not pointing to a valid object it fails and gives you errors like EXC_BAD_ACCESS
Person.bib may not have been loaded yet.
Did you leave the bib property defined as #dynamic and not #synthesize?
Did you override the bib accessor method? If so your override needs to be KVO friendly.