Archiving and Unarchiving objects in Objective-C

Apple, Objective-C, iPhone No Comments »

Woohoo … my first Objective-C related post!

Ok, so this is nothing new but I thought I’d log a couple of things that caught me out as a NOOB to the whole iPhone development malarky.

First off archiving your objects is a way of saving them to a property list file that sits on your device and can be unarchived the next time your app loads as a way to persist data locally on the device. Very handy it is too. Now there are better ways to manage data in Obj-C … CoreData for a start. This is a much more powerful way to persist data to a SQL lite database and allows you loads more freedom in what you can actually archive. There are limitations to the property list method you see. You can only archive NS objects and simple scalars so your class structure needs to compensate for this. The ‘plist’ objects you can archive are … NSArray, NSDictionary, NSString, NSNumber, NSDate and NSData along with their mutable subclasses. The scalars are int, float, double etc.

I don’t want to write a massive chapter on this and there’s loads of information online about the technical ins and outs of what’s happening behind the scenes. What I do want to do is share the classes I’ve used in a recent project and explain in basics what’s happening.

Firstly we’ll create the object we want to be archived. Any object that needs to be archived and is a subclass of NSObject must adopt the NSCoding protocol. Take a look at this object …

DataModel Object for archiving

  1. /* INTERFACE */
  2.  
  3. #define kfavesArray @"favesArray"
  4. #define kCurrentFave @"currentFave"
  5. #define kCurrentFaveIndex @"currentFaveIndexPath"
  6.  
  7. #import <Foundation/Foundation.h>
  8.  
  9. @class FaveVO;
  10.  
  11.  
  12. @interface DataModel : NSObject <NSCoding>
  13. {
  14.         NSMutableArray *favesArray;
  15.         FaveVO *currentFave;
  16.         int faveIndex;
  17. }
  18.  
  19. @property (nonatomic, retain) NSMutableArray *favesArray;
  20. @property (nonatomic, retain) FaveVO *currentFave;
  21. @property int faveIndex;
  22.  
  23. -(void)addNewFaveLocation:(FaveVO *)fave;
  24. -(void)createNewFaveVOFromFaveVO:(FaveVO *)fave;
  25. -(void)setFaveLocation:(int)index;
  26. -(void)removeFaveLocation;
  27.  
  28. @end
  29.  
  30. /* IMPLEMENTATION */
  31.  
  32. #import "DataModel.h"
  33. #import "FaveVO.h"
  34.  
  35. @implementation DataModel
  36.  
  37. @synthesize favesArray;
  38. @synthesize currentFave;
  39. @synthesize faveIndex;
  40.  
  41. //------------------------------------------------------
  42. -(id)init
  43. {
  44.         if(self = [super init])
  45.         {
  46.                 favesArray = [[NSMutableArray alloc] init];
  47.         }
  48.        
  49.         return self;
  50. }
  51. //--------------------------------------------------
  52. -(void)addNewFaveLocation:(FaveVO *)fave
  53. {
  54.         if(!favesArray) favesArray = [[NSMutableArray alloc] init];
  55.        
  56.         [favesArray insertObject:fave atIndex:0];
  57.         currentFave = [favesArray objectAtIndex:0];
  58.         faveIndex = 0;
  59.        
  60.         NSLog(@"DataModel currentFave: %@ faveIndex: %i", currentFave,faveIndex);
  61. }
  62. //--------------------------------------------------
  63. -(void)setFaveLocation:(int)index
  64. {
  65.         currentFave = [favesArray objectAtIndex:index];
  66.         faveIndex = index;
  67.        
  68.         NSLog(@"DataModel currentFave: %@ faveIndex: %i", currentFave,faveIndex);
  69. }
  70. //--------------------------------------------------
  71. -(void)removeFaveLocation
  72. {
  73.         currentFave = nil;
  74.        
  75.         NSLog(@"DataModel currentFave: %@ faveIndex: %i", currentFave,faveIndex);
  76. }
  77. //--------------------------------------------------
  78. -(void)createNewFaveVOFromFaveVO:(FaveVO *)fave
  79. {
  80.         double lat = fave.lat;
  81.         double lon = fave.lon;
  82.        
  83.         FaveVO *newFaveVO = [[FaveVO alloc] initWithLabel:[NSString stringWithString:fave.label]
  84.                                                                                 streetAddress:[NSString stringWithString:fave.streetAddress]
  85.                                                                                                  city:[NSString stringWithString:fave.city]
  86.                                                                                                 state:[NSString stringWithString:fave.state]
  87.                                                                                                   zip:[NSString stringWithString:fave.zip]
  88.                                                                                                   lat:lat
  89.                                                                                                   lon:lon];
  90.         [favesArray addObject:newFaveVO];
  91.         [newFaveVO release];
  92. }
  93. //--------------------------------------------------
  94. -(void)dealloc
  95. {
  96.         [favesArray release];
  97.         [currentFave release];
  98.         [super dealloc];
  99. }
  100. //--------------------------------------------------
  101.  
  102.  
  103. //--------------------------------------------------
  104. #pragma mark NSCoding
  105. - (void)encodeWithCoder:(NSCoder *)encoder
  106. {
  107.         [encoder encodeObject:favesArray forKey:kfavesArray];
  108.         [encoder encodeObject:currentFave forKey:kCurrentFave];
  109.         [encoder encodeInt:faveIndex forKey:kCurrentFaveIndex];
  110. }
  111. //--------------------------------------------------
  112. - (id)initWithCoder:(NSCoder *)decoder
  113. {
  114.         NSLog(@"DataModel initWithCoder: %@", decoder);
  115.        
  116.         if (self = [super init])
  117.         {
  118.                 self.favesArray = [decoder decodeObjectForKey:kfavesArray];
  119.                
  120.                 self.faveIndex = [decoder decodeIntForKey:kCurrentFaveIndex];
  121.                 self.currentFave = [favesArray objectAtIndex:faveIndex];
  122.         }
  123.         return self;
  124. }
  125.  
  126. @end

