Open subdigital opened 3 years ago
originally written by Alex Hedley on 04/21/2012 16:11:22
Great tut, was looking at some code on Github and came across this tut on Mogen, thought it might be useful [http://raptureinvenice.com/...]
originally written by Donwlarson on 05/01/2012 16:23:50
Two requests:
1) How to save and retrieve a .png image from CoreData.
2) How to programmatically delete the old database when the refresh button is pressed as part of the refresh process. This would be required on the actual iOS device, right?
Thank you. :-)
originally written by Ben Scheirman on 05/01/2012 17:09:13
1) You can add binary attributes to a model. Here's a stack overflow question which demonstrates this in action: http://stackoverflow.com/qu...
I would probably lean on saving the image to disk and putting the path to the image in your core data model. I'm not sure if binary data is retrieved by default or not, but it would be cumbersome to have to exclude this attribute from general fetches.
2) It's actually really easy to delete the old database (if you wanted to) by just removing the sqlite file and re-initializing it. This isn't really needed on a device, because we are checking the server id before inserting or updating. But if you didn't have this type of unique key (or if you needed to make sure to delete records that aren't there), then you might have to do this.
originally written by Martin Juhasz on 05/08/2012 20:11:08
a little request: it would be nice if you add the complete lines of code you write during a show in the show-notes. f.e. i'm missing the shell script for mogenerator here.
originally written by Marcioluizdesign on 05/10/2012 19:10:00
Hello Ben!! Great Work Mate! I'm building a wine cart for iPad and this just fitted well!!To populate my database I've create an update button and two functions as written bellow:- (IBAction)botaoAtualizacao:(id)sender { [self updateDataMainMenu:aWLBaseURL];}-(void) updateDataMainMenu:(NSString *)aWLBaseURL{ if (!_hud) { _hud = [[MBProgressHUD alloc] initWithView:self.view]; } [_hud setMode:MBProgressHUDModeIndeterminate]; [_hud setLabelText:@"CarregandoMenuPrincipal..."]; [self.view addSubview:_hud]; NSString *stringURL = [aWLBaseURL stringByAppendingString:@"json/titulos/1"]; NSURL *url = [NSURL URLWithString:stringURL]; NSLog(@"%@",url); NSURLRequest *req = [NSURLRequest requestWithURL:url]; NSLog(@"%@",req); AFJSONRequestOperation *op; op = [AFJSONRequestOperation JSONRequestOperationWithRequest:req success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSONmainMenu) { [self parseMainMenu:JSONmainMenu]; } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSONmainMenu) { [self displayError]; }]; [_hud show:YES]; [op start]; }- (void)parseMainMenu:(id)menus { [_hud setMode:MBProgressHUDModeDeterminate]; [_hud setProgress:0]; [_hud setLabelText:@"LoadingData..."]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ NSInteger totalRecords = [menus count]; NSInteger currentRecord = 0; NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init]; [context setPersistentStoreCoordinator:[[AWLDataModel sharedDataModel] persistentStoreCoordinator]]; for (NSDictionary *dictionary in menus) { NSInteger codigoCliente = [[dictionary objectForKey:@"CodigoCliente"] intValue]; MenuPrincipal *menuPrincipal = [MenuPrincipal menuPrincipalWithCodigoCliente:codigoCliente usingManagedObjectContext:context]; if (menuPrincipal == nil) { menuPrincipal = [MenuPrincipal insertInManagedObjectContext:context]; } [menuPrincipal updateAttributes:dictionary]; currentRecord++; dispatch_async(dispatch_get_main_queue(), ^{ float percent = ((float)currentRecord)/totalRecords; [_hud setProgress:percent]; }); } NSError *error = nil; if ([context save:&error]) { dispatch_async(dispatch_get_main_queue(), ^{ [_hud setLabelText:@"Done!"]; [_hud hide:YES afterDelay:2.0]; }); } else { NSLog(@"ERROR: %@ %@", [error localizedDescription], [error userInfo]); exit(1); } });}The JSON fetched is in the following link: http://www.cntecnologia.com... I'm getting the following error from the objectForKey method:2012-05-10 15:18:10.660 Adega's WineList[213:4c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString objectForKey:]: unrecognized selector sent to instance 0x2e7e00'*** First throw call stack:(0x3597888f 0x3359c259 0x3597ba9b 0x3597a915 0x358d5650 0x11f19 0x33d05c59 0x33d117bb 0x34b91dfb 0x34b91cd0)terminate called throwing an exception2012-05-10 15:18:10.661 Adega's WineList[213:5307] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString objectForKey:]: unrecognized selector sent to instance 0x2da3a0'*** First throw call stack:(0x3597888f 0x3359c259 0x3597ba9b 0x3597a915 0x358d5650 0x11599 0x33d05c59 0x33d117bb 0x34b91dfb 0x34b91cd0)terminate called throwing an exceptionCould you help me with that?
originally written by Ben Scheirman on 05/10/2012 19:16:47
Since the code formatting didn't come through, it's hard to read (maybe post it to gist.github.com?).
The error message is telling me that you're calling objectForKey on what you think is a dictionary, but it's actually a string.
originally written by Marcioluizdesign on 05/10/2012 20:25:24
Well,Here's the code pasted in pastebin: <iframe src="http://pastebin.com/embed_i..." style="border:none;width:100%"></iframe>The JSON fetched is in the following link: http://www.cntecnologia.com.br...
originally written by Marcioluizdesign on 05/10/2012 20:26:47
ok, doesn't accpet iframes... here's the link: http://pastebin.com/xCxEsYXw
originally written by Ben Scheirman on 05/10/2012 20:26:58
The comment system won't allow HTML. Just paste a link and it will become clickable.
originally written by Ben Scheirman on 05/10/2012 20:30:52
Can you post the JSON link again? Looks like the other one got truncated.
originally written by Ben Scheirman on 05/10/2012 20:46:44
Sorry about that! I've added the script in the show notes. I also added some more to Episode 11's notes in the same vein. Thanks for catching it.
originally written by Marcioluizdesign on 05/10/2012 20:50:32
originally written by Ben Scheirman on 05/10/2012 20:57:36
The JSON returned in that is an object with a single attribute.
Summarized, it looks like:
{
"foo":"[1, 2, 3]"
}
While the value may look like JSON, it's actually being returned as a string.
I'd advise to fix this on the server side. You can handle it on the client side of course, but that's not fixing the problem at the source, and you'll likely have to apply this fix elsewhere if you have more than one client.
If you _must_ parse this without touching the server, then you can do this:
id fooValue = [dictionary objectForKey:@"foo"];
id values = [fooValue JSONValue];
This assumes you're using SBJSON. If you're using JSONKit, you'll have to look up the syntax, but it is similar.
originally written by Marcioluizdesign on 05/10/2012 21:07:34
Thanks for that! Well I've talked to my server develper, and he changed the json now it looks better: http://www.cntecnologia.com..., but the way it is isn't working either..
originally written by Ben Scheirman on 05/10/2012 21:26:28
Well the root element you're treating like an array, but it's an NSDictionary.
Try logging out the value you get for the "menus" variable. It should help shed some light on what the structure looks like after it is parsed.
originally written by Marcioluizdesign on 05/11/2012 17:48:59
Another question, how to fetch the data and show it on a UIViewController instead of a UITableViewController?
originally written by Eric Baker on 05/25/2012 23:17:35
When you create the 'Run Mogenerator' build phase script, you can drag the build phase to be above 'Compile Sources'. That way the entities can be regenerated before the first compile, saving you from have to compile a second time to get the updates.
originally written by subdigital on 05/25/2012 23:20:14
Good call, thanks for pointing that out :)
originally written by Hernandoz on 10/25/2012 14:45:06
Nice tutorial, would be nice if you can MapKit tap on a cell and show the brewery location on the map.
originally written by jamra on 02/15/2013 04:16:21
One thing that you passed over here was how to handle the one to many relationship of a Beer to a Brewery. So far, you download the name of the Brewery, but not the Beer itself. It seems odd that we would create the to-many relationship and not use it. Am I missing something?
originally written by subdigital on 02/15/2013 18:40:50
What we did was map the array to all of the breweries for a beer, but our property simply grabbed the first one's name and returned it. We created the to-many relationship to map to the response format. We might be able instruct RestKit to flatten this for us, but I didn't see an easy way to do this.
Does this answer your question?
originally written by jamra on 02/15/2013 19:36:52
So we created the relationship in order to parse the JSON response. I think I understand. When fiddling with the parseBeers method, it explains why I am able to get an (NSSet *) of Beers for each Brewery using the mutableSetValueForKey method.
I was trying to implement a detail page where you can see each beer for a given brewery, but that is probably not within the scope of this video.
Would you recommend looping through each beer to insert them or is there a way to insert the entire set?
Thanks.
originally written by subdigital on 02/16/2013 14:38:04
Sorry for the confusion. I responded to your comment from my email, and I assumed you were talking about a more recent video (51-53) where I worked with a similar beers API using RestKit. These videos cover what you are talking about. Basically we don't download the beers until you tap on a brewery and then those beers are downloaded.
If your API was returning all of the data in one go, then you could loop over the beers as well and import those, however this would increase the import time by a large number. In that case I might suggest moving the context save operation to happen in batches of 500 records or something, to avoid a gigantic, time-consuming save at the very end. If you did this, then you could actually start filling up the UI with records as they are created by observing the contextDidSave notification and merging those changes into the main queue's managed object context.
Hope this helps.
originally written by Kris Utter on 04/04/2013 17:20:47
I don't know if anyone had this problem, but I had to put 'PATH=${PATH}:/usr/local/bin' at the top of the shell script other wise I got a failing error. Great tutorial by the way.
originally written by Matt on 04/09/2013 15:43:02
Performing a fetch for each record you get from your JSON feed is very expensive. Do you have a more efficient way of doing that? You could load all existing core data records into a dictionary keyed by your server ID and then just do a lookup. This would use more memory, but it would mean you only needed a single fetch.
originally written by subdigital on 04/09/2013 15:49:20
Yeah that's probably a better idea.
originally written by Roy Li on 04/25/2013 22:24:26
What if you have multiple users for one app that uses Core Data? Since all the paths these guys are gonna use are the same does that mean we need create multiple stores to distinguish one user from others?
originally written by subdigital on 04/25/2013 22:26:33
You can solve this a few ways. One is to create a persistent store for that given user. Another way would be to delete the store when the user logs out. Lastly, you could control it by maintaining a user model in your store, and everything would be related to the user that was logged in.
originally written by Jin on 05/20/2013 21:51:00
Nice Tutorial!!
However, mogenerator script is not working for me.
It keep gives me "/bin/sh failed with exit code 127 mogenerator"
Can you help me with this?
Thank you
originally written by David Cespedes on 05/24/2013 21:07:00
IF you don't insert the following line
self.serverId = [NSNumber numberWithInt:[[attributes objectForKeyOrNil:@"serverId"] intValue]];
in updateAttributes: method of Brewery.m, it won't recognize the already created breweries and will create them many times.
originally written by subdigital on 05/24/2013 22:53:11
You're absolutely right. The sample code has this fix, but I forgot to include this in the video.
originally written by icarod on 06/12/2013 11:10:01
$ sudo ln -s /usr/local/bin/mogenerator /usr/bin/
originally written by John Grange on 07/12/2013 21:02:28
Sorry maybe I'm wrong but in your screencast you mention that the original name of the model is the new version and the numbered is the old, and that's Xcode auto switches. In my experience and research that is backwards :
1) the numbered version is the new version.
2) you must select the new version in properties or the system will continue to use the existing version.
originally written by Matt on 09/28/2013 00:35:49
I'm getting the same error as Jin. It says 'Command /bin/sh failed with exit code 127.' Can you help please? Thanks.
originally written by subdigital on 09/30/2013 03:11:12
That typically fails if the script can't find the mogenerator binary. Make sure the path to your installation of mogenerator is correct.
originally written by Kennedy on 04/30/2014 12:30:10
Hi. How can I ensure that I do not get duplicated data. Every time I click the refresh button, my core data is populated with duplicate info. :(
originally written by subdigital on 04/30/2014 14:57:05
There are a few ways do this. The easiest and most inefficient is to try to fetch the entity before inserting. If one exists you just update the properties. In this case the records never change so we only insert if the object doesn’t exist. For this we can make the process more efficient by grabbing the ids of the records that exist locally up front, that way you can do a simple in memory lookup to see if you need to insert or not.
originally written by Kennedy on 04/30/2014 15:27:54
That's exactly what I would like to do but am still newbie to iOS dev.. Will be nice if you could organize a screencast on that.. Will really appreciate.. Am sure other subscribers will appreciate too. :)
originally written by subdigital on 04/30/2014 15:29:39
As luck would have it, I have an episode in the works that will sort of address this. It’s a couple weeks out though.
originally written by Kennedy on 05/01/2014 08:11:23
Thank you.. I am still newbie to ios but I have an app idea and thanks to NSScreencast lessons, am almost half way. :) My app relies on syncing the remote server with core data. Once I achieve that, then I will be the happiest ios newbie ever hehe.
originally written by Surge Pedroza on 05/19/2014 21:19:18
what is the serverId? i did not see serverid in the json data that you displayed in the beginning. (new to iOS)
originally written by onmyway133 on 05/24/2014 14:23:48
Sorry, but
1. I think you misunderstand setPropertiesToFetch, see http://stackoverflow.com/qu...
2. In your breweryWithServerId: you have to go to ask the database for every object, is that efficient ?
originally written by subdigital on 05/24/2014 16:01:03
Thanks, I didn't realize setPropertiesToFetch worked that way!
You're right, this solution isn't the most efficient. Loading all of the entities in memory up front is also probably not a good idea, as you might have thousands of them. A good balance would probably to divide up the work in batches of maybe 50 so you don't have so many SELECTs required.
originally written by subdigital on 05/24/2014 16:05:00
serverId is the "id" key in the JSON response. It will not be advisable to create a property named "id" because that is also a type.
originally written by Marios Mourelatos on 07/03/2014 14:09:34
Hey Great Video.
Where is the file breweries.json I am trying to run your sample code and I would like to test it with data.
originally written by subdigital on 07/03/2014 14:22:54
This is dynamically returned by a Rails server.
--
Ben Scheirman
originally written by Marios Mourelatos on 07/03/2014 14:24:03
Ok I know that but how can I call that service in order to test the application?
originally written by subdigital on 07/03/2014 14:39:54
You can use this one I put on heroku: http://beerapi.herokuapp.co...
--
Ben Scheirman
originally written by Marios Mourelatos on 07/03/2014 14:42:27
Great! Thanks
originally written by Ashish Porecha on 09/06/2014 10:28:04
This is insane!
Written on 01/24/2015 10:58:37
URL: https://nsscreencast.com/episodes/12-importing-into-core-data