Sunday, April 12, 2015

Two Steps Back

I’ve decided to break my blog down into four sections so that I cover the topics I intend to each week.  First will be “Progress” where I highlight the things I learned this week. Next will be “Reading” where I talk about what I am currently studying.  Following that will be “Quick Looks” where I talk about some technologies I briefly researched during the week.  Finally I will have “News” where I will talk about news that caught my eye this week.  So without further ado, here goes:


Progress
I didn’t make as much progress as I had hoped this week.  I did add Marcus Zarra’s CoreDataStack design to my project.  It was pretty straight forward.  Here is the initialization in Swift:
   init(dbName:String, syncToCloud:Bool, completion: ((Void) -> Void)? ) {  
     modelName = dbName  
     // Get the Model  
     let bundle = NSBundle.mainBundle()  
     let modelURL = bundle.URLForResource(dbName, withExtension: "momd")  
     let _model = NSManagedObjectModel(contentsOfURL: modelURL!)  
     assert(_model != nil, "Could not retrieve model at URL \(modelURL)")  
     model = _model!  
     // Build the persistent store coordinator  
     psc = NSPersistentStoreCoordinator(managedObjectModel: model)  
     // Set up the main MOC  
     mainQueueMOC = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)  
     // Create the private MOC, this is the parent context of the mainQueueMOC and it  
     // owns the persistent store.  
     privateMOC = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)  
     privateMOC.persistentStoreCoordinator = psc  
     // Make the main MOC a child of the private MOC  
     mainQueueMOC.parentContext = privateMOC  
     // Attach the basic life cycle listeners  
     attachInternalListeners()  
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {  
       // Get the proper options dictionary and storeURL based on the state  
       // of our sync flag.  
       var storeURL:NSURL?  
       var options:[NSObject: AnyObject]?  
       if (syncToCloud) {  
         storeURL = self.cloudStoreURL  
         if (self.rebuildFromCloudStore) {  
           options = self.cloudStoreOptionsWithRebuild  
         }  
         else {  
           options = self.cloudStoreOptions  
         }  
       }  
       else {  
         options = self.localStoreOptions  
         storeURL = self.localStoreURL  
       }  
       var error: NSError? = nil  
       self.store = self.psc.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL!, options: options!, error: &error)  
       assert(self.store != nil, "Could not add store URL \(storeURL)")  
       if let _completion = completion {  
         dispatch_async(dispatch_get_main_queue(),_completion)  
       }  
     }  
   }  


Where I got tripped up is in running the deduplication algorithm.  It worked but after migrating the store to iCloud then running the deduplication code and standing up a new NSFetchedResultsController I get the following error:


CoreData: Ubiquity:  Librarian returned a serious error for starting downloads Error Domain=BRCloudDocsErrorDomain Code=5 "The operation couldn’t be completed. (BRCloudDocsErrorDomain error 5 - No document at URL)"


Doing a few google searches I found that others are also seeing this error, but so far there is no answer.  I’m not sure this is really the error that is causing all the issues.  What I am seeing in my test app is if I include the deduplication code in the code path after the store is migrated (whether that be to the cloud or to local store) my app hangs right when I try to update the fetched results for my UITableView.  And yes, I am on the main queue when it happens so I know that is not the problem.


I’m also still running across folks giving up on CoreData and iCloud syncing so my decision to continue this investigation seems a little shakey.  I just wished I knew what they were moving to, since the problem of sync’d data seems like a required feature in today’s apps.  I do not want to stand up my own server to do this (although I am entirely capable of doing it) because I don’t want to incur the recurring cost for an app that might not be able to pay the server costs.


Reading
I am currently reading Spring in Action from Manning Publishing.  I’m about a third of the way through and it appears to be very thorough.  I need to work on a test app to apply what I am learning


News That Caught My Eye
Well the Apple Watch was opened for pre-order this past Friday.  I was up with the intent of buying one, but in the end I decided against it. At least for now.  I think I can get buy with the simulator as the supply chain gets filled and the first real users start reporting on it.


Quick Looks

I intended to look at React this past week, but ran out of cycles.  Maybe next week.

Sunday, April 5, 2015

A Light?