This object also references another object called FaveVO this is an object that I’m feeding into an array and also adopts the NSCoding protocol so you can see that you can archive quite a complicated object overall.

The important stuff is after the line that says “#pragma mark NSCoding”. These methods (using Actionscript terminology but I don’t care) handle what happens when the encoder and decoder go to work on your object.

- (void)encodeWithCoder:(NSCoder *)encoder
{
 [encoder encodeObject:favesArray forKey:kfavesArray];
 [encoder encodeObject:currentFave forKey:kCurrentFave];
 [encoder encodeInt:faveIndex forKey:kCurrentFaveIndex];
}

The encodeObject message takes each of my class variables and copies them into an NSData object using the keys which I defined in the interface. These are unique identifiers that I can use when I want to decode them later like so :

- (id)initWithCoder:(NSCoder *)decoder
{
 if (self = [super init])
 {
  self.favesArray = [decoder decodeObjectForKey:kfavesArray];
  self.faveIndex = [decoder decodeIntForKey:kCurrentFaveIndex];
  self.currentFave = [favesArray objectAtIndex:faveIndex];
 }
return self;
}

And that’s all you need to know about the Object you want to archive. Next comes the class that I’m using to do the archiving and unarchiving.

Here’s the class :

Archiving and Unarchiving DataModel Object

  1. /* INTERFACE */
  2.  
  3. #import <Foundation/Foundation.h>
  4.  
  5. #define kFilename       @"dataarchive.plist"
  6. #define kDataKey                @"Data"
  7.  
  8. @class DataModel;
  9. @interface DataManager : NSObject {
  10.  
  11.         DataModel *dataModel;
  12. }
  13.  
  14. @property (nonatomic, retain) DataModel *dataModel;
  15.  
  16. -(NSString *)dataFilePath;
  17. -(void)initDataModel;
  18. -(void)applicationWillTerminate:(NSNotification *)notification;
  19.  
  20. +(DataManager *)sharedDataManager;
  21.  
  22. @end
  23.  
  24. /* IMPLEMENTATION */
  25.  
  26. #import "DataManager.h"
  27. #import "SynthesizeSingleton.h"
  28. #import "DataModel.h"
  29. #import "FaveVO.h"
  30.  
  31. @implementation DataManager
  32.  
  33. SYNTHESIZE_SINGLETON_FOR_CLASS(DataManager);
  34.  
  35. @synthesize dataModel;
  36.  
  37. //-----------------------------------------------------------------------------------------------------
  38. - (NSString *)dataFilePath
  39. {
  40.         NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  41.         NSString *documentsDirectory = [paths objectAtIndex:0];
  42.         return [documentsDirectory stringByAppendingPathComponent:kFilename];
  43. }
  44. //-----------------------------------------------------------------------------------------------------
  45. -(void)initDataModel
  46. {
  47.         NSString *filePath = [self dataFilePath];
  48.        
  49.         if([[NSFileManager defaultManager] fileExistsAtPath:filePath])
  50.         {
  51.                 NSLog(@"FILE EXISTS");
  52.                
  53.                 NSData *data = [[NSMutableData alloc] initWithContentsOfFile:[self dataFilePath]];
  54.                 NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
  55.                
  56.                 DataModel *decodedDataModel = [unarchiver decodeObjectForKey:kDataKey];
  57.                
  58.                 dataModel = [[DataModel alloc] init];
  59.                
  60.                 NSEnumerator *enumerator;
  61.                 enumerator = [decodedDataModel.favesArray objectEnumerator];
  62.                
  63.                 FaveVO *decodedFaveVO;
  64.                
  65.                 while (decodedFaveVO = [enumerator nextObject])
  66.                 {
  67.                         [dataModel createNewFaveVOFromFaveVO:decodedFaveVO];
  68.                 }
  69.                
  70.                 int index = decodedDataModel.faveIndex;
  71.                 dataModel.faveIndex = index;
  72.                 dataModel.currentFave = [dataModel.favesArray objectAtIndex:index];
  73.                
  74.                 [unarchiver finishDecoding];
  75.                 [unarchiver release];
  76.                 [data release];
  77.         }
  78.         else
  79.         {
  80.                 NSLog(@"FILE DOES NOT EXIST");
  81.                
  82.                 dataModel = [[DataModel alloc] init];
  83.         }
  84.        
  85.         UIApplication *app = [UIApplication sharedApplication];
  86.         [[NSNotificationCenter defaultCenter] addObserver:self
  87.                                                                                          selector:@selector(applicationWillTerminate:)
  88.                                                                                                  name:UIApplicationWillTerminateNotification
  89.                                                                                            object:app];
  90.         
  91. }
  92. //-------------------------------------------------------------
  93. - (void)applicationWillTerminate:(NSNotification *)notification
  94. {
  95.         NSLog(@"Application will terminate");
  96.        
  97.         NSMutableData *data = [[NSMutableData alloc] init];
  98.         NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
  99.        
  100.         [archiver encodeObject:dataModel forKey:kDataKey];
  101.         [archiver finishEncoding];
  102.         [data writeToFile:[self dataFilePath] atomically:YES];
  103.        
  104.         [archiver release];
  105.         [data release];
  106. }
  107.  
  108.  
  109. //--------------------------------------------------
  110. -(void)dealloc
  111. {
  112.         [dataModel release];
  113.         [super dealloc];
  114. }
  115.  
  116.  
  117. @end

