Just another OSX news aggregator…

Archive for 'How-to'

Thanks to the ability to have configurations in a Core Data Managed Object Model and being able to save data to multiple Persistent Stores, it is possible to have a Core Data Model that is constructed from not only an internal model, but from the models of all the plug-ins that are loaded into the application.

In this example we are going to build a basic application with the following requirements:

  • A plug-in framework
  • Plug-ins can extend the managed object model of the application
  • Removal of a plug-in should not corrupt the persistent store.

The Concept

Core Data allows a NSManagedObjectModel to be constructed from multiple ‘sub’ models. Therefore we can load up all of our plug-ins and ask them for their NSManagedObjectModel references. Using those plus the models included with the application we can build a composite model.

However this would still save into a single file which would then become fragile if a plug-in disappeared. Instead we will use Core Data Configurations. By declaring a configuration for each model, we can specify a different file on disk for each configuration and thereby be able to split the persistent store by model on disk. If a plug-in disappears, the configuration is not loaded and its corresponding persistent store is not loaded and therefore the integrity of the persistent store stays intact.

The Plug-in Framework

In this example we are not going to explore Plug-in design in too much depth. That subject has been covered elsewhere. Our plug-in for this design is going to use a framework to host the shared code and both the application and the bundles will link to it and import from it.

Our framework is going to consist of a header file that defines the protocol that the plug-ins must implement to be loaded. The header is as follows:

@protocol ZSPlugin <NSObject>
'
- (NSString*)name;
- (NSString*)modelConfigurationName;
- (NSManagedObjectModel*)managedObjectModel;
'
@end

The Example Plug-in

To test this we need to include at least one plug-in. That plug-in will consist of a principal class along with a data model. The plug-in does not need to stand up a Core Data stack because its model will be included in the primary application’s Core Data stack. Therefore we just need to implement the methods in the protocol.

-name

The name method in this example just returns a string.

- (NSString*)name;
{
  return @'Example Plugin v1.0';
}

-modelConfigurationName

Like the name method above, the -modelConfigurationName method only returns a string. In a more robust solution we would check in the plug-in manager to confirm that this name is unique and does not conflict with the configuration of the base application.

- (NSString*)modelConfigurationName;
{
  return @'ExamplePlugin';
}

-managedObjectModel

The final method that we declare in the protocol returns the NSManagedObjectModel for the plug-in. This method does a simple load from the plug-ins bundle.

- (NSManagedObjectModel*)managedObjectModel;
{
  if (managedObjectModel) return managedObjectModel;
'
  NSBundle *myBundle = [NSBundle bundleForClass:[self class]];
  NSArray *bundles = [NSArray arrayWithObject:myBundle];
  managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:bundles] retain];
  return managedObjectModel;
}

The one interesting part of this code is that we need to get a reference to the NSBundle for the plug-in from its principal class. This is because the call [NSBundle mainBundle] will return the application’s bundle instead.

The Plug-in Manager

The plug-in manager loads all of the available plug-ins on launch. In this example we do not allow dynamic plug-in loading.

#import <ZSPlugin/ZSPlugin.h>
'
@interface ZSPluginManager : NSObject
{
  NSArray *loadedPlugins;
}
'
@property (retain) NSArray *loadedPlugins;
'
+ (id)shared;
'
- (NSArray*)pluginModels;
- (NSArray*)modelConfigurations;
- (NSString*)applicationSupportFolder;
'
@end

-init

The plug-in manager is a singleton that initializes itself and loads all of the existing plug-ins upon first request.

- (id)init
{
  if (!(self = [super init])) return nil;
'
  //Find the plugins
  NSFileManager *fileManager = [NSFileManager defaultManager];
  NSArray *plugins = [fileManager directoryContentsAtPath:[self applicationSupportFolder]];
'
  if (![plugins count]) {
    NSLog(@'%@:%s No plugins found', [self class], _cmd);
    return self;
  }
'
  //Load all of the plugins
  NSMutableArray *loadArray = [NSMutableArray array];
  for (NSString *pluginPath in plugins) {
    if (![pluginPath hasSuffix:@'.bundle']) continue;
    NSBundle *pluginBundle = [NSBundle bundleWithPath:pluginPath];
    Class principalClass = [pluginBundle principalClass];
    if (![principalClass conformsToProtocol:@protocol(ZSPlugin)]) {
      NSLog(@'Invalid plug-in, does not conform to the ZSPlugin Protocol: %@', pluginPath);
      continue;
    }
    id&lt;ZSPlugin&gt; plugin = [[principalClass alloc] init];
    [loadArray addObject:plugin];
    NSLog(@'Plug-in Loaded: %@', [plugin name]);
    [plugin release], plugin = nil;
  }
  [self setLoadedPlugins:loadArray];
'
  return self;
}

