Swift Core Data: ManagedObjectModel, PersistentStoreCoordinator and MainObjectContext

So I’m starting to dive into Core Data at work.  Core Data is more than just a database.  Among other things, it manages the database for you which is very handy, especially when a database update is needed.

Today, we made a Core Data manager that initializes Core Data for use in my app.  It initializes the Managed Object Model, the Persistent Store Coordinator and the Main Object Context.

-Managed Object Model

This is the structure of the database.  Generally, you’ll create this in your .xcdatamodel file.  It’s initialized by referring to that file:

        self.managedObjectModel =  NSManagedObjectModel(contentsOfURL: modelUrl)!

-Persistent Store Coordinator

This object coordinates the data with the managed object model to create the database:

       self.persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)

-Main Object Context

This object is the way the app communicates with the database.  So a swift way of creating the data manager class might look like this (including a save function- pretty important for a database):

 

import Foundation

import CoreData

final class CoreDataManager {

    

    private let managedObjectModel: NSManagedObjectModel

    private let persistentStoreCoordinator: NSPersistentStoreCoordinator

    let mainObjectContext: NSManagedObjectContext

    

    init() {

        //    //Get the Object Model

        let modelUrl: NSURL = NSBundle.mainBundle().URLForResource("YourXCDatamodelFileName", withExtension: "momd")!

        

        self.managedObjectModel =  NSManagedObjectModel(contentsOfURL: modelUrl)!

        let paths = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)

        let storeURL: NSURL = paths[0].URLByAppendingPathComponent("NotificationModel.sqlite")

        

        let options = [NSMigratePersistentStoresAutomaticallyOption: true,

                        NSInferMappingModelAutomaticallyOption: true]

        

        self.persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)

        do {

            try self.persistentStoreCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: options)

        } catch {

            fatalError("Error migrating store: \(error)")

        }

        

        self.mainObjectContext =  NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)

        mainObjectContext.persistentStoreCoordinator = persistentStoreCoordinator

    }

    

    func save() {

        do {

            try mainObjectContext.save()

        } catch {

            fatalError("Error while saving: \(error)")

        }

    }

}

ps. I take no credit for this code – it’s mostly pilfered and/or translated from Objective C

Changing font size and dynamically changing cell row height for Accessibilty

The iPhone is great for people with vision problems. As it turns out, most people start to lose the ability to focus in our forties – called presbyopia.  So, yeah maybe most people using mobile phones are younger than 40, maybe, but for those of us getting on in years it’s nice to adjust the text size in our iPhones.  This can be done by going to the general settings of the iPhone, going to accessibility and tapping on the “Large Text” option which leads to a slider.  However, unless developers code apps appropriately, this will cause some problems in an app.

First, it’s important to use “textStyles” for fonts, the “Headline” or “Subheadline,” either in the interface builder or in code.  This will allow the font to be changed when users change text size in their iPhones accessibility settings.  But then this can cause problems in sizing various elements. For example, say we have a table view cell that has a certain height that’s just fine for the default text we use.  But when the text is enlarged by a certain amount it will look awful and in some cases spill off the cell (particularly for custom cells).

Here’s what I did (with help of course) to get around this problem:

In the Cocoa frame work for TableViewControllers there’s a method called “heightForRowAtIndexPath” that you can use to change the height of a specific cell, or in my case, set a constant height for all cells.  Let’s say that we know we want the cell to be as high as the text plus 10 for margin’s sake.  That means, no matter how large the text gets there will always be a margin.  We can set up a dummy label using the text size the user has set, find out what size that is and set the row height as that size plus 10.  Here’s sample code:

    override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {

        let label = UILabel()
        label.font = UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline)
        label.text = "Placeholder Text"
        let size = label.sizeThatFits(CGSizeMake(view.width, CGFloat.max))
        return size.height + 10

}