The initDataModel method looks for the property list and then uses the NSKeyedUnarchiver object to decode the objects. When the application terminates the objects are encoded using the NSKeyedArchiver object. The class listens for the ApplicationWillTerminate notification using the NSNotificationCenter object. This is similar to the Actionscript event model that uses listeners. The NSEnumerator object is used to step through an array of objects. The decoded FaveVO objects are then sent through to my DataModel class and passed to the createNewFaveVOFromFaveVO method which is where the objects are re-created as shiny new objects. Remember the NSKeyedUnarchiver object is released so you need to retain the objects you need … usually better to create new ones within the correct scope.

Adobe vs Apple? Sod the developers … what does the user want?

Apple, Flash, Web tools, iPhone, rant No Comments »

There’s been all kinds of heated debate and colorful invective surrounding the latest events in the Adobe vs Apple altercation. It’s hard for me to take sides because as a Flash developer for over ten years now and as a loyal Mac user for nearly 20 I’m finding that I do sympathise with both sides.

I find it distasteful that Apple should introduce section 3.3.1 merely days before the release of CS5 and Adobe’s new ‘compile Flash to iPhone app’ feature. It’s really quite underhand and will effect a lot of people’s livelihoods and damage business. Let’s not forget it’s not just Adobe that will be affected by this change. Unity3D and other 3rd party tools will not be able to release apps on the store. Some great apps like the ‘Star Wars Trench Run’ may need to be removed and as I understand it with my limited knowledge of these things some of the larger publishers like EA may also be affected as their games use 3rd party interpreters and tools that will be outlawed by Apple’s new rules.