In the -init method we first find all of the files in the Application Support directory. If there are no files then we quickly return self. If there are files then we start looping over them. On each iteration we check to see if the file is a plug-in and if it is not we skip to the next loop. If it is then we look-up its principal class and confirm that it conforms to the ZSPlugin protocol. If it does not we warn the developer and skip to the next loop.

Once we pass all of the integrity checks we then call alloc and init on the plug-in and add it to the array of loaded plug-ins.

-pluginModels

To help the main application initialize we have a couple of helper methods in the plug-in manager. The first is a method that returns all of the plug-in models.

- (NSArray*)pluginModels;
{
  NSMutableArray *array = [NSMutableArray array];
  for (id&lt;ZSPlugin&gt; plugin in [self loadedPlugins]) {
    [array addObject:[plugin managedObjectModel]];
  }
  return array;
}

-modelConfigurations

The second helper method returns an NSArray of the configuration names used by the plug-ins. These names will be used both to load the configurations and to decide on the persistent store’s file name.

- (NSArray*)modelConfigurations;
{
  NSMutableArray *array = [NSMutableArray array];
  for (id&lt;ZSPlugin&gt; plugin in [self loadedPlugins]) {
    [array addObject:[plugin modelConfigurationName]];
  }
  return array;
}

The Primary Application

With our quick walkthrough of the plug-in structure complete we need to review the changes to the application itself. All of the changes are limited to the Core Data methods.

-managedObjectModel

The first change we need to make is how we load the NSManagedObjectModel. Normally we would just call [NSManagedObjectModel mergedModelFromBundles:nil] and be done. However we want to load not only the models within the application itself but also merge with all of the models in the plug-ins. Therefore a couple of extra steps are required.

- (NSManagedObjectModel*)managedObjectModel
{
  if (managedObjectModel) return managedObjectModel;
'
  NSMutableArray *models = [NSMutableArray array];
  [models addObject:[NSManagedObjectModel mergedModelFromBundles:nil]];
  [models addObjectsFromArray:[[ZSPluginManager shared] pluginModels]];
'
  managedObjectModel = [[NSManagedObjectModel modelByMergingModels:models] retain];
  return managedObjectModel;
}

In this method we start with the NSManagedObjectModel from the Application itself and add it to a NSMutableArray. We then request an array of all the models from the plug-ins via the ZSPluginManager and add those models to the NSMutableArray. Once we have all of the models together we call +modelByMergingModels: and merge all of the models into one super model. We retain that model and return it to the caller.

-persistentStoreCoordinator

The second and last change we need to make to the Core Data stack is the way that we handle the NSPersistentStoreCoordinator.

- (NSPersistentStoreCoordinator*)persistentStoreCoordinator
{
  if (persistentStoreCoordinator) return persistentStoreCoordinator;
'
  NSFileManager *fileManager;
  NSString *applicationSupportFolder = nil;
  NSURL *url = nil;
  NSError *error = nil;
  NSString *filePath = nil;
'
  fileManager = [NSFileManager defaultManager];
  applicationSupportFolder = [[ZSPluginManager shared] applicationSupportFolder];
  if (![fileManager fileExistsAtPath:applicationSupportFolder isDirectory:NULL] ) {
    if (![fileManager createDirectoryAtPath:applicationSupportFolder attributes:nil]) {
      NSLog(@'%@:%s Failed to create app support directory', [self class], _cmd);
      return nil;
    }
  }
'
  NSManagedObjectModel *mom = [self managedObjectModel];
  if (!mom) return nil;
  NSPersistentStoreCoordinator *psc = nil;
  psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
'
  NSMutableArray *configArray = [NSMutableArray array];
  [configArray addObject:@'Core'];
  [configArray addObjectsFromArray:[[ZSPluginManager shared] modelConfigurations]];
'
  for (NSString*configName in [[ZSPluginManager shared] loadedPlugins]) {
    filePath = [configName stringByAppendingPathExtension:@'sqlite'];
    filePath = [applicationSupportFolder stringByAppendingPathComponent:filePath];
    url = [NSURL fileURLWithPath:filePath];
    if (![psc addPersistentStoreWithType:NSSQLiteStoreType
                           configuration:configName
                                     URL:url
                                 options:nil
                                   error:&amp;error]) {
'
      [[NSApplication sharedApplication] presentError:error];
      [psc release], psc = nil;
      return nil;
    }
  }
'
  persistentStoreCoordinator = psc;
  return persistentStoreCoordinator;
}