A few days ago I was ready to give up.  I was so depressed over trying to get Core Data sync working.  My personal feeling right now is LEARNING CORE DATA IS A CHORE!!!  I guess at this point I know enough to be dangerous.  Swapping in and out of cloud syncing almost seems to be impossible.  Not to mention adding Swift and MagicalRecord to the mix just made it even more challenging.  So continuing on:


After contemplating tossing all my devices in the trash and going fishing, I decided to try the simplest thing that could work.  I created a new test app and decided to just do the most minimalist Core Data (CD) app I could and add syncing in as I went.  I think at this point there may be a light at the end of this very narrow, long and twisty tunnel. I found this blog post which I thought was really interesting:

Martin Craft's Core Data Stack

I really like Marcus’ assessment of the state of information about getting a proper CD stack setup.  He absolutely nailed it, it is all over the place and there are A LOT of red herrings. I also found this link to a CD book that looked promising (but I have not read it yet):

Tim Roadly Core Data Book


But there appears to be a new version being worked on using Swift.  So if I do decide to buy it I’ll wait for that version.


One side issue I ran into was I had attached listeners to all the events that CD throws and in my listeners I was logging them using NSLog and trying to print out the notification using Swift’s inline string parameterization (I forget the technical term for this and am too lazy to look it up right now).  It worked fine on the simulator but when I moved to a real device, I got BAD_EXEC errors.  Switching to use “println” instead seemed to solve the problem.  So I have added that gem of information to my list of items to try when Swift seems to be misbehaving.


Another thing that helped was to mark my class that was handling the CD stack with “@objc” this seemed to calm down a lot of errors I was dealing with when listening for events coming from CD itself.


So for review here is my original list of requirements:


  1. Make an app agnostic class to manage a Core Data stack in Swift
  2. Be able to switch from a local store to a cloud store
  3. Be able to switch from a cloud store back to a local store
  4. Be able to remove the cloud store all together
  5. Be able to blow away local changes and rebuild from the cloud store
  6. A simple way to hook into CD notifications
  7. Support schema migrations


My status so far is this:


Item 1 - Done.  I take a model name in the initializer for the class and then build everything else from there.


Item 2 - Partially done.  I can now make the switch to iCloud from a local store.  What doesn’t work is after doing this the first time then switching back to a local store and then switching back to the cloud store. I end up with duplicate records.  That makes sense to me as when I switch to the local store the device loses knowledge that those items existed in the cloud.  When going back to the cloud the device dutifully merges it’s objects with those in the already existing cloud store so I end up with duplicates.  This is the step in Apple’s iCloud with Core Data store talking about deduplication of records.  


1:   func switchToCloudStore(completion: ((Void) -> Void)?) {  
2:      let cloudOptions = cloudStoreOptions  
3:      let storeURL = cloudStoreURL  
4:      if (storeURL == nil) {  
5:        println("Could not switch to store because store URL not available")  
6:        return  
7:      }  
8:      var error: NSError?  
9:       let newStore = psc.migratePersistentStore(store!, toURL: storeURL!, options: cloudOptions, withType: NSSQLiteStoreType, error: &error)  
10:       if let _newStore = newStore {  
11:        println("Cloud store URL is: \(psc.URLForPersistentStore(_newStore))")  
12:        self.store = _newStore  
13:        context.reset()  
14:        if let _completion = completion {  
15:          _completion()  
16:        }  
17:      }  
18:      else if let _error = error {  
19:        println("Error in migrating to cloud store: \(_error)")  
20:      }  
21:      else {  
22:        println("Returned newStore was nil when trying to migrate to cloud store")  
23:      }  
24:    }  

Item 3 - Partially done.  This has the same problem as item 2 where I move back to a local store (that already existed and had records in it).  I end up with the records from the cloud store as well as the set of records that were already existing in the local store.


1:    func switchToLocalStore(completion: ((Void) -> Void)?) {  
2:      var localOptions = localStoreOptions  
3:      localOptions.updateValue(true, forKey: NSPersistentStoreRemoveUbiquitousMetadataOption)  
4:      var error : NSErrorPointer = nil  
5:      if let _newStore = psc.migratePersistentStore(store!, toURL: localStoreURL, options: localOptions, withType: NSSQLiteStoreType, error: error) {  
6:        self.store = _newStore  
7:        context.reset()  
8:        if let _completion = completion {  
9:          _completion()  
10:        }  
11:      }  
12:    }  