On the other side though, Adobe should never have introduced this feature without the approval of Apple. They rushed this thing out and in the process have gambled with the livelihoods of hundreds of developers who have put their stake in iPhone app development with Flash.

Basically I think both parties have been very arrogant and have damaged a lot of reputations in the industry … mainly developers. We’ve got decent, honest people at each others throats when all they want to do is work together to make amazing, engaging content.

But the biggest victim in all this is the user. People buy iPhones and wonder why they can’t see the rich content they’ve come to expect. They struggle trying to view Flash content in the browser that hasn’t been built properly or they haven’t got the correct plug-in installed. What does the user want? Why is it all going wrong?

Fifteen years ago I was building CD-Rom titles in Director 3 which at the time was owned by Macromedia. We started using Flash 2 when it was released so we could include animated SWF content in our Director titles. We then started building Flash content for the web. At the time there was no such thing as ‘web standards’ … HTML was pretty basic and browsers were packed full of plug-in’s developed so you get the most out of your browsing experience. You had the ‘Real’ or ‘Quicktime’ plugin to watch video, ‘Shockwave’ allowed you to play amazing games online and ‘Flash’ exploded all over the web because it brought the browser to life and allowed us to build truly engaging rich content without loading new pages to update content.

In the present day we have a completely different type of internet. Web standards have evolved to the point that we now have a perfectly reasonable alternative to Flash integrated into the browser. HTML5 and WebGL allows us to build rich engaging content without a plug-in. In fact Flash is probably one of the few plugins people are still required to install into their browser to view a vast majority of content. And this is where Adobe have failed the user. Director died a death because people didn’t need to publish CD-Roms anymore and Flash should have evolved so the user didn’t need to use a plug-in in their browser.

Adobe should have adapted Flash so it output HTML5 and WebGL 3D content. The AIR runtime is fine on the desktop (although I will always choose a native Mac OS app) and will be just fine on the Android platform, hell they might even integrate it into their OS. But it’s in the browser they’ve failed and if they want to see Flash content on the iPhone they need to improve their tools (like Flash or Dreamweaver) so they produce standards compliant, rich, interactive content in the browser natively. This, after all, is what the user wants.

And Steve, stop being so evil. You’re forgetting what Apple was supposed to stand for. You should watch your 1984 Keynote speech every morning to remind yourself.

Some links on the subject …

http://www.smashingmagazine.com/2010/04/12/the-gradual-disappearance-of-flash-websites/

http://www.devwhy.com/blog/2010/4/12/its-all-about-the-framework.html?lastPage=true#comment8034519

http://mashable.com/2010/04/10/steve-jobs-adobe/

http://theflashblog.com/?p=1888

http://blog.codecomputerlove.com/2010/04/09/have-apple-crushed-cs5-flash-to-iphone-opportunity/

UPDATE: Apparently Flash to HTML5 was showcased during a ‘sneak peek’ session at MAX 2009 but has not made it into the new CS5 release. This is a real shame … Adobe could have made some real progress there.

UPDATE UPDATE: Apple have already started pulling apps. Scratch is an education tool built by MIT … it’s now not educating children in computer science.

Apple also banned this app for being too satirical!

iPhlash Application – nightmare scenario #1

Flash, humour, iPhone 15 Comments »

Ok, so you are now an iPhlash developer, creating cutting edge iPhone apps with the Flex Mobile Framework, AIR and Flash CS5. Things are looking pretty rosy and you can be sure the offers of work are going to start rolling in along with the cash. Who needs Objective C ay? You’re an Actionscript 3 developer … you can build amazing applications and now you can build them for the iPhone … you rock! Hey, what’s that … an email from your client asking if you could build a small marketing app for the iPhone … and they want to pay you a stupid amount of money! Result! Of course you can … you’re now an iPhlash developer!