It’s the “sizeThatFits” method on the label that does the magic.  We always use “CGFloat.max” as the height and the width is actually irrelevant.  This method returns the size of the label that fits for the current text.  An viola!  Now whenever text size is changed the cell heights will also change.

Basic iOS Custom Utilities Interface for adding border options

One of my assignments at the Flatiron School was  to program a blackjack game and make it work in views.  It went swimmingly except it looked like crap.  I used labels to make cards and the labels didn’t have borders.  I thought “surely Apple put border options in the utilities window, I mean their not savages!”  Alas, I was wrong.  But the option is definitely there programmatically.  I’ve found a number of ways online, but the simplest was to create a category of UIView in the project that creates an interface option so that all classes and subclasses of UIView now have a border option.  For the sake of the example I also added opacity and shadow radius. I’m not sure those additions are very practical except as an example. Essentially what we’re doing is unhiding options for the utilities uiinterface. So here’s how you do it:

As of writing this post we’re on Xcode 6.  So you create a new file>Objective C file>Name it what you want, for example “BorderOptions”, make sure it’s a subclass of “UIView”Screen Shot 2015-06-14 at 9.38.13 PM

Next add the following properties to the category header file:

[sourcecode language=”objc”]@property (nonatomic) IBInspectable UIColor *borderColor;
@property (nonatomic) IBInspectable NSInteger borderWidth;
@property (nonatomic) IBInspectable NSInteger cornerRadius;
@property (nonatomic) IBInspectable float opacity;
@property (nonatomic) IBInspectable CGFloat shadowRadius;[/sourcecode]

Then, in the .m implementation file add this:

[sourcecode language=”objc”]@dynamic borderColor,borderWidth,cornerRadius;
-(void)setBorderColor:(UIColor *)borderColor
{
[self.layer setBorderColor:borderColor.CGColor];
}

-(void)setBorderWidth:(NSInteger)borderWidth
{
[self.layer setBorderWidth:borderWidth];
}

-(void)setCornerRadius:(NSInteger)cornerRadius
{
[self.layer setCornerRadius:cornerRadius];
}

-(void)setOpacity:(float)opacity
{
[self.layer setOpacity:opacity];}

-(void) setShadowRadius:(CGFloat)shadowRadius
{
[self.layer setShadowRadius:shadowRadius];
}
[/sourcecode]

The methods here use our class’s super-class, UIView, methods.  So instead of defining new getters, we just have to tell Xcode to use the super-class’s getters.  We do this by inserting the line

[sourcecode language=”objc”]
@dynamic borderColor, borderWidth, cornerRadius[/sourcecode]

@dynamic tells the compiler just that – it tells Xcode that all these methods are methods in the super-class, so just use the super-classes getters.

Now in the attributes inspector you will have an option to set border color, radius and thickness:
Screen Shot 2015-06-14 at 9.46.02 PM

That’s it!

But what does it mean? Well that’s a little more complicated.  To see the full story is beyond the scope of this post and written more completely by Apple’s developers here:

Creating custom views that render in interface builder

*My simple answer was primarily taken from:

stackoverflow

 

 

5/14/15 Objective C

Coding progress:

As per usual when learning a new technology, at first I think I’m not getting it at all, and then all of a sudden it just works in my head.  Objective-C is transitioning to a better place.

Pointers?  I think, as far as I can understand, that it’s almost just like making all the variable types sort of like an array except that the notation is different and also the actual memory location is expressed.  Ok, so maybe I don’t quite get it yet.  I feel like I’m getting there.  In the meantime, I’m just adding *s to my variables.  It works.

Also, I’m getting used to the more verbose syntax of objective C and I approve, so far.  It makes sense to be clearer in the programming language and less reliant on comments.  We’ll see how I feel once I get to actually programming.

I’m studying a number of different things: Treehouse Objective C course, Stanford 2013 iOS Course (may be a little advanced for me but I’m just starting it), Udemy Intro to C programming, and Codeschool iOS.  Phew.  Not to mention pre-work for the flatiron bootcamp.