The first half of the method is almost straight out of the template. However once we have the application support directory created and the raw NSPersistentStoreCoordinator initialized it is time to deviate.

The first then we do is construct a NSMutableArray and add our application model’s configuration name to it. In this example I called it ‘Core’. With the array initialized we then grab all of the configuration names from the plug-ins via the ZSPluginManager and add them to the array.

With the array fully populated it is time to iterate over it. Within each iteration we do the following:

  1. We construct a file path for the configuration using the application support folder and the configuration name. We add a ‘sqlite’ extension to it although in a production system you should use an application specific extension.

  2. We then add the newly constructed file path to the NSPersistentStoreCoordinator re-using the configuration name and checking for failure. If we fail we present an error and abort.

Conclusion

That is all there is to it! Core Data takes over from there and automatically saves the correct objects into the correct store files for us. If a plug-in goes away we don’t load its model and we don’t reference it’s store so integrity remains.

In the included example application I have also built a UI which lists the entities that are available in the model. If you run it straight from the zip file you will see the following UI:

However, if after building the application, you copy the example plugin into your ~/Library/Application Support/CDPlugins directory and run the application again you will see the following.

Which shows that not only is the plug-in loaded but that it’s entity (Widget) has been included in the Core Data stack. This can even be extended to create widgets and then remove the plug-in to confirm that integrity is maintained.

xcode.png
Layer Rotate Demo Project

(Via Cocoa Is My Girlfriend.) Original Link: Core Data and Plug-ins

Learn How to Build iPhone Apps from Stanford University [IPhone Apps]: “

If you’ve ever hand an idea for an iPhone application but you’ve never known how to begin creating it, Stanford will be offering how-to-build-iphone-apps computer science courses via free video podcasts through iTunes U. Later this week, you’ll be able to get a Stanford-level education without the stress of having to apply to the prestigious school and especially without having to pay tuition being a huge dbag. [Ed. note: Ed went to Cal.] [TechCrunch]





(Via Gizmodo.)

Apple Seeds Second iPhone 3.0 Beta to Developers: “
After only two weeks from its initial release, Apple has released a second beta version of their iPhone 3.0 operating system. The new seed is available only to registered iPhone developers. The iPhone 3.0 beta was first introduced earlier t…”

(Via MacRumors : Mac News and Rumors.)

Filed under: , , , ,

In our last iPhone Dev 101, a continuing series on iPhone development, we talked about resources that you can use while you are coding with Cocoa. In this dev post, I’m going to walk you through Xcode and creating your first project.

First we need to open Xcode, so once you have the SDK installed, you’ll need to open /Developer/Applications/ and look for Xcode.app. This is Apple’s IDE (Integrated Development Environment) that allows you to code, debug, test, and build all of your iPhone and Mac applications. When you open this application, nothing specially really happens, although you might see the welcome center — if you see this, you can choose to disable it at startup by using the check box at the bottom.

To create a new project, select File > New Project. In the resulting window select iPhone OS Application > View-based Application, and click “Choose.” You will then need to specify a save name and location for the resulting files that will combine to create your application. In the resulting Xcode window, you should note that most of the work is already done for you!

At this point you have a fully functional application. Try it out: click the “build and go” button at the top of the window and wait while the app is compiled and opens in the iPhone Simulator. The app definitely doesn’t do much, but still, it’s a running application you made without writing any code.

Continue reading to learn more about Xcode, and get a brief UI overview.

Continue reading iPhone Dev 101: Creating Xcode projects, brief Xcode UI overview

TUAWiPhone Dev 101: Creating Xcode projects, brief Xcode UI overview originally appeared on The Unofficial Apple Weblog (TUAW) on Tue, 31 Mar 2009 09:30:00 EST. Please see our terms for use of feeds.

Read | Permalink | Email this | Comments

(Via The Unofficial Apple Weblog (TUAW).) Original Link: iPhone Dev 101: Creating Xcode projects, brief Xcode UI overview