Cool … the project is go and here’s a design from their Art Director …

iPhlasher

NNNNNNNNNNNNNNOOOOOOOOOOOOOO!!!!!!!!!!!!!!!!!!!!!

Now you know I’ve only got love for Flash but I hope you understand the point of this post. Scenario’s like this are gonna bite people in the arse unless they are careful about what they promise their clients. You need that Cocoa UIKit. You need Interface Builder. There’s so much in the iPhone SDK that you will need to build proper iPhone apps.

Let’s be realistic about this … we’re not talking about building apps for the browser or even for AIR. If you build an application for an OS then it is best-practice to adhere to the rules of that OS and use the common UI tools made available. If you own a mac then I think you would agree that when you download and install an app you want to feel comfortable using it. You want the reassurance that the application you are using integrates with the rest of the OS so you can quickly get your head around how it works. This is why the HIG exists and this is why Apple will deny any attempt to reproduce their UIKit components.

Unless your building a game with no OS UI requirements or your app is a bit of eye-candy then you’d be better off building it with XCode. Hopefully Adobe will expand on what they’ve started by creating tools that will let us export assets or views from Flash Builder to Cocoa Obj-C code. It would be great if we could export our project to a View and then integrate it into an iPhone app. There’s already a great tool built in AIR for exporting shapes from SWF to Obj-C that you can view here.

I know that the Flash community are an ingenious bunch and the majority of them aren’t stupid either so I hope that this is just the incentive they need to build some really useful tools that will enable us to build proper iPhone apps in the near future. Until then you’d be best not to promise your clients you’ll be porting over their web apps to the iPhone just yet … not until you’ve discussed the requirements IN DEPTH.

This post by Jeff LaMarche is a much more eloquent argument about why we should all step back and have a re-think about this. Especially how this may effect the relationship between Adobe and Apple. Hopefully Jeff will have some further comments to make on the subject and I invite him to do so here too.

From Jeff …

If I were a Flash developer, I wouldn’t cheer just yet. This looks like a risky proposition to me at present. Adobe and Apple are still acting in an antagonistic fashion toward each other. Adobe could very well have crossed the line here. There are both legal and technical options open to Apple to prevent Adobe from doing this if they choose to. Will they? I honestly don’t know. Apple still makes money from apps that are created with Flash tools, so they might just ignore it and take their 30% cut quietly.

Introducing Slider – the new Flex Mobile Framework

Actionscript, Apple, Flash, Flex, iPhone 3 Comments »

So the big news from the Adobe MAX conference yesterday was the announcement that Flash Player 10.1 will allow Flash Platform developers to create content for a range of other devices including Mobile, NetBooks and Set-top boxes. The new player will include some new multi-touch events to take advantage of this capability on Mobile, MacBook’s and Windows 7 touch-enabled devices. I’ll be looking at these events myself when they release the updated SDK and player and will be sure to post some examples and experiments.

Bigger news came in the form of a spoof ‘MythBusters’ video exploring the ‘myth’ that you can’t produce Flash content for the iPhone. Yes, Adobe will be compiling native iPhone content directly from Flash CS5. There’s no Flash plugin in the browser on the iPhone but the new FP10.1 touch events will work apparently. The compiler technology is way over my head but here’s the press release and some information on labs. It seems that Adobe have snuck a few iPhone apps onto the store in advance and the example I’ve played with, Chroma Circuit, performed very well (and is really addictive).

This got me thinking about the future for apps on the iPhone if Flash peeps all rush off trying to submit their content to the store. For a start Apple are going to be struggling to keep on top of their approval process. Apple is very strict when it comes to the Human Interface Guidelines (HIG) and the iPhone Dev kit that most devs use to generate UI elements on the iPhone ensure that developers ‘toe the line’ and by and large result in a design consistency that has been part of their success with the device. Now, I know there are already a lot of god awful apps on the iPhone that seem to deviate from the HIG exceedingly but it isn’t just the appearance of an app that is the issue here. Developing apps for the iPhone is a tricky, slippery business. Memory management and proper garbage collection is vital to the performance of the app and without thorough testing and a decent authoring/debugging environment like XCode it’s going to be very difficult indeed to create a decent iPhone app in Flash. So how will we develop decent apps for the iPhone or any of the other devices for that matter?

