Updates from March, 2013 Toggle Comment Threads | Keyboard Shortcuts

  • Jay Versluis 6:48 pm on March 24, 2013 Permalink | Reply
    Tags:   

    Categories: iOS ( 222 )   

    How to create a Fetch Request in the Xcode Model Editor 

    You can create Fetch Requests in the Xcode model editor, including a Predicate. These are somewhat easier to setup. To create one, select your .xcdatamodeld file, then head over to Editor – Add Fetch Request. Give it a catchy name and a filter property, and much of the above code becomes obsolete.

    Here’s how you can retrieve one of those in code:

        // create a fetch request from template
        NSFetchRequest *fetchRequest = [self.managedObjectModel fetchRequestTemplateForName:@"MyFetch"];
        
        NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:nil];
        for (Event *event in fetchedObjects) {
            NSLog(@"%@", [event.timeStamp description]);
        }
    

    Note that to retrieve your Fetch Request Template you need a reference to your Managed Object Model as well as your context. The easiest way to grab hold of it in an iOS app is to pass it in on a property, just like we did with self.managedoObjectContext.





     
  • Jay Versluis 1:19 pm on March 24, 2013 Permalink | Reply  
    Categories: iOS ( 222 )   

    How to retrieve a Managed Object in Core Data Fetch Requests 

    Retrieving Managed Objects is somewhat more complex than creating them, mainly because you can filter what you’re getting back rather than retrieve everything that your store file has to offer.

    Let’s first illustrate a basic NSFetchRequest. For the following examples I’m using the iOS Master/Detail template which provides an Entity called Event with a property called timeStamp. I’ve created custom subclasses for this entity. Press the add button a few times so we have some data, then quit the application.

    Basic Fetch Request

    Here’s how we can retrieve all our values using a basic Fetch Request:

        // create a fetch request
        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
        NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:self.managedObjectContext];
        [fetchRequest setEntity:entity];
    
        // fetch all objects
        NSError *error = nil;
        NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
        if (fetchedObjects == nil) {
            NSLog(@"Houston, we have a problem: %@", error);
        }
    
        // display all objects
        for (Event *event in fetchedObjects) {
            NSLog(@"%@", [event.timeStamp description]);
        }

    The easiest way to get this code is by using a code snippet from the Xcode library (search for fetch, the first one is a “basic fetch”).

    Note that the results are unfiltered, which means they’re not necessarily in the order you would like them to be in. To remedy this, you can use a Sort Descriptor:

    Fetch Request with Sort Descriptors

        // create a fetch request
        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
        NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:self.managedObjectContext];
        [fetchRequest setEntity:entity];
    
        // define a sort descriptor
        NSSortDescriptor *descriptor = [[NSSortDescriptor alloc]initWithKey:@"timeStamp" ascending:YES];
        NSArray *scArray = [[NSArray alloc]initWithObjects:descriptor, nil];
    
        // give sort descriptor array to the fetch request
        fetchRequest.sortDescriptors = scArray;
    
        // fetch all objects
        NSError *error = nil;
        NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
        if (fetchedObjects == nil) {
            NSLog(@"Houston, we have a problem: %@", error);
        }
    
        // display all objects
        for (Event *event in fetchedObjects) {
            NSLog(@"%@", [event.timeStamp description]);
        }

    You can pass more than one Sort Descriptor, hence we need to pass an NSArray to the fetch request. A usage example would be “list all employers alphabetically, in order of which they’ve started working”. To do this, create another sort descriptor, then add both to the array.

    The easiest way to get this is to use the Xcode Code Snippets again, this time select the “fetch with sorting” and it will have all this code ready for you.

    Fetch Request using a Predicate

    Predicates are filters with which you can specify conditions, such as “is this date older than x”, “does the first name contain steve”, and so forth. I have written a more in-depth article on Predictates elsewhere on this site and won’t go into the details.

    Here’s how you create a Fetch Request with a Predicate, combined with a Sort Descriptor:

        // create a fetch request
        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
        NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:self.managedObjectContext];
        [fetchRequest setEntity:entity];
        
        // setup a predicate
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"timeStamp > %@", [NSDate date]];
        
        // give the predicate to the fetch request
        fetchRequest.predicate = predicate;
        
        // define a sort descriptor
        NSSortDescriptor *descriptor = [[NSSortDescriptor alloc]initWithKey:@"timeStamp" ascending:YES];
        NSArray *scArray = [[NSArray alloc]initWithObjects:descriptor, nil];
        
        // give sort descriptor array to the fetch request
        fetchRequest.sortDescriptors = scArray;
        
        // fetch all objects
        NSError *error = nil;
        NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
        if (fetchedObjects == nil) {
            NSLog(@"Houston, we have a problem: %@", error);
        }
        
        // display all objects
        for (Event *event in fetchedObjects) {
            NSLog(@"%@", [event.timeStamp description]);
        }

     

    If you don’t need the Sort Descriptor, just remove that code from the example. This snippet is also available from Xcode and is called “fetch with predicate”.

    For more information on Predicates, check out Apple’s Predicate Programming Guide.





     
  • Jay Versluis 12:43 pm on March 24, 2013 Permalink | Reply  
    Categories: iOS ( 222 )   

    How to create a Managed Object in Core Data 

    Assuming you’re using an app template that includes Core Data, you will have access to the Managed Object Context. In the simplest form, and without custom Entity classes setup, you can use key/value coding to set your object’s properties. In fact, the Master/Detail template does this.

    Here’s an example for an Entity named Event with two properties (myKey and anotherKey):

    // create a managed object
    NSManagedObject *myObject = [NSEntityDescription insertNewObjectForEntityForName:@"Event" inManagedObjectContext:self.managedObjectContext];
        
    // set its attributes
    [myObject setValue:@"This is my value" forKey:@"myKey"];
    [myObject setValue:@"My other value" forKey:@"anotherKey"];
    

    If you have created custom NSManagedObject subclasses for your Entity then you can create an object like this:

    // create a managed object from my custom class
    Event *myObject = (Event *)[NSEntityDescription insertNewObjectForEntityForName:@"Event" inManagedObjectContext:self.managedObjectContext];
        
    // set my object's properties
    myObject.myKey = @"This is my value";
    myObject.anotherKey = @"My other value";
    

    The KVC method will always work, regardless if you have custom classes or not. Custom Classes have the advantage that you can add custom behaviour (i.e. methods), and of course code completion in Xcode.

    Note that these snippets will create an object, but your values are only stored once you save the Managed Object Context:

    [self.managedObjectContext save:nil];
    




     
  • Jay Versluis 2:30 pm on March 21, 2013 Permalink | Reply  
    Categories: iOS ( 222 )   

    How to create a Save As dialogue with NSSavePanel 

    Likewise we can save our previously selected file using an NSSavePanel. It too is easy to use, just as the NSOpenPanel.

    For a save action to make sense we need to have some data to save, so in this example we will copy an existing file (self.myURL) to the new URL that the save panel returns. We’ll let the NSFileManager just create a copy with a new name that the user specifies using the save panel:

    - (IBAction)saveFile:(id)sender {
        
        // create the save panel
        NSSavePanel *panel = [NSSavePanel savePanel];
        
        // set a new file name
        [panel setNameFieldStringValue:@"NewFile.png"];
        
        // display the panel
        [panel beginWithCompletionHandler:^(NSInteger result) {
            
            if (result == NSFileHandlingPanelOKButton) {
                
                // create a file namaner and grab the save panel's returned URL
                NSFileManager *manager = [NSFileManager defaultManager];
                NSURL *saveURL = [panel URL];
                
                // then copy a previous file to the new location
                [manager copyItemAtURL:self.myURL toURL:saveURL error:nil];
            }
        }];
        
    }
    

    The only alien looking thing here is the use of a Block (like it is in the NSOpenPanel). This is the equivalent to an anonymous function in JavaScript, basically a block of code that runs upon completion. As it’s part of the method call, the closing ] is way at the bottom.

    Further Reading

    Apple’s NSSavePanel Class Reference:

    A Short Practical Guide to Blocks:





     
  • Jay Versluis 2:19 pm on March 21, 2013 Permalink | Reply  
    Categories: iOS ( 222 )   

    How to create an Open File dialogue with NSOpenPanel 

    NSOpenPanel is surprisingly easy to use: create the panel, call the openPanel method, and handle the returned URL object in a block.

    In this example we invoke the panel from a button in the main window, then display the returned URL in a textLabel:

    - (IBAction)loadFile:(id)sender {
        
        // create an open documet panel
        NSOpenPanel *panel = [NSOpenPanel openPanel];
        
        // display the panel
        [panel beginWithCompletionHandler:^(NSInteger result) {
            if (result == NSFileHandlingPanelOKButton) {
                
                // grab a reference to what has been selected
                NSURL *theDocument = [[panel URLs]objectAtIndex:0];
                
                // write our file name to a label
                NSString *theString = [NSString stringWithFormat:@"%@", theDocument];
                self.textLabel.stringValue = theString;
                
            }
        }];
        
    }
    

    Further Reading

    Apple’s NSOpenPanel Class reference:





     
  • Jay Versluis 8:00 am on March 20, 2013 Permalink | Reply  
    Categories: Screencast ( 87 ), WordPress ( 144 )   

    What to do if you’ve forgotten all credentials to your WordPress site 

    This podcast describes how to gain access to WordPress even without username, password or working email address.

    It’s happened to the best of us:

    • you forgot your Password
    • you forgot what User you are
    • even worse, you’ve forgotten which email you’ve used when you installed WordPress
    • worse still, your email no longer exists

    Fear not, for in this week’s Podcast I will talk you through all these mishaps, and show you how you can still gain access to your WordPress site.

    Enjoy!

     

     

     





     
  • Jay Versluis 2:10 am on March 20, 2013 Permalink | Reply
    Tags: , ,   

    Categories: iOS ( 222 )   

    How to pass data from the App Delegate to your Top View Controller 

    If the App Delegate has something that your top view controller needs then you simply pass it the required object via a property set on the top view controller. This is easy when your top view controller is also the root view controller.

    However, when you embed your top view controller in a Navigation Controller, and perhaps that one is also embedded in a Tab Bar Controller, then this array isn’t quite so easy to figure out (and I must admit that I always forget how to do this when a new challenge arises).

    So here’s how this works. In this example, the thing that’s displayed is called MyViewController, which is embedded in a Navigation Controller. I’m passing it the App Delegate’s self.managedObjectContext which is defined as a property on MyViewController.

    // grab our own navigation controller
    UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
        
    // grab our table view controller
    MyViewController *myViewController = (MyViewController *)navigationController.topViewController;
        
    // pass in whatever data you need (such as this):
    myViewController.managedObjectContext = self.managedObjectContext;
    

    We call this in the applicationDidFinishLaunching method, just before the return statement.





     
  • Jay Versluis 10:38 am on March 18, 2013 Permalink | Reply  
    Categories: iOS ( 222 )   

    How to return the number of rows in a UITableView with Core Data 

    Likewise, here’s how we return the number of rows using a fetched results controller – as provided by the Master / Detail template:

    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections]objectAtIndex:section];
            
        return [sectionInfo numberOfObjects];
    }
    




     
  • Jay Versluis 10:36 am on March 18, 2013 Permalink | Reply  
    Categories: iOS ( 222 )   

    How to return the number of sections in a UITableView with Core Data 

    I can never remember how to do this. Here’s the method provided by the Master / Detail template when using Core Data:

    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
        return [[self.fetchedResultsController sections] count];
    }
    




     
  • Jay Versluis 7:11 pm on March 17, 2013 Permalink | Reply
    Tags:   

    Categories: iOS ( 222 )   

    How to convert a Persistent Store from XML to SQLite in Core Data 

    By default Mac Apps use XML as store type when saving in Core Data, even though it can use other formats – such as SQLite, which is the default on iOS. Here’s a way to quickly convert one into the other.

    Note that this is designed as a one-off operation to create a new store file which can be used in another application. Once run, comment the code out and either change your store file, or take the store file and use it in another app.

    Add this code to the AppDelegate.m file in the persistenStore method (just before the return statement):

    // convert this thing to SQL
    NSURL *sqlstore = [applicationFilesDirectory URLByAppendingPathComponent:@"NewStoreFile.sqldata"];
    NSPersistentStore *xmlstore = [coordinator persistentStoreForURL:url];
        
    [coordinator migratePersistentStore:xmlstore toURL:sqlstore options:nil withType:NSSQLiteStoreType error:nil];
    

    For more information on how to do this in context, check out Simon Allardice’s superb course Core Data for iOS and OS X on Lynda.com.





     
c
Compose new post
j
Next post/Next comment
k
Previous post/Previous comment
r
Reply
e
Edit
o
Show/Hide comments
t
Go to top
l
Go to login
h
Show/Hide help
shift + esc
Cancel