Filed under: , , , ,

It has been a while since the last iPhone Dev 101 post (and I must apologize for that — sometime life can get in the way of different things, and this was one of those times). In this Dev 101 post, I want to take you through a few of my favorite resources for Cocoa/iPhone development. Some of these resources are books, while others are sites, but all of the resources are valuable to up and coming developers (and experiences developers) alike.

Books
Some books are just invaluable and couldn’t be replaced with another. Aaron Hillegass’ Cocoa Programming for Mac is just that book. Currently in it’s 3rd edition, the book gives you much of the Cocoa programming information that you need to program for both the Mac and iPhone. There are only a few subtle differences in programming for these platforms, namely the use of the Cocoa Touch. If you ever have the chance, going to one of the Big Nerd Ranch Cocoa programming classes gives you the ability to learn Cocoa hands-on.

Another title that is useful to beginning iPhone developers is the Beginning iPhone Development book. This book has a useful approach to stepping into the world that is programming on iPhone. It talks about numerous topics including UI design, Quartz, and OpenGL. Also covered in the book are APIs like CoreLocation and interfacing with the camera.

If you already know Cocoa and a little about iPhone development, Erica Sadun’s iPhone Developer Cookbook is a great jumping off point to start development. She assumes, however, that you already understand Cocoa.

Continue reading to learn about more valuable books, websites, and resources for iPhone/Mac developers.

Continue reading iPhone Dev 101: Useful Cocoa Development Resources

TUAWiPhone Dev 101: Useful Cocoa Development Resources originally appeared on The Unofficial Apple Weblog (TUAW) on Wed, 25 Mar 2009 10:00:00 EST. Please see our terms for use of feeds.

Read | Permalink | Email this | Comments

(Via The Unofficial Apple Weblog (TUAW).) Original Link: iPhone Dev 101: Useful Cocoa Development Resources

I’ve spent a lot of time fighting with certificates, keys, and provisioning profiles in the time I’ve been working on iPhone apps for clients and myself. I finally figured out how to make it easy to manage multiple sets of certs/keys (i.e. one per client). Even if you are only working with a single set, though, it’s still helpful to keep iPhone stuff separate from the rest of your keychain. I’m going to approach this as if you are starting from scratch, but it’s easy enough to fix if you have already set up certs and keys and it should be pretty obvious how to go about it from these instructions.

First off, you need to know your tools. Keychain Access is where all of your certificates and keys (and passwords, and a variety of other things irrelevant to this discussion) live. Xcode, iPhone Configuration Utility, and iTunes all deal with the same store of provisioning profiles, but only the configuration utility is actually good at it. Download it from Apple right now and install it. When working within the iPhone Configuration Utility (hereafter referred to as iPCU) neither iTunes nor Xcode should be running since they will need to be restarted anyway to see any changes you make.

Before anything else, you need to download and install the WWDR intermediate certificate if you haven’t already. Get it here and open it in Keychain Access (hereafter referred to as KA). You’ll want to install it in either the login or System keychains (it doesn’t matter much). Now that you’re in KA, create a new keychain (File menu) and name it for the particular program portal you’re working with at the moment. I recommend saving it in the default location, ~/Library/Keychains, but if you save it somewhere else just make sure you remember where. You’ll need to set a password for it, and you can choose to be as secure or insecure as you like about it; the certs/keys would otherwise be in the login keychain, which is open by default as long as you are logged in, so anything is more secure than the alternative. Follow the program portal instructions for creating a Certificate Signing Request (CSR). Notice that creating the CSR created a private key in the login keychain in KA. Drag that private key to the new keychain you just created (the client keychain). Upload the CSR and go through the process of getting a developer certificate and a distribution certificate. (You’ll need both eventually, and you can use the same CSR for both; if you don’t, a new private key may be generated for the second CSR, and you’ll need to drag that from the login keychain to the client keychain as well.) Install the certificates in the client keychain rather than System or login.

When you are done with this process, you should have a private key (maybe two — see above), a developer certificate, and a distribution certificate in the client keychain. I like to set the keychain to lock after a period of inactivity so Xcode asks me for a password when it codesigns and I know it’s doing what I expect. Remember where you saved the keychain file? Make a backup copy of it now and put it somewhere safe (source control, offsite backup, optical media, whatever). If this is the only program portal you deal with, you’re done. If not, right-click (or ctrl-click) on the client keychain and choose Delete Keychain “[whatever]“.