Well, while everyone was tweeting about the iPhone news I found myself reading through the Mobile dev FAQ’s and noticed this …

Can I use the Flex Framework to create content for the iPhone?

While it is possible to create iPhone content using the desktop Flex Framework, we do not recommend it. The Flex framework is currently optimized for execution in a desktop environment. The performance, UI, and interaction models have not been optimized for mobile devices.

Adobe is working on a mobile Flex Framework, which should be better suited for iPhone development.

What? That last line got me very excited. And then I saw the link.

And here’s a sneak preview!

Flex for mobile devices

Here’s the app they built running on an iPhone :
Flex Mobile Framework

Interesting bit of trivia is that the codename ‘Slider’ is a joke based on a conversation in which the original Flex framework was compared with a nice juicy burger for developers and so the mobile framework would be a smaller burger … a ‘slider’. As a brit … I don’t get it.

So, there’ll be a new lightweight Flex framework that will allow us to produce UI elements and advanced layouts for mobile devices and this framework is currently codenamed ‘Slider’. Now, personally the iPhone thing could be painful but lets not forget about all of the other devices that we can now develop for. A project will need to change state dynamically to fit within a range of screen sizes, layout will be extremely important as people expect their content to adjust to different orientations and the implementation of themes is also going to be huge. The Flex framework is perfect for this type of development and the Spark/FXG partnership is lightweight and flexible.

Reading the FAQ I noticed this …

On what platforms will Slider run?
The initial Slider framework will be optimized to run on high-end smartphones (phones with a processor speed of 400Mhz or more, 128MB of RAM), and will initially target standalone application environments such as Adobe AIR. This matches the category of devices targeted by Flash Player 10.

Reading between the lines here but does this suggest that the AIR runtime will also be available on devices?

UPDATE: This video on Adobe TV talks about how the process of developing the iPhone app is very similar to building an AIR app. So I guess there wont be an AIR runtime for mobile devices.

Building Mobile Applications with Adobe AIR

Some interesting information in that video. Hardware acceleration will be supported via the use of the cacheAsSurface property.

Ted Patrick has a great post on developing iPhone apps with CS5 including source. Check it out.

Here’s a real good cast of the Secret Session from yesterday with Richard Galvan which explores a bit more about the new features of Flash Pro CS5 including the Text framework and support for ligatures and flow.

They’ve added integration between the Flash IDE and Flash Builder so you can launch FB4 from the Flash IDE and setup workflows between the two environments including launching Flash pro to test from FB. This is going to be great for managing assets in Flash while coding in Flash Builder. Code snippets in Flash Pro let non-coders add interactivity too. This will allow large agencies with teams to have their tech dude add all the common code the designers need to build banners for example. Code completion in Flash mimics FB too … finally!

I’m expecting more news today in the second keynote and will update this post. If you are at MAX and see any demos of the Slider framework then please leave me a comment and let me know what you saw and heard.

The obligatory post about writing a post on your iPhone

iPhone No Comments »

So here I am sitting in bed blogging about blogging on an iPhone. I’ve installed the WordPress app and so far it all seems to work rather well. I was able to set up both of my blogs with ease and the interface is easy to understand although the initial blog selection screen uses arrow buttons to indicate the edit mode which is counter intuitive. To make this app really useful however I would like to see blogging options integrated into other apps on the phone which will allow me to automatically attach video, photos and maplets. Maplets? I’m not sure if I’ve heard that before or just made it up. In my mind a Maplet is a small map widget with some data attached to it … a mini-google map.

I’ve added a photo from my library of my lovely daughter. I have no idea how it’s going to attach it to my post … We’ll see ay?

iPhone Account center for MT

hosting, iPhone No Comments »

Our beloved and most excellent hosts ‘Media Temple (MT)’ (grovel, grovel, creep, creep) have added an ‘iPhone only’ account center to their list of excellent (grovel, grovel) services.

Check out the info here.

Unfortunately, you need an iPhone to use the service. I’m hoping they are able to provide a standard mobile version of the account center as well. We’ll see ay.

WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS Log in