Item 4 -  Partially works - This appears to work, but it appears I need to remove the store from all devices before it completely goes away.  This doesn’t totally surprise me, but it is still a little unnerving.  I can live with it though.


1:    func resetStore(completion: ((Void) -> Void)?) {  
2:      let storeURL = cloudStoreURL  
3:      if (storeURL == nil) {  
4:        println("Could not reset store because store URL not available")  
5:        return  
6:      }  
7:       let options = [NSPersistentStoreUbiquitousContentNameKey: "\(modelName)CloudStore"]  
8:       var error : NSErrorPointer = nil  
9:      let result = NSPersistentStoreCoordinator.removeUbiquitousContentAndPersistentStoreAtURL(storeURL!, options: options, error: error)  
10:      if (result) {  
11:        if let _completion = completion {  
12:          _completion()  
13:        }  
14:      }  
15:    }  

Item 5 - I haven’t started on this yet, but it seems straight forward.


Item 6 - Done.  I implemented two methods on my class, attachInternalListeners() and attachListenerForChangeEvents(AnyObject,Selector).  The first method is internal for the stack manager to do the right things when changes come in.  The second method is for external consumers of the stack manager so they can attach to change events and do the right thing when those happen.  It is intended for things like a table view controller to get updates when the underlying store changes due to the ubiquitous store changing.  I thought my view controller would automatically update because it has a NSFetchedResultsController but so far I haven’t got that to work.  More work to be done here.


Item 7 - I don’t think there is anything to do on this one.  Reading Apple’s documentation it sounds like syncing will be disabled on a device until it gets to the current version in iCloud.  Now, how all this works depending on the sync state of the device is anyone’s guess.  I suspect I will have to use items 4 or 5 to fix any issues
So right now, I feel like I have made progress.  I still need to deal with threading issues so my code is a “good citizen” of the CPU.  I’m planning on basically setting my contexts up like Marcus Zarra did in his article (this is mostly how I think MagicalRecord worked and how I tried to roll my own in the past)


The other issue I need to deal with is the deduplication of records as I transition to and from the cloud store.  This might be a little more harder than I thought.  My plan is to go back and look at how Apple suggests dealing with that.


Once I am done with all that I’ll probably end up posting the code somewhere so everybody can tell me what I did was wrong or possibly learn something from my ordeal.

Till next time, hoping for more progress.

Sunday, March 29, 2015

Next Steps

After the last effort I tried the following things:

First, I tried to stand-up my own Core Data stack by trying to piece together the code from MagicalRecord’s setup method.  I was doing fine until I ran into the code that set a flag in MagicalRecord to indicate that iCloud was being used.  It was a private method.  I need to look to see where that flag is used, if it turns out it is used inside MagicalRecord, then I will need to stand-up my own stack from the ground up.  I’m wondering if I could do that and then set the right final objects on MagicalRecord and it would work.  

I next deleted the app from my device.  In the end I lost all my stored records.  But the app did come back and I was again able to use it (at the current model version number I was on).  I still need to try a sane migration.  

I found out auto-migration is the only thing supported for Core Data iCloud sync.  But I still had this issue where my local stores were not syncing.  I ran across an article that talked about a method called a NSPersistentStoreCoordinator method, removeUbiquitousContentAndPersistentStoreAtURL.  Which the documentation says will delete all ubiquitous content for all peers for the persistent store at a given URL and also deletes the local store file.  (http://www.objc.io/issue-10/icloud-core-data.html)

So I set this up and on my first device as follows and ran it:

   class func resetCloudStore(completion: ((Void) -> Void)?) {
       let containerId = getCloudContainerId()

       let cloudURL = NSPersistentStore.MR_cloudURLForUbiqutiousContainer(containerId)
       var error: NSError? = nil
       let contentNameKey = getUbiquitousContentNameKey()
       let options = NSDictionary(objectsAndKeys: contentNameKey, NSPersistentStoreUbiquitousContentNameKey)
       let storeURL = NSPersistentStore.MR_urlForStoreName(MagicalRecord.defaultStoreName())
       MagicalRecord.cleanUp()

       let result = NSPersistentStoreCoordinator.removeUbiquitousContentAndPersistentStoreAtURL(storeURL, options: options, error: &error)
       NSLog("Finished deleting ubiquitous store with result \(result)")

   }

To make this work I created two helper methods:

getCloudContainerId() - returns a String of this form "iCloud.\(bundleIdentifier)"
getUbiquitousContentNameKey() - returns the same String we used when setting up MagicalRecord

I also added a completion block which I am not using right now but intend to later.

The result was the local store went away, so I lost all my local data.  I then went to my second device and did the same.  What happened next was unexpected.  Within a few seconds the first device got all of the data from the second device.  Syncing was now working again.  That isn’t what I expected.  I had expected that I would have had to enter my data all over again.  It seems somewhere the data was stored, got sync’d to the cloud account and then sync’d to all the attached devices.  

I’m now at a point where I want to be able to turn on and off iCloud syncing.  Actually, I only want to be able to turn it on (never to turn it off again).  Reading more online I am still trying to figure out how this works.  There could be a book written just on Core Data sync.  There probably should be one written.  I’d buy it if it was any good.  It would have to only cover the the new API though.  I feel like that is what the Ensembles guys are doing, just wish the book was more than 60% complete (as of March 28, 2015).  That would probably swing my decision to use their package.

At any rate, back to the issue at hand.  How do you do a one way transition to cloud syncing?  Here is what I think I know so far.  When the Core Data stack is stood up (I’m using MagicalRecord but I don’t think that really matters much here) there is a local “backing” store and a cloud store (the ubiquitous store).  Any time I save a NSManagedObject it goes to the local “backing” store and eventually is sync’d to the cloud store.  

When I do the same setup but only go to the local store (i.e. don’t add the icloud options) I get an empty local store.  My hunch was that I was getting two different stores for the local store depending on whether I had sync enabled or not.  After doing a good bit of debugging I confirmed that was the case as the URL’s for the local store and local “backing” store didn’t match between sync versus no-sync modes.  

In the same article I referenced above there is a section on how to turn iCloud sync on and off.  I have started down that road.  So far it’s not working.  It’s kind of interesting, for a long time I could not get Core Data iCloud sync-ing to work, now I can’t get it to stop!!  

Monday, March 23, 2015

Onward and Upward

Well when I last left off I was trying to verify step 3 of Apple’s iCloud Programming Guide For Core Data.  I failed miserably.  I am coming to the realization that the document is outdated.  When I removed the app from all my devices and the simulator and waited an hour, and enabled airplane mode the log still said Using Local store 0 and my data was still there.  I have no idea how this is supposed to work or why it isn’t working.

I decided to press onward and maybe something will make sense.  One change I did make is now instead of listening to the Core Data messages for didChange and willChange I switched to use MagicalRecord’s (kMagicalRecordPSCDidCompleteiCloudSetupNotification
and kMagicalRecordDidMergeChangesFromiCloudNotification)

Aggregations:
After getting the top level object to save I turned my attention to how would I manage a child object in an aggregation.  I used a tutorial I got from Ray Wenderlich’s site (http://www.raywenderlich.com).  The general steps are:
  • clone the collection from the parent object into a mutable collection
  • change the collection as desired
  • Set the collection back on the parent object
  • store the parent object

They also alluded to the fact open source projects tend to provide helper methods for this.  I couldn’t find anything looking through the MagicalRecord source so I rolled my own.  

I ran into a problem where during the third step I was having an inconsistent object failure.  It turned out this was how I was loading the parent object to begin with.  I was loading it on a separate thread and then returning it to the main thread.  The end result of all this was the MOC was not set on the parent object and trying to make a change to it later resulted in this error.  This seems like a design flaw in my code.  I need to rethink this.

What about Parse?

I was playing an iOS game last night and they had me sign-up.  I had two choices, enter my email or sign-in via facebook.  It got me to thinking about my experience with Parse.  I might could create my own login/signup page where all I asked for was the user’s email address.  Would that be enough to simulate the iCloud Core Data syncing without having them have to create a full fledged account(and remember their password)?  I need to think more on this one.

I ran across a project called “Sugar Record”  It looks promising, but I’m not willing to bite that one off until it matures more.

Retrieving NSDate from NSManagedObject

I found that in my NSManagedObject (generated by XCode) my date objects were declared as:

@NSManaged var dateEntered: NSDate

This seemed to trip Swift up when I tried to reference the dateEntered attribute (particularly if it was nil).  I ended up having to protect myself from this by using this code:

       if let _dateEntered = object.dateEntered as NSDate? {
           dateEnteredLabel.text = "\(_dateEntered)"
       }

Notice the explicit downcast to an optional NSDate. Kind of strange, but otherwise the compiler complained about the attribute not being able to be nil when clearly it can be.  I wonder if I could manually declare the NSDate attribute on the object as optional?

Here We Go Again

So I was thinking about my progress and I thought that I should try a migration just to make sure I was comfortable with how that would work.  Unfortunately, I started down that path before I knew it.  In making changes, I accidentally changed some attributes of my model without creating a new version.  That caused me to get a “Can’t find model for source store” when testing on my device.  After some investigation I realized that when MagicalRecord sets up the store it sets it up to be auto migrating.  This normally would be fine had I not messed the model up by making a change to it without first creating a new version.  My first attempt at fixing this was to create a new model version and set that as the default.  No luck.  I then poked around a bit and figured I would set MagicalRecord.shouldDeleteStoreOnModelMismatch to true, but that didn’t fix it either, so I was left with what do I do?

I looked around for a way to do a manual migration with MagicalRecord.  I even found a StackOverflow reference back in 2013 to an experimental method to setup the stack so that you could provide a MappingModel. But when I checked the latest code that didn’t seem to have made it in the latest release.  Sooo, I am left with thinking that I need to stand the stack up manually.  I’m not looking forward to that.

Yes I could probably delete the app from my device and reinstall, but what happens with the iCloud store? I still am unclear how the iCloud store would ever get migrated.  Oh well, more to learn I guess.

Sunday, March 15, 2015

Back To The Basics

I published my first app (Pain Logger) on the app store about two years ago.  For the app, I had some very simple data requirements. Essentially I wanted to store the user’s data in a database using Core Data and then sync that to the cloud so it would be available to other devices the user owned.  Seemed simple at the time, but in practice it wasn’t.  Like many other developers, I found that syncing wasn’t all it was cracked up to be.  

This post has a good history of what I and apparently everyone else was dealing with:


To get my app out I reluctantly decided to disable the syncing capability.  My goal was to add that feature back in, once I learned more.

Fast forward two years and this issue has continued to be on my radar.  I have read countless blogs and tried different solutions but none have quite given me what I was looking for.  

I had two events recently that have re-sparked my interest again in this. First, I had a customer contact me about why my app didn’t have that ability.  Second, I have a new app (written in Swift) that I have been working on for about three months now and it has the same basic database syncing requirements.

I first considered using Core Data on the client and CloudKit for the cloud support.  I looked into it enough to know that I didn’t like the idea of having to marshal my objects stored on the client device into name value pairs to be stored using CloudKit and then having to do the reverse when getting it back.  On the surface this looked like it would be a lot of code.

I next looked at using two third party packages, MagicalRecord and Ensembles.  I actually got them working.  The one thing that kept nagging at me was the amount of third party code I was using that abstracted my code away from the basic Core Data.  Not to mention Ensembles has a free for version 1.0 but "you must pay for version 2.0/source code/book/updates" pricing model.  That made me a little hesitant to say I really needed it.

About a month ago I started looking into using the Parse framework.  This seemed very promising and I was up very quickly with syncing to their cloud service.  However, my new app has a need to store data locally when not connected and I wanted to only enable the syncing capability if the user purchased that capability as an in-app purchase.

I started working with Parse’s anonymous user capability and local storage and it sort of worked, but it seemed weird to me in my use case that the user would pay for the in-app purchase to sync their device and then I would have to have them create an account (so it could be saved in Parse). 

I thought of various schemes of creating that user behind the scenes but I’m not convinced that would work. One great advantage I see in the Parse solution is you as a developer have great access to the user’s data stored in the cloud including the actual User login information, so if in the future there is a problem you might be able to fix it.  One downside of Parse was that it was free for the first tier but if the app usage started to pick up you could be forced to pay a monthly fee to keep up with the increased traffic.  I don’t think that is necessarily a deal killer just something I wasn’t sure about.  

One thing that had always nagged at me was in a session at WWDC last year one of the speakers alluded to how bad Core Data syncing was when it was first implemented (that was the time I was trying to get my first app out).  The speaker assured the audience that a lot of work had gone into fixing those issues.  

Sooo, long story short, I decided to relook at just using plain Core Data syncing to see if it really has been fixed.  However, I still want to use MagicalRecord as it seems to be a good compromise between raw Core Data and abstracting all of it away.  So I have embarked down this path.  Here is what I have done so far:

Step 1: Adding an iCloud Persistent Store to Core Data

I setup my new project to use Cocoapods and pulled in the MagicalRecord library and wired up the BridgingHeader as I am doing all my new projects in Swift to force me to learn the language.

I created my data model. One thing of note, if you let XCode build the NSManagedObject subclasses of your data model and you check the box “Use scalar properties for primitive data types” your Date attributes will be declared as NSTimeIntervals (which wasn’t what I wanted as I wanted dates to be nullable even though I had declared the attribute to be Optional)  Would be nice if you could do this on an individual attribute level.

Next was to begin setting up the Core Data stack using the documentation for MagicalRecord(MR) and comparing with the iCloud Core Data Programming Guide from Apple.  My first hurdle was what MR setup method should I use and how the parameters map to Apple’s setup instructions.  

I figured I needed to use the most configurable version of the MagicalRecord.setupCoreDataStackWithiCloudContainer method.

Unfortunately this method is not documented so I needed to figure out what each of the parameters are and how they map to the underlying Core Data implementation. I have come up with the following definitions for each:

  • containerID - This eventually gets mapped to bucketName in the MagicalRecord code. For iCloud support it must begin with “iCloud.” and I just appended my bundle identifier to that. It is used to create the URL for the ubiquity container.  In Apple’s documentation this is used to create the storeURL. MagicalRecord will create what it calls the cloudURL with this and then attach that to the NSPersistentStoreUbiquitousContentURLKey in the options dictionary.
  • contentNameKey - This is the name of the persistent store in the ubiquity container. If you use a name with periods you will get an error.  After googling this a bit and trying things out I found that if I just used {my app name}_DataStore that would work fine.  This value is used for the value to the NSPersistentStoreUbiquitousContentNameKey in Apple’s documentation.
  • localStoreName - This is the name of the database as stored on the user’s device. MagicalRecord will use this to create NSPersistentStore for the local database.
  • pathSubcomponent - This can be nil.  I presume this is used in cases where you might want to store different stores under the same top-level ubiquity container. Since my app was one database I didn’t need it.
  • completion - This is a completion block which is called after the default persistent store has been set.  Note, this appears to be called before the iCloud container is setup.

After setting all this up I ran my app and as is mentioned in Apple’s documentation (the first Checkpoint) I saw in the log the two log messages, first using the local store and then not using the local store.

Some other notes to this point.  
  • When setting up my entitlement it was important to let XCode create one for my app. Essentially what I did was turn on the iCloud capability ensure Key-value Storage and iCloud Documents were checked and choose to Use default container and ensured I had my app’s iCloud container (remember it must start with iCloud.) listed and checked in the list.
  • When testing this on the iOS Simulator I found I had to be logged into a valid iCloud account.  Yeah I know, that seems obvious, but you try a lot of things when debugging.

After all of this here is the code I ended up with for step one.

       var bundleIdentifier:String = ""
       if let infoDictionary:NSDictionary = NSBundle.mainBundle().infoDictionary {
           bundleIdentifier = infoDictionary.objectForKey(kCFBundleIdentifierKey) as String
       }
       let containerId = "iCloud.\(bundleIdentifier)"
       let contentNameKey = "GoalTrak_DataStore"
       MagicalRecord.setupCoreDataStackWithiCloudContainer(
           containerId,
           contentNameKey: contentNameKey,
           localStoreNamed: STORE_NAME,
           cloudStorePathComponent: nil,
           completion: {_ in
               NSLog("Finished setting up CoreData stack")
           })

Two notes about the code.  I chose to build the containerId by getting the bundle identifier from the mainBundle and appending “iCloud.” on the front of it.  I could of just hard coded it.
Also the STORE_NAME is just a class level constant for the name of the local database.

Step 1 complete!!

Step 2: Reacting to iCloud Events

This step just seemed to be adding a listener for when the NSPersistentStoreCoordinatorStoresDidChangeNotification was fired.  I added this line above the code I did in step one since the Apple documentation implied this should be done early.  

NSNotificationCenter.defaultCenter().addObserver(self, selector: "persistentStoreDidChange:", name: NSPersistentStoreCoordinatorStoresDidChangeNotification, object: nil)

Note: I did not listen to a specific NSPersistentStore as I wanted MagicalRecord to do as much of the heavy lifting as it could so at this point in the code I did not have a NSPersistentStore to listen to.

In the selector code I just printed out the notification’s userInfo:

   func persistentStoreDidChange(notification:NSNotification) {
       NSLog("Persistent store did change")
       if let _info: [NSObject:AnyObject] = notification.userInfo {
           for key in _info.keys {
               NSLog("   Key: \(key) Value: \(_info[key])")
           }
       }
   }

Step 2 complete!!

Step 3: iCloud Performs a One-Time Setup
At this point I realized that the Apple’s documentation is for a basic Core Data/iCloud setup and as such assumes you have direct access to the PersistentStoreCoordinator and uses the basic notifications.  MagicalRecord abstracts a good bit of that away and rightly so as there are now more events that are more specific to the Core Data stack that MagicalRecord has setup.  So I decided to refactor a bit and begin listening to some other more MagicalRecord specific events.  Also in this step I had to setup my first saving of a record.  This is accomplished with a simple algorithm of getting the ManagedObjectContext (MOC) for the object that needs to be saved and calling it’s MR_saveWithOptions method, passing in a completion block.

I know this is vague, but it is beginning to get app specific.  My goal here is to document the events that MagicalRecord will send as an object gets saved.

One thing to get MagicalRecord to play nicely with Swift is you have to tell MagicalRecord what the entity name is, otherwise you will see errors when saving, like “entityForName: could not locate an entity named ‘{project name}.{class name}’ To fix this I had to add a class method to each NSManagedObject instance that looks like this (assuming your class name was Foobar)

   class func MR_entityName() -> String {
       return "Foobar"
   }

You have to do this for each subclass of NSManagedObject that you have.  Additionally you have to go into your Model and set each of the Entities class to a fully qualified name.  So for instance using the example above and assuming your project was named MyProject you would enter MyProject.Foobar into the class attribute for the Foobar entity.

At this point I can create an object, and show a list of them.  One thing that isn’t working is when the app first stands up, my initial list of objects is not shown in my UITableViewController.  I think the problem here is the Core Data stack isn’t fully stood up before the viewDidLoad method in my initial view controller is called.  For now I just added a refresh button.  But I will add a notification this week and have my initial view controller listen and react to that.

That’s where I have stopped for now.  My next steps are to load the app on two devices and follow the checkpoint steps in Apple’s documentation.  I’m not convinced that I won’t need the Ensembles framework or I might even end up back using Parse.  We’ll see as I continue traveling down this road.  I think my main goal is to learn how this works, and have some type of service layer that I can apply to other apps as I build them.  We’ll see how that goes.

Monday, March 9, 2015

Blog Reboot

It's been a long time since I posted to this blog. I've decided that it is time to reboot this blog and share my experiences (no matter how mundane they may be). So what do I intend to talk about? My plans are to start or restart this blog as more of a journal about my professional journey as a programer. I intend to start first by just discussing the things I am working on right now particularly the highlights and low lights. I hope to post once a week. We'll see where this goes.

So first, who am I? I am a developer working for a large corporation in Raleigh NC. I have been a developer for 26 years and after a fairly significant bit of time in our nation's military I settled down to my current day job (that of programmer) about 16 years ago. I have worked on a bunch of different projects, at startups and now for the past ten years at my current employer (which is definitely not a startup). Up until the last year I primarily used Java, concentrating on the front end user interfaces in AWT and SWT (for you Eclipse gurus). About a year ago my company made a big push to switch from thick client applications to thin HTML5 based applications. I followed along and so for the past year I have been concentrating mostly on HTML5 clients and their integration with Java back ends.

Over my career I have used tons of different technologies. I started with C, quickly switched to C++ and then picked up Java. My "after work, work time" is spent on other areas of the development world I am interested in. Particularly mobile development on iOS. I have also dabbled in Unity, and Ruby. To date, I have released three apps to the various app stores. None very successful. My first was a simple Android game. When I found the tooling at the time to be fairly primitive and saw that iOS seemed to be a more lucrative endeavor I switched to iPhone/iPad development. That was about two years ago and since then I have released two iOS apps to the app store. One being a "light" version of the other.

One thing I struggled with early on was sharing the code base between these two apps. I feel with the module support now added to XCode, that problem may have been mitigated, but at this point I haven't had time to explore it much. I also have continued to develop my skills as a front-end web developer. Several years ago I was disgruntled with the state of J2EE applications and all the boiler plate junk you had to put together just to get a simple web site running with a backend including persistence. So I went in search of a simpler solution. I ended up deciding on Ruby on Rails. That has been a personally rewarding endeavor. As a result I have developed a few Ruby on Rails applications with dedicated front ends.

So where am I at today? This is what I intend to be the major thrust of this blog. I don't intend to talk much about my day job. My first iOS app required persistence on the device and I had hoped to sync that to the user iCloud account. This was when Core Data sync had just been released. It was a disaster. I found, like many other developers I have come to learn since, that the Core Data sync worked until it had conflicts and then the whole stack just came crashing down. You couldn't get updates and you had no idea what was going on. In reading other blogs I have learned this may have changed since then but I am still gun-shy over my experience.

So for a long time I had been looking at alternatives. Recently I have been trying out "Parse" and so far I like what I see. I have created a test app (written in Swift) and have successfully integrated Parse into it. Unfortunately, when I first implemented it I didn't include individual user support. So I tried to add that in and so far have fallen flat on my face. My idea is to create an anonymous user when the app starts up and allow the user to signup/login later in the use of the app. But it seems I get stuck when creating that anonymous user. Not sure why, the app just hangs and no information goes to the console. So that is where I am at today. Until next week.

Sunday, August 30, 2009

Flex Printing - OH MY!!!!

I've been working a budgeting application and I've gotten to the point where everything works the way I had envisioned. But as with any financial application, you want to be able to generate printouts of the data. My task was to print a table of data (shown in a DataGrid in the app) which could span multiple pages with some header and footer information at the beginning and end. Nothing extravagant. So I charged off into the realm of how to do this.

My first attempt was using Flex PrintJob. It's easy to use, can do multiple pages, and can print tables using MXML files as the source. During the development I learned that it's easy to print tables, but not so easy to print multi-page tables with headers and footers. I found examples on how to do this but didn't feel like trying them because of a more fundamental flaw (at least in my opinion) in PrintJob. That flaw is that there is no way of doing a print preview. So I used up a good bit of ink and paper before I decided that wasn't the way to go. I did find one solution to this which was to print to a PDF printer but I thought that would be strange for a user.

My next attempt was FlexReport. That had some promise, but I ditched that when I found out it had issues with HBox layouts, the documentation seemed to be almost non-existent and it seemed like the project wasn't being actively developed.

Next I tried AlivePDF. This was probably the best I had tried, from a Flex solution. It worked well. But one quirky thing I found was when using it for a Flex web app. You end up generating the pdf in the client flex app then sending it to your server so your server can stream the bytes back to the client and show it in a new window. Yes this supports the print preview I was wanting but there didn't seem to be easy support for datagrid. It looked to me like I would need to draw the tables out that I wanted to print.

Finally, even though AlivePDF was adequate for my needs, I didn't like the idea of having to draw the tables by hand (with lineto methods and such) and since I was going to have to hit the server anyway, why not use a server side solution. Since my server was Ruby based, and I had used a Ruby server based PDF renderer before (PDF::Writer). I chose that as my solution. The one thing I don't like about this solution is I have to duplicate the data manipulation code that is on the client used to provide the data to the tables on the server.

I guess my final comment is the Flex environment seems to be a mess when it comes to printing support. Being new to Flex I find this very odd and disappointing. I wonder if Flex 4 will help close this hole?