NSDistantObject enumeration - cocoa

I was make communication for client-server application and have strange problem.
here is a code where i pickup objects.
- (byref NSArray*)objectsOfName:(bycopy NSString*)name
withPredicate:(bycopy NSPredicate*)predicate;
{
NSManagedObjectContext *context = [self managedObjectContext];
NSError *error = nil;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:name
inManagedObjectContext:context]];
[request setPredicate:predicate];
NSArray *results = [context executeFetchRequest:request error:&error];
[request release], request = nil;
if (error) {
NSLog(#"%#:%# Error on fetch %#", [self class], NSStringFromSelector(_cmd), error);
return nil;
}
//NSLog(#"%#:%# Result of fetch is %#", [self class], NSStringFromSelector(_cmd), results);
return results;
}
Here is pickup:
NSArray *destinations;
#ifdef SNOW_CLIENT
destinations = [server objectsOfName:#"DestinationsListWeBuy" withPredicate:predicate];
If i do
NSLog(#"Destination:%#\n",destinations);
i seen all objects in log.
If i try to do
NSLog(#"all:%#\n%#\n%#\n",[[destinations objectAtIndex:0] valueForKey:#"rate"],[[destinations objectAtIndex:0] valueForKey:#"lastUsedACD"],[[destinations objectAtIndex:0] valueForKey:#"lastUsedCallAttempts"]);
i seen attributes also.
But, if i try to do loop around objects:
for (NSManagedObject *dest in destinations)
{
NSLog(#"all:%#\n%#\n%#\n",[dest valueForKey:#"rate"],[dest valueForKey:#"lastUsedACD"],[dest valueForKey:#"lastUsedCallAttempts"]);
i have EXC_BAD_ACCESS in this part of code:
for (NSManagedObject *dest in destinations)
all debug technic, which i know, don't give me possibility to understand, what happened. (NSZombieEnabled = YES)
if i do loop at another manner:
for (NSUInteger count = 0;count < [destinations count]; count++)
NSLog(#"all:%#\n%#\n%#\n",[[destinations objectAtIndex:count] valueForKey:#"rate"],[[destinations objectAtIndex:count] valueForKey:#"lastUsedACD"],[[destinations objectAtIndex:count] valueForKey:#"lastUsedCallAttempts"]);
i seen all keys without exception. All nsmanagedobject's is subclassed.
If i need implement encodeWithCored method for all subclasses, examples is appreciated.
*UPDATE for Marcus *
This is how i receive objects from server side:
- (byref NSArray*)allObjects
{
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (!coordinator) {
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setValue:#"Failed to initialize the store" forKey:NSLocalizedDescriptionKey];
[dict setValue:#"There was an error building up the data file." forKey:NSLocalizedFailureReasonErrorKey];
NSError *error = [NSError errorWithDomain:#"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
[[NSApplication sharedApplication] presentError:error];
return nil;
}
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
[moc setPersistentStoreCoordinator:coordinator];
[moc setUndoManager:nil];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self
selector:#selector(mergeChangesForClient:)
name:NSManagedObjectContextDidSaveNotification
object:thirdMOC];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Carrier"
inManagedObjectContext:moc];
[request setEntity:entity];
[request setIncludesSubentities:YES];
NSError *error = nil;
NSArray *objects = [moc executeFetchRequest:request error:&error];
[request release], request = nil;
for (NSManagedObject *carrier in objects) {
NSSet *destinations = [carrier valueForKeyPath:#"destinationsListForSale"];
for (NSManagedObject *destination in destinations) [destination addObserver:self forKeyPath:#"rate" options:NSKeyValueObservingOptionNew context:nil];
}
if (error) {
NSLog(#"%#:%# error: %#", [self class], NSStringFromSelector(_cmd), error);
return nil;
}
return objects;
}
This is what i do with them on client side:
NSArray *allObjects = [server allObjects];
[carrierArrayController setContent:allObjects];
There is no serialization in this case. Any other ways (like send copy of server moc to client side doesn't work, it just generate exceptions on main.c).
p.s. many thanks to Marcus for his Core Data book.

unrecognized selector sent to class 0x1000a2ed8 2011-03-17 02:15:18.566 snowClient[19380:903] +[AppDelegate encodeWithCoder:]: unrecognized selector sent to class 0x1000a2ed8
That is not a core data problem. That is an error in your code where you are trying to call a method on an object that does not respond to that method. You need to track that down as it appears that you are trying to serialize your AppDelegate.
Update
What kind of class is 0x1000a2ed8? Break on the exception and print out the object to see what it is. Again, this is not a core data error directly, it is sending a messages to an object that does not respond to that message. It is possible that Core Data no longer allows you to send Managed objects across as distributed objects. It is possible that this is simply an issue with an over-released object. No way to know without further investigation.
Step one: Find out what object 0x1000a2ed8 is and see if the object changes from one run to the next.

Related

When sorting a NSMutable array from core data, i get an error

Below is my viewDidLoad method in a tableViewController. When viewDidLoad runs this error comes up
2014-03-03 12:44:54.904 SalesCRM2[30188:70b] -[_PFArray sortUsingDescriptors:]: unrecognized selector sent to instance 0x8c45710
2014-03-03 12:44:54.931 SalesCRM2[30188:70b] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_PFArray sortUsingDescriptors:]: unrecognized selector sent to instance 0x8c45710'
on this line of code
[array sortUsingDescriptors:[NSArray arrayWithObject:sort]];
Here is the whole method
- (void)viewDidLoad
{
[super viewDidLoad];
JCAppDelegate *appDelegate =
[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context =
[appDelegate managedObjectContext];
NSEntityDescription *entityDesc =
[NSEntityDescription entityForName:#"Customers"
inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];
NSError *error;
NSArray *objects = [context executeFetchRequest:request
error:&error];
NSMutableArray *array = (NSMutableArray *)objects;
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:#"firstName" ascending:YES];
[array sortUsingDescriptors:[NSArray arrayWithObject:sort]];
if ([objects count] == 0)
{
//_isEmpty = YES;
}
else
{
//_isEmpty = NO;
_resultsArray = (NSMutableArray *)objects;
NSLog(#"resultsArray: %i",[_resultsArray count]);
// matches = objects[0];
// _address.text = [matches valueForKey:#"address"];
// _phone.text = [matches valueForKey:#"phone"];
// _status.text = [NSString stringWithFormat:
// #"%lu matches found", (unsigned long)[objects count]];
}
}
Read the error message. It's telling you the problem. You can say sortUsingDescriptors: to an immutable array. It is immutable.
Now, as for what you are doing wrong, it is much more interesting! You are saying:
NSMutableArray *array = (NSMutableArray *)objects;
Perhaps you believe that this turns an immutable array into a mutable array. It doesn't. You can't turn a silk purse into a sow's ear by typecasting. You may lie to the compiler (and you did, by typecasting to a false class), but you can't lie to the runtime. What an object is, that's what it is, no matter what you call it.
If you want a mutable array, you must make a mutable array (e.g. by calling mutableCopy) - it isn't enough to say a thing is a mutable array when in fact it isn't.

Crash Occurring on First Launch When populating core data database

I keep getting an error in the debugger for my application saying,
2013-06-23 16:07:15.826 collection view recipies[5681:c07] -[NSManagedObject length]: unrecognized selector sent to instance 0x9495280
2013-06-23 16:07:15.827 collection view recipies[5681:c07] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSManagedObject length]: unrecognized selector sent to instance 0x9495280'
* First throw call stack:
(0x26ac012 0x1517e7e 0x27374bd 0x269bbbc 0x269b94e 0x2b11c4 0x16d80a 0x4464 0x64f2da 0x6508f4 0x652b91 0x19c2dd 0x152b6b0 0x18eefc0 0x18e333c 0x18eeeaf 0x23b2bd 0x183b56 0x18266f 0x182589 0x1817e4 0x18161e 0x1823d9 0x1852d2 0x22f99c 0x17c574 0x17c76f 0x17c905 0x185917 0x14996c 0x14a94b 0x15bcb5 0x15cbeb 0x14e698 0x2c06df9 0x2c06ad0 0x2621bf5 0x2621962 0x2652bb6 0x2651f44 0x2651e1b 0x14a17a 0x14bffc 0x1e9d 0x1dc5)
libc++abi.dylib: terminate called throwing an exception
In My application delegate, if check to see if the application is being launched for the first time, and if it is, I then add several image paths to the core data structure.
In AppDelegate.m under ApplicationDidFinishLaunchingWithOptions,
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"HasLaunchedOnce"])
{
// app already launched
}
else
{
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"HasLaunchedOnce"];
[[NSUserDefaults standardUserDefaults] synchronize];
// This is the first launch ever
NSArray *mainDishImages = [NSArray arrayWithObjects:#"egg_benedict.jpg", #"full_breakfast.jpg", #"ham_and_cheese_panini.jpg", #"ham_and_egg_sandwich.jpg", #"hamburger.jpg", #"instant_noodle_with_egg.jpg", #"japanese_noodle_with_pork.jpg", #"mushroom_risotto.jpg", #"noodle_with_bbq_pork.jpg", #"thai_shrimp_cake.jpg", #"vegetable_curry.jpg", nil];
NSArray *drinkDessertImages = [NSArray arrayWithObjects:#"angry_birds_cake.jpg", #"creme_brelee.jpg", #"green_tea.jpg", #"starbucks_coffee.jpg", #"white_chocolate_donut.jpg", nil];
for (NSString *imagePath in mainDishImages) {
NSManagedObjectContext *context = [self managedObjectContext];
NSManagedObject *newRecipe = [NSEntityDescription insertNewObjectForEntityForName:#"Recipe" inManagedObjectContext:context];
[newRecipe setValue:imagePath forKey:#"imageFilePath"];
}
for (NSString *imagePath in drinkDessertImages) {
NSManagedObjectContext *context = [self managedObjectContext];
NSManagedObject *newRecipe = [NSEntityDescription insertNewObjectForEntityForName:#"Deserts" inManagedObjectContext:context];
[newRecipe setValue:imagePath forKey:#"imageFilePath"];
}
}
And I access that data in my collectionViewController, I access that data.
- (NSManagedObjectContext *)managedObjectContext{
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Deserts"];
deserts = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
NSFetchRequest *fetchRequestTwo = [[NSFetchRequest alloc] initWithEntityName:#"Recipe"];
meals = [[managedObjectContext executeFetchRequest:fetchRequestTwo error:nil] mutableCopy];
recipeImages = [NSArray arrayWithObjects:meals, deserts, nil];
[self.collectionView reloadData];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Deserts"];
deserts = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
NSFetchRequest *fetchRequestTwo = [[NSFetchRequest alloc] initWithEntityName:#"Recipe"];
meals = [[managedObjectContext executeFetchRequest:fetchRequestTwo error:nil] mutableCopy];
recipeImages = [NSArray arrayWithObjects:meals, deserts, nil];
UICollectionViewFlowLayout *collectionViewLayout = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout;
collectionViewLayout.sectionInset = UIEdgeInsetsMake(5, 0, 5, 0);
self.navigationController.navigationBar.translucent = YES;
self.collectionView.contentInset = (UIEdgeInsetsMake(44, 0, 0, 0));
selectedRecipes = [NSMutableArray array];
}
According to crashalytics, the error is in the line where it says
recipeImageView.image = [UIImage imageNamed:[recipeImages[indexPath.section] objectAtIndex:indexPath.row]];
In the method
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = #"Cell";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
UIImageView *recipeImageView = (UIImageView *)[cell viewWithTag:100];
recipeImageView.image = [UIImage imageNamed:[recipeImages[indexPath.section] objectAtIndex:indexPath.row]];
cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"photo-frame"]];
cell.selectedBackgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"photo-frame-selected.png"]];
return cell;
}
I hope you can help. Thanks In Advance!
The UIImage method imageNamed takes an NSString as argument, but you pass a NSManagedObject to it.
You should get the image path from the managed object first. Try this:
id managedObject = [recipeImages[indexPath.section] objectAtIndex:indexPath.row];
NSString* imagePath = [managedObject valueForKey:#"imageFilePath"];
recipeImageView.image = [UIImage imageNamed:imagePath];

how could i integrate via me social site into iphone app

hi i want to integrate Via Me social site into my iphone app,i googled but didn't find any samples.
The basic process is as follows:
Create a custom URL scheme for your app. Via Me will use this after the user has been authenticated, to return to your app. In my example, I created one called "robviame://"
Register your app at http://via.me/developers. This will give you a client id and a client secret:
When you want to authenticate the user, you call:
NSString *redirectUri = [[self redirectURI] stringByAddingPercentEscapesForURLParameterUsingEncoding:NSUTF8StringEncoding];
NSString *urlString = [NSString stringWithFormat:#"https://api.via.me/oauth/authorize/?client_id=%#&redirect_uri=%#&response_type=code", kClientID, redirectUri];
NSURL *url = [NSURL URLWithString:urlString];
[[UIApplication sharedApplication] openURL:url];
What that will do is fire up your web browser and give the user a chance to log on and grant permissions to your app. When user finishes that process, because you've defined your custom URL scheme, it will call the following method in your app delegate:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
// do whatever you want here to parse the code provided back to the app
}
for example, I'll call a handler for my Via Me response:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
ViaMeManager *viaMeManager = [ViaMeManager sharedManager];
if ([[url host] isEqualToString:viaMeManager.host])
{
[viaMeManager handleViaMeResponse:[self parseQueryString:[url query]]];
return YES;
}
return NO;
}
// convert the query string into a dictionary
- (NSDictionary *)parseQueryString:(NSString *)query
{
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
NSArray *queryParameters = [query componentsSeparatedByString:#"&"];
for (NSString *queryParameter in queryParameters) {
NSArray *elements = [queryParameter componentsSeparatedByString:#"="];
NSString *key = [elements[0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *value = [elements[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
value = [[value componentsSeparatedByString:#"+"] componentsJoinedByString:#" "];
[dictionary setObject:value forKey:key];
}
return dictionary;
}
That handler might, for example, save the code and then request the access token:
- (void)handleViaMeResponse:(NSDictionary *)parameters
{
self.code = parameters[#"code"];
if (self.code)
{
// save the code
[[NSUserDefaults standardUserDefaults] setValue:self.code forKey:kViaMeUserDefaultKeyCode];
[[NSUserDefaults standardUserDefaults] synchronize];
// now let's authenticate the user and get an access key
[self requestToken];
}
else
{
NSLog(#"%s: parameters = %#", __FUNCTION__, parameters);
NSString *errorCode = parameters[#"error"];
if ([errorCode isEqualToString:#"access_denied"])
{
[[[UIAlertView alloc] initWithTitle:nil
message:#"Via Me functions will not be enabled because you did not authorize this app"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil] show];
}
else
{
[[[UIAlertView alloc] initWithTitle:nil
message:#"Unknown Via Me authorization error"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil] show];
}
}
}
and the code to retrieve the token might look like:
- (void)requestToken
{
NSURL *url = [NSURL URLWithString:#"https://api.via.me/oauth/access_token"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
NSDictionary *paramsDictionary = #{#"client_id" : kClientID,
#"client_secret" : kClientSecret,
#"grant_type" : #"authorization_code",
#"redirect_uri" : [self redirectURI],
#"code" : self.code,
#"response_type" : #"token"
};
NSMutableArray *paramsArray = [NSMutableArray array];
[paramsDictionary enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) {
[paramsArray addObject:[NSString stringWithFormat:#"%#=%#", key, [obj stringByAddingPercentEscapesForURLParameterUsingEncoding:NSUTF8StringEncoding]]];
}];
NSData *paramsData = [[paramsArray componentsJoinedByString:#"&"] dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPBody:paramsData];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error)
{
NSLog(#"%s: NSURLConnection error = %#", __FUNCTION__, error);
return;
}
NSError *parseError;
id results = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
if (parseError)
{
NSLog(#"%s: NSJSONSerialization error = %#", __FUNCTION__, parseError);
return;
}
self.accessToken = results[#"access_token"];
if (self.accessToken)
{
[[NSUserDefaults standardUserDefaults] setValue:self.accessToken forKey:kViaMeUserDefaultKeyAccessToken];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}];
}
Hopefully this will be enough to get you going. This is described in greater detail at the http://via.me/developers page.

edit an attribute in core data

here is my code to edit a particular attribute and save it to the sqlite DB but i can't save the changes to the DB.
-(void)changeMemberKey
{
NSEntityDescription *entityDesc=[NSEntityDescription entityForName:#"Table1" inManagedObjectContext:context];
NSFetchRequest *request=[[NSFetchRequest alloc] init];
NSPredicate *predicate=[NSPredicate predicateWithFormat:#"(member_id=Null)"];
[request setPredicate:predicate];
[request setEntity:entityDesc];
Table1 *matches;
NSError *error;
NSArray *objects=[context executeFetchRequest:request error:&error];
NSLog(#"Object count===%d",[objects count]);
for(int i=0;i<[objects count];i++)
{
matches=[objects objectAtIndex:i];
Table1 *data=(Table1 *)matches;
NSLog(#"Data before===%#",data);
[data setValue:memberKey forKey:#"member_id"];
[context save:&error];
NSLog(#"Data after====%#",data);
data=nil;
}
entityDesc=nil;
request=nil;
matches=nil;
error=nil;
objects=nil;
}
Try to replace the for loop to
for(Table1 * data in objects)
data.member_id = memberKey;
if (! [context save:&error])
NSLog(#"Couldn't save data! Error:%#", [error description]);
Not sure whether it'll work or not, just take a try. Anyway, it's cleaner.

Broken Multithreading With Core Data

This is a better-focused version of an earlier question that touches upon an entirely different subject from before.
I am working on a Cocoa Core Data application with multiple threads. There is a Song and Artist; every Song has an Artist relation. There is a delegate code file not cited here; it more or less looks like the template XCode generates.
I am far better working with the former technology than the latter, and any multithreading capability came from a Core Data template. When I'm doing all my ManagedObjectContext work in one method, I am fine. When I put fetch-or-insert-then-return-object work into a separate method, the application halts (but does not crash) at the new method's return statement, seen below. The new method even gets its own MOC to be safe, and it has not helped any. The result is one addition to Song and a halt after generating an Artist.
I get no errors or exceptions, and I don't know why. I've debugged out the wazoo. My theory is that any errors occurring are in another thread, and the one I'm watching is waiting on something forever.
What did I do wrong with getArtistObject: , and how can I fix it? Thanks.
- (void)main
{
NSInteger songCount = 1;
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
[moc setPersistentStoreCoordinator:[[self delegate] persistentStoreCoordinator]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(contextDidSave:) name:NSManagedObjectContextDidSaveNotification object:moc];
/* songDict generated here */
for (id key in songDict)
{
NSManagedObject *song = [NSEntityDescription insertNewObjectForEntityForName:#"Song" inManagedObjectContext:moc];
[song setValue:[songDictItem objectForKey:#"Name"] forKey:#"title"];
[song setValue:[self getArtistObject:(NSString *) [songDictItem objectForKey:#"Artist"]] forKey:#"artist"];
[songDictItem release];
songCount++;
}
NSError *error;
if (![moc save:&error])
[NSApp presentError:error];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:moc];
[moc release], moc = nil;
[[self delegate] importDone];
}
- (NSManagedObject*) getArtistObject:(NSString*)theArtist
{
NSError *error = nil;
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
[moc setPersistentStoreCoordinator:[[self delegate] persistentStoreCoordinator]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(contextDidSave:) name:NSManagedObjectContextDidSaveNotification object:moc];
NSFetchRequest *fetch = [[[NSFetchRequest alloc] init] autorelease];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Artist" inManagedObjectContext:moc];
[fetch setEntity:entityDescription];
// object to be returned
NSManagedObject *artistObject = [[NSManagedObject alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:moc];
// set predicate (artist name)
NSPredicate *pred = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"name = \"%#\"", theArtist]];
[fetch setPredicate:pred];
NSArray *response = [moc executeFetchRequest:fetch error:&error];
if (error)
[NSApp presentError:error];
if ([response count] == 0) // empty resultset --> no artists with this name
{
[artistObject setValue:theArtist forKey:#"name"];
NSLog(#"%# not found. Adding.", theArtist);
return artistObject;
}
else
return [response objectAtIndex:0];
}
#end
Try locking the managed object context before you access it and unlocking it again after you are done with it:
- (void)main
{
NSInteger songCount = 1;
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
[moc lock];
[moc setPersistentStoreCoordinator:[[self delegate] persistentStoreCoordinator]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(contextDidSave:) name:NSManagedObjectContextDidSaveNotification object:moc];
[moc unlock];
/* songDict generated here */
for (id key in songDict)
{
[moc lock];
NSManagedObject *song = [NSEntityDescription insertNewObjectForEntityForName:#"Song" inManagedObjectContext:moc];
[moc unlock];
[song setValue:[songDictItem objectForKey:#"Name"] forKey:#"title"];
[song setValue:[self getArtistObject:(NSString *) [songDictItem objectForKey:#"Artist"]] forKey:#"artist"];
[songDictItem release];
songCount++;
}
NSError *error;
[moc lock];
if (![moc save:&error])
[NSApp presentError:error];
[moc unlock];
[moc lock];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:moc];
[moc unlock];
[moc release], moc = nil;
[[self delegate] importDone];
}
- (NSManagedObject*) getArtistObject:(NSString*)theArtist
{
NSError *error = nil;
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
[moc lock];
[moc setPersistentStoreCoordinator:[[self delegate] persistentStoreCoordinator]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(contextDidSave:) name:NSManagedObjectContextDidSaveNotification object:moc];
[moc unlock];
NSFetchRequest *fetch = [[[NSFetchRequest alloc] init] autorelease];
[moc lock];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Artist" inManagedObjectContext:moc];
[moc unlock];
[fetch setEntity:entityDescription];
// object to be returned
[moc lock];
NSManagedObject *artistObject = [[NSManagedObject alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:moc];
[moc unlock];
// set predicate (artist name)
NSPredicate *pred = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"name = \"%#\"", theArtist]];
[fetch setPredicate:pred];
[moc lock];
NSArray *response = [moc executeFetchRequest:fetch error:&error];
[moc unlock];
if (error)
[NSApp presentError:error];
if ([response count] == 0) // empty resultset --> no artists with this name
{
[artistObject setValue:theArtist forKey:#"name"];
NSLog(#"%# not found. Adding.", theArtist);
return artistObject;
}
else
return [response objectAtIndex:0];
}
#end
You can not lock NSManagedObjects!

Resources