iOS Fragmentation – iCloud style

To be clear from the start, I’m talking from development’s point of view, not percentage of devices getting new OS versions. Just good old code :)

Since iOS version 5.x there is a fragmentation in iOS that I really don’t like. Since my app was rejected from the appstore I started reading more about iCloud and how it has been implemented in different iOS versions.

Official reason why my app was rejected is:

We found that your app does not follow the iOS Data Storage Guidelines, which is required per the App Store Review Guidelines.

That sounded OK, I’m not complaining, I was unaware of iCloud integration to be honest (or how deep the integration is). In the same message from apple, I’ve got a hint to take a look at this Q&A.

To make a long story short:

  1. iOS 4.x: There is no iCloud sync, so you can store your files in /Documents folder without any problems.
  2. iOS 5.0: Everything in /Documents folder is synced with iCloud, so you have to put your files in /Cache. The only problem is that when your iDevice runs out of space, your cache folder will be deleted most likely.
  3. iOS 5.0.1: You can set a “don’t sync” this file/folder inside your /Documents folder. That is pretty good, but this code is only for this version
    #import <sys/xattr.h>
    - (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL {
    
      assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]);
    
      const char* filePath = [[URL path] fileSystemRepresentation];
      const char* attrName = "com.apple.MobileBackup";
    
      u_int8_t attrValue = 1;
    
      int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0);
    
      return result == 0;
    
    }

    Apple marked this code as deprecated for later version of iOS

  4. iOS 5.1+ (currently 5.1 and 5.1.1): You can also flag files or folders, so that they are not synced to iCloud. Here is the snippet:
    - (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL {
      assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]);
    
      NSError *error = nil;
      BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES]
                                    forKey: NSURLIsExcludedFromBackupKey error: &error];
    
      if(!success){
        NSLog(@"Error excluding %@ from backup %@", [URL lastPathComponent], error);
      }
    
      return success;
    
    }

Also in my app I’ve added a small piece of code that handles iOS updates. For example if user had my app with 5.0 and then updates to 5.0.1 or similar.
After applying these snippets to my app it was approved without problems.

So the only thing I’m wondering is why isn’t iCloud handling as elegant as most of iOS features? :)
It’s not that bad, but I don’t like it.

Advertisement

Super easy iOS XML parsing

I just love it when you need something simple and easy that perfectly suits your needs. I needed some lightweight XML parser for iOS, and I found it.

To be honest (since I’m coming from java background), I didn’t quite fall in love with objective-c at first, and it seemed to be that I needed a lot more code to make some basic stuff work. For example XML parsing. NSXMLParser is ok, but it’s event driven (link #1, link #2). I wanted some dead simple DOM parser.

So the whole library is just two classes SMXMLElement and SMXMLDocument. To show you how simple it is to parse a file, here is a (reduced) snippet from my application:


- (void) parseData:(NSData *) {

   NSError *error;
   SMXMLDocument *document = [SMXMLDocument documentWithData:data error:&error];

   // check for errors
   if (error) {
   DDLogError(@"Error while parsing the document: %@", error);
   return nil;
}

// Array of objects that we are returning
NSMutableArray *result = [[NSMutableArray alloc] init];

// Get the videos node
SMXMLElement *videos = document.root;

// Go through every sub-element "video"
for (SMXMLElement *video in [videos childrenNamed:@"video"]) {
   VideoInfo *info = [[VideoInfo alloc] init];
   info.name = ;

   // Get other values from XML...
   [result addObject:info];
   [info release];
}

return result;
}

A shorter version of XML that the code above parses is:


<videos>
   <video>
      <name>Yup, this a name of a video</name>
   </video>
   <video>
      <name>And another one :)</name>
   </video>
</videos>

As you can see I’m only using (NSString*) valueWithPath:(NSString *) here, but there are a couple more


- (SMXMLElement *)childNamed:(NSString *)name;
- (NSArray *)childrenNamed:(NSString *)name;
- (SMXMLElement *)childWithAttribute:(NSString *)attributeName  value:(NSString *)attributeValue;
- (NSString *)attributeNamed:(NSString *)name;
- (SMXMLElement *)descendantWithPath:(NSString *)path;
- (NSString *)valueWithPath:(NSString *)path;

Do you really need anything else (in some small applications)? :)
Really awesome, kudos to the creators.