Alert: Delete Keychain

IMPORTANT: Be sure to choose “Delete References” and not “Delete References & Files”!!! If you choose the wrong one, you will be glad you made that backup copy. KA will close the keychain, but you can open it again when you are working with that program portal again. You can then repeat the process for any other program portals that involve you.

Clearly, if someone else has created the distribution certificate you need to use you will need to get the cert and private key from that person instead. You can still put them in the client keychain once you have them, of course. If you have already been dealing with certs in your login keychain, you might have lots of private keys lying around and no good way to tell which key goes with which cert. I feel like there should be an easy way to tell, but I haven’t found it. Instead, create a new keychain and put all but one of the private keys into it, leaving one in the login keychain, then lock that temporary keychain (i.e. click its lock icon in KA). Build something in Xcode that requires the codesigning cert you are testing and see whether it asks for a keychain password. If not, the key you left in the login keychain goes with that cert; otherwise, switch keys and try again. (You can be cleverer about it by locking away half the keys so it’s a binary rather than linear search, plus you can test more than one cert at a time, but I leave that as an exercise for the reader.) Eventually you will be able to associate keys with certs and put them in their appropriately separate keychains.

Next up, we’ll look at provisioning profiles. There are three kinds of profiles: development, ad hoc, and app store. Both ad hoc and app store are considered distribution profiles, but they behave differently. In fact, ad hoc profile behave more like development profiles than app store profiles. (Note: there may be still yet another profile type for enterprise distribution, but I have no experience with that.) A development or ad hoc profile permits an app with a particular app ID (or ID prefix) to be installed on any of a set of physical devices when signed by one of a set of certificates. For ad hoc, it’s only one certificate: the distribution certificate. A device must have the provisioning profile installed on it to run the app, which Xcode does automatically for development profiles. I’ve had a lot of trouble with ad hoc profiles, and I’m still not confident I can get things working 100% of the time, but I have a better grasp on it than I used to. For the sake of my own sanity I am going to assume that you have figured out how to set up app IDs, devices, and provisioning profiles in the program portal.

There isn’t a whole lot more to it, really, except keeping track of which profiles belong to which portals if you are dealing with more than one. I recommend naming the profiles carefully when you create them or, failing that, keeping a text file listing what each profile identifier is for. Whenever you have a new profile you’ll want to use to build an app, I recommend installing it in iPCU rather than Xcode. It seems to work more dependably for me. Also, if it’s an ad hoc profile, I recommend installing it on the device using iPCU rather than iTunes if at all possible. If you use the multiple certs/keys keychains trick, I’d like to tell you that there is a similarly good way to manage provisioning profiles; I don’t know of one. The good thing, though, is that Xcode is smart enough to check the currently open keychains when presenting you with a list of provisioning profiles in a project’s (or target’s) build settings. If the cert for a particular profile is not available (even if the keychain is locked, its contents are available as long as KA has it listed), it will be grayed out with a message saying <matching certificate identity with private key not found in login keychain>. No matter how many provisioning profiles you have installed from other program portals, only the ones related to the certs and keys you have open will be available, which helps avoid silly mistakes.

I hope this is helpful to someone out there. I know I wish I’d known this stuff when I started developing for the iPhone. Enjoy!

(Via Ruby Discoveries and Idioms.) Original Link: Managing iPhone Development

Sync Your iPhone in Linux—Version 2.0 [Linux]: “

Apple’s 2.0 firmware update generally killed wireless syncing with Linux. Ubuntu users, hackers that they are, have posted a detailed walkthrough detailing a work-around or two that re-connect the two. Thanks Salvador!





(Via Lifehacker.)

How To Install a Second Hard Drive in the New Mac Mini [Mods]: “

iFixit has posted a fantastic, step-by-step tutorial tutorial explaining how to swap out the new Mac Mini’s optical drive for a second hard drive.

Being the compact Mac Mini (and involving 2.5-inch laptop drives), you knew it would be a bit more complicated than your standard, tower bay component swap. The process does require a few moments of soldering and careful notation of various internal wires/sensors, but the tutorial has big, beautiful pictures to hold your hand every step of the way.

Also, to make things a bit easier, they’re offering a 1TB, 5400RPM upgrade kit for $250 that includes all the necessary tools and components. You could maybe do it cheaper, but that’s how these guys pay the bills for these fancy tutorials. [iFixit]





(Via Gizmodo.)