Home > Articles > Mobile Application Development & Programming

  • Print
  • + Share This
This chapter is from the book

Recipe: Implementing Document Support

If your application provides document support, each time it becomes active, you should check to see if an Inbox has appeared in the Documents folder. If so, you should move elements out of that inbox and to where they belong, typically in the main Documents directory. Once the inbox has been cleared, delete it. This provides the best user experience, especially in terms of any file sharing through iTunes where the Inbox and its role may confuse users.

- (void)applicationDidBecomeActive:(UIApplication *)application

{

    // perform inbox test here

}

When moving items to Documents, you’ll want to check for name conflicts, and use an alternative path name (typically by appending a hyphen followed by a number) to avoid overwriting any existing file. The following method helps find an alternative name for a destination path. It gives up after a thousand attempts, but seriously, none of your users should be hosting that many duplicate document names. If they do, there’s something deeply wrong with your overall application design.

- (NSString *) findAlternativeNameForPath: (NSString *) path

{

    NSString *ext = path.pathExtension;

    NSString *base = [path stringByDeletingPathExtension];



    for (int i = 0; i < 999; i++)

    {

        NSString *dest =

            [NSString stringWithFormat:@"%@-%d.%@", base, i, ext];



        // if the file does not yet exist, use this destination path

        if (![[NSFileManager defaultManager]

            fileExistsAtPath:dest])

            return dest;

    }



    NSLog(@"Exhausted possible names for file %@. Bailing.",

        path.lastPathComponent);

    return nil;

}

Recipe 16-5 walks through the ugly details of scanning for the Inbox and moving files into place. It removes the Inbox once it is emptied. As you can see, any method like this is file manager-intensive. It primarily involves handling all the error combination possibilities that might pop-up throughout the task. This should run quickly for small file support. If you must handle large files, such as video or audio, make sure to perform this processing on its own operation queue.

If you plan to support public.data files (i.e., will open anything), as this recipe does, you may want to display those files using UIWebView instances. Refer to Technical Q&A QA1630 (http://developer.apple.com/library/ios/#qa/qa1630) for details about which document types iOS can and cannot display in those views. Web views can present most audio and video assets, as well as Excel, Keynote, Numbers, Pages, PDF, Powerpoint, and Word resources in addition to simple HTML.

Recipe 16-5. Handling Incoming Documents

- (void) cleanInboxIfNeeded

{

    NSString *documentsPath = [NSHomeDirectory()

        stringByAppendingPathComponent:@"Documents"];

    NSString *inboxPath = [documentsPath

        stringByAppendingPathComponent:@"Inbox"];



    // Does the Inbox exist? If not, we're done

    BOOL isDir;

    if (![[NSFileManager defaultManager]

        fileExistsAtPath:inboxPath isDirectory:&isDir])

        return;



    NSError *error;

    BOOL success;



    // If the Inbox is not a folder, remove it.

    if (!isDir)

    {

        success = [[NSFileManager defaultManager]

            removeItemAtPath:inboxPath error:&error];

        if (!success)

        {

            NSLog(@"Error deleting Inbox file (not directory): %@",

                error.localizedFailureReason);

            return;

        }

    }



    // Retrieve a list of files in the Inbox

    NSArray *fileArray = [[NSFileManager defaultManager]

        contentsOfDirectoryAtPath:inboxPath error:&error];

    if (!fileArray)

    {

        NSLog(@"Error reading contents of Inbox: %@",

            error.localizedFailureReason);

        return;

    }



    // Remember the number of items

    NSUInteger initialCount = fileArray.count;



    // Iterate through each file, moving it to Documents

    for (NSString *filename in fileArray)

    {

        NSString *source =

            [inboxPath stringByAppendingPathComponent:filename];

        NSString *dest =

            [documentsPath stringByAppendingPathComponent:filename];



        // Is the file already there?

        BOOL exists =

            [[NSFileManager defaultManager] fileExistsAtPath:dest];

        if (exists) dest = [self findAlternativeNameForPath:dest];

        if (!dest)

        {

            NSLog(@"Error. File name conflict not resolved");

            continue;

        }



        // Move file into place

        success = [[NSFileManager defaultManager]

            moveItemAtPath:source toPath:dest error:&error];

        if (!success)

        {

            NSLog(@"Error moving file from Inbox: %@",

                error.localizedFailureReason);

            continue;

        }

    }



    // Inbox should now be empty

    fileArray = [[NSFileManager defaultManager]

        contentsOfDirectoryAtPath:inboxPath error:&error];

    if (!fileArray)

    {

        NSLog(@"Error reading contents of Inbox: %@",

            error.localizedFailureReason);

        return;

    }



    if (fileArray.count)

    {

        NSLog(@"Error clearing Inbox. %d items remain",

            fileArray.count);

        return;

    }



    // Remove the inbox

    success = [[NSFileManager defaultManager]

        removeItemAtPath:inboxPath error:&error];

    if (!success)

    {

        NSLog(@"Error removing inbox: %@",

            error.localizedFailureReason);

        return;

    }



    NSLog(@"Moved %d items from the Inbox", initialCount);

}



// Check for the Inbox each time the app becomes active

- (void)applicationDidBecomeActive:(UIApplication *)application

{

    [self cleanInboxIfNeeded];

}
  • + Share This
  • 🔖 Save To Your Account