Category Archives: Xcode

SimpleDrawing for iOS


Introduction

As the name implies, SimpleDrawing is a simple open source drawing app for iOS. I created SimpleDrawing to serve as an example of how to handle the basic drawing features on an iOS device, including:

  • Tools such as pen, line, text, rectangle, ellipse, and eraser
  • Individual tool settings such as primary and secondary color, line width, transparency, and font size
  • Importing photos from the photo album
  • Multi-level undo and redo operations
  • Layers with individual levels of transparency
  • Sharing via mail, Twitter, camera roll and more

The drawing functionality of SimpleDrawing can be used within your own applications with minimal effort. The design of the code also makes it easy to add your own tools by inheriting from SDDrawingTool and overriding (usually) only one method.

Installation

It is possible to use the drawing functionality of SimpleDrawing within your own project. First add the contents of the SimpleDrawing project directly to your Xcode project by drag-and-drop. Next, add the required frameworks: Quartz, Twitter, and MessageUI. Select the main.m file from SimpleDrawing and uncheck it’s “Target Membership” for your target in the File inspector. Finally, disable ARC using the -fno-objc-arc flag for the files BGRSLoupeLayer.m, BSBrightnessSlider.m, and RSColorPickerView.m.

Usage

Once the required files are included in your project, with just a few lines of code you can display a view that lets you browse and create new drawings:

//instantiate the view controller
NSBundle *bundle = [NSBundle bundleForClass:[SDDrawingsViewController class]];
UIStoryboard *storyboard;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
    storyboard = [UIStoryboard storyboardWithName:@"SDSimpleDrawing_iPad" bundle:bundle];
} else {
    storyboard = [UIStoryboard storyboardWithName:@"SDSimpleDrawing_iPhone" bundle:bundle];
}
SDDrawingsViewController *viewController = [storyboard instantiateInitialViewController];

//present the view controller
[self presentViewController:viewController animated:YES completion:nil];

Using the SDSimpleDrawing_iPad storyboard presents the user with a suitable iPad UI:

You can download the source code for SimpleDrawing at my repository here.

UPDATE: The SimpleDrawing app is now available for free from the Apple App Store if you want a free and easy way to try the app.

Advertisements

FileSystemView for iOS Developers

Introduction

When developing an iOS application with persistent data, having an easy way to browse the file system from within the app can be very beneficial. It’s possible to view files in Xcode Organizer with your device tethered via USB, and it’s possible browse the OS X file system to view files created in the simulator. However, having a view that can be tailored to show your application-specific directories available directly within the app is far more convenient. That’s where FileSystemView comes in.

Installation

FileSystemView is easy to include in any iPhone, iPod or iPad project. Simply add the contents of the FileSystemView project directly to your Xcode project by drag-and-drop. Specifically you’ll need to include the contents of the Views, ViewControllers, and Categories directories.

Usage

Once the required files are included in your project, with just a few lines of code you can display a view that lets you navigate the file system at a custom root path, and with a custom starting path:

//instantiate the view controller
NSBundle *bundle = [NSBundle bundleForClass:[FSDirectoryViewController class]];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"FSFileSystemView" bundle:bundle];
UINavigationController *navigationController = [storyboard instantiateInitialViewController];
FSDirectoryViewController *viewController = (FSDirectoryViewController*)navigationController.topViewController;

//set properties on the view controller
viewController.rootPath = [self drawingsDirectory];
viewController.rootPathTitle = @"All Drawings";
viewController.startingPath = [self photoDirectory];
viewController.navigationItem.title = @"Drawing Contents";

//present the view controller
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {

    [self.popoverController dismissPopoverAnimated:YES];
    self.popoverController = [[UIPopoverController alloc] initWithContentViewController:navigationController];
    [self.popoverController presentPopoverFromBarButtonItem:self.folderViewButton permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];

} else {

    [self presentViewController:navigationController animated:YES completion:nil];

}

The view shows file counts and file sizes, including recursive counts for directories. In addition the view lets you drill down into sub-directories, navigate to a customizable root path, and view individual file details.

You can grab the source code from my Bitbucket repo here.

UPDATE: The repository was incorrectly setup when I originally posted this. The repo was public but the wiki (which is the landing page) was private. That is resolved now and the repo should be publicly accessible.

Hip Shot Update Brings Improved Diabetes Support

Version 1.2 of Hip Shot is now available in the Apple App Store. This update incudes the following:

  • You can now track medicine, doses, and carbs with Hip Shot
  • You can build a medication list with default dosages, and also flag a medicine as default
  • Settings are now synchronized between devices using iCloud

With this update, Hip Shot’s feature set is expanding to make the app more useful to those who suffer from illnesses other from Multiple Sclerosis, such as Diabetes.


You can see a video showing some of these new features here.

Hip Shot 1.0 Available on iTunes

I’m very proud to say that my latest iOS project is available on iTunes. I’ve been working with several great friends on this project for a few months now, and I think it has turned out well.

The app is called Hip Shot, and is designed for MS sufferers. Many who suffer from MS self-inject medication and must rotate through a set of locations across the body to minimize negative reactions. These folks also have the need to share that history with their nurses and neurologists. Hip Shot helps users keep track of previous injection locations, suggests coming injection locations, and allows for easy review and sharing of history.

I was approached by my good friend Zack last year about the project. He’d been diagnosed with MS and wasn’t happy with the apps already available. He put together a set of requirements and I set to work with the intention of writing an app and donating the proceeds.

I was lucky to get another friend and colleague, Al Sevajian, to help with some truly great graphics for the app. The app could have been pretty dull given the concept, but I think the professional graphics Al came up with are just top notch. My buddy Greg was also kind enough to put together a simple website for the app.

Hip Shot has been great to work on. While I’ve done a few iOS projects in the past, this is the first time I’ve done something I’d consider graphical, working with all of the different file resolutions for iPhone vs iPad vs Retina iPad. It was also my first submission directly to iTunes (my previous iOS work has been for other clients). Also, Hip Shot gave me an excuse to learn both Core Data and about synchronizing data with iCloud.

So far the feedback from users has been great, and word is slowly spreading both among users and medical personnel. As proceeds come in from Apple I’ll be making donations to the National MS Society. You can learn more at hipshotapp.com.

Delay Applying Updates in Data Abstract iOS Apps

Even though the code generated by the Data Abstract for Xcode template for iOS apps is mostly asynchronous, you may notice delays in the UI when applying updates to your server. If you check out the asyncRequest:didFinishApplyingChangesForTables:withErrors: method in DataAccess.m, you’ll see that, once an asynchronous request finishes, your data will be saved to the local briefcase file:

- (void)asyncRequest:(DAAsyncRequest *)request didFinishApplyingChangesForTables:(NSArray *)tables withErrors:(NSArray *)errors
{
	[self saveData];
	[self setBusy:NO];
...

This happens on the main thread and, given a large enough set of data, will cause your app to stutter.

Luckily this is pretty straight forward to address. Cocoa makes it easy enough to run code in a background thread, and that’s exactly what Alexander from RemObjects suggests:

-(void)saveDataInBackground {</pre>
    [self performSelectorInBackground:@selector(saveData) withObject:nil];
}

- (void)asyncRequest:(DAAsyncRequest *)request didFinishApplyingChangesForTables:(NSArray *)tables withErrors:(NSArray *)errors
{
    [self saveDataInBackground];
    [self setBusy:NO];
...

I’ve been using a form of the above solution for a while now and can confirm that things are running smoothly, even with a larger set of data. Alexander let me know that this would be addressed in the Xcode templates for a future DA update.

Offline Mode with Data Abstract for Xcode

Offline Mode Sample App

Data Abstract for Xcode makes it simple to support disconnected n-tier iPhone applications. The briefcase support is a snap, requiring only a few extra lines to be uncommented from the templates installed into Xcode by the Data Abstract installer.

I recently looked into adding support for an “offline” mode to a Data Abstract application I’ve been developing for the iPhone. Basically, the application should function whether the iOS device has an active network connection or not. If there is no connection, any changes to data should be cached until a network connection becomes available.

This ended up being pretty easy to do. I started by adding Reachability support to the application. You can read detailed instructions about how to do that on Stack Overflow.

Once Reachability support has been added, it’s trivial to alter the beginApplyUpdates code in DataAccess.m to only apply updates when a network connection is available:

- (DAAsyncRequest *)beginApplyUpdates
{
	if (!internetActive) {
		return nil;
	}
        ...
}

Then, modify the Reachability usage to apply any unsaved updates when a connection becomes available:

		case ReachableViaWiFi:
		case ReachableViaWWAN: {
			NSLog(@"The internet is working via WIFI.");
			internetActive = YES;
			//have we received data before?
			if (self.daTestTable) {
				//setup data adapter (to get a new connection)
				[self setupDataAdapter];
				//commit any pending changes to the server
				[self beginApplyUpdates];
			}

			break;
		}

The only tricky bit I found was the need to re-create the DARemoteDataAdapter after a network connection becomes available. This is because you may have an old connection that will cause an error if you try to reuse it.

You can download a sample application here. The archive includes a SQL script for generating the sample DB table.