iOS Simulator and Documents folder

August 4th, 2013

This is geared to the iOS developers or project managers who might be testing builds with the simulator out there…

Recently, my client wanted to check out wow their currently shipping app would look under Apple’s new iOS 7. Since they did not have iOS 7 installed on any of their testing iPads, they wanted to run the latest code base under the simulator. Their app requires some files in the Documents directory to be at useful, so the question of how to populate it with test data came up. Here is the skinny:

Overview

When you are developing an application for iOS, I would guess that a majority of the time (except in certain situations) you will be relying on the iOS Simulator (it is actually named “iPhone Simulator”, but it covers all the iDevices, so whatever). If for no other reason than the code-compile-debug cycle is much faster. But what if your application works with external files stored and transferred in and out of the Documents directory?

From here on out, we are going to assume a bit of familiarity with Terminal.app. If you are a developer and don’t have experience with Apple’s command line terminal application, we keep it fairly simple, but you really should become familiar with it. Please launch it now. You will find it in /Applications/Utilities/.

Find The Way

So, when Xcode runs your application in the simulator, where does it live? Here:

~/Library/Application Support/iPhone Simulator/<iOS version>/Applications/

Where <iOS version> might be “6.1″ or some what ever (well pretend at this date and time we are referring to 6.1, but it would be the same with any version). If we get a directory listing (ls command), we should see something like:

Screen Shot 2013-07-26 at 1.25.54 PM

Here we see 7 different entries, each corresponding to a different application (your listing may have more or less, depending on how many different projects you have going at one time). When the application is launched in the Simulator for the first time (or after a “Reset Contents and Settings…” from within the simulator) Xcode creates and associates an Unique IDentifier (erstwhile known as UID) with which to name the directory for the application bundle and to track the application from within the debugger.

As you might expect, this makes it slightly challenging to find your app. Sometimes, using the ls -l command will give us the additional information we need (namely, date of the creation for the directory), from which we can determine our desired directory.

Screen Shot 2013-08-04 at 7.02.44 PM

Otherwise, we can do:

ls ~/Library/Application Support/iPhone Simulator/6.1/Applications/*

and examine the results to see which contains our application (looking for MyApp.app). You should see each of the above directories (with UID naming) plus their contents listed beneath each.

Screen Shot 2013-08-04 at 7.03.56 PM

Copying

OK, so now we know our path to our target iOS application. From here on out we’ll use 05EF4BB0-A995-99C1-067752EAD15B as our example UID. The path to this applications’s Documents directory will appear as such:

~/Library/Application Support/iPhone Simulator/6.1/Applications/05EF4BB0-A995-99C1-067752EAD15B/Documents/

Now we’ll employ the services of the Unix command cp (for copy) in the Terminal:
cp -v /path/to/file or files/we/want/copied/* ~/Library/Application Support/iPhone Simulator/6.1/Applications/05EF4BB0-A995-99C1-067752EAD15B/Documents/

Translated this is telling the system: copy all the files in the source directory to our simulator app documents directory. The ‘-v” tells cp to report each file copied, so you can leave this option off if you like.

If you prefer to use the OS X Finder to drag-and-drop copy files, then simply issue the system command

open ~/Library/Application Support/iPhone Simulator/6.1/Applications/05EF4BB0-A995-99C1-067752EAD15B/Documents/

And a new window will be opened with connected to the Documents directory.

I hope this helps.

Integrating non-ARC source into an ARC project

July 2nd, 2013

There is little to no reason to not be using Apple’s Automatic Reference Counting (unless your product is truck in an ancient runtime – pre iOS 4 and OS X 10.6). But, if you have some legacy code that gets compiled into an ARC enabled project, here’s a little trick using C macros (you can name them whatever you want, we use the WB, for “Wooly Beast”, prefix):

#ifndef WBRetain
#if __has_feature(objc_arc)
# define WBRetain(obj) obj
#else
# define WBRetain(obj) [obj retain]
#endif
#endif

#ifndef WBRelease
#if __has_feature(objc_arc)
# define WBRelease(obj)
#else
# define WBRelease(obj) [obj release], obj = nil
#endif
#endif

#ifndef WBAutorelease
#if __has_feature(objc_arc)
# define WBAutorelease(obj) obj
#else
# define WBAutorelease(obj) [obj autorelease]
#endif
#endif

Some examples of usage:

// an autoreleased object
MyObject *obj = WBAutorelease([[MyObject alloc] init]);

// a manually released object
MyObject *obj = [[MyObject alloc] init];
// do stuff...
WBRelease(obj);

For easy cut-and-paste, check out the gist.

CoreData + iCloud, Buyer Beware

February 4th, 2013

Back when iOS 5 was released, it was introduced having support for Apple’s new “cloud service”, iCloud. Dutifully, Apple provided developers with an API to store and access data in iCloud, and their usual Apple way, attempt to implement the “heavy lifting”.

We can now store small bits of key-value data, quickly and easily, to be shared amongst our devices.

Additionally, documents can be “magically” store with minimal additional effort from previous document support.

Finally, the coup-de-gras, is the ability to sync our Core-Data backed data, again, with only the smallest number of changes to current implementation.

To help its developers along, Apple provides sample projects and code snippets to demonstrate the ease by which these magical technologies may be easily incorporated.

Even at the latest local CocoaHeads meeting, the presenter puts together a demo that shows the wonders of using CoreData plus iCloud, and we all applaud in approval.

Others might have disagreed, however.

  • No Identity apps had their tush bitten by a released application.
  • Notable Mac developer, Bare Bones Software (at this time) is still struggling with getting their app, Yojimbo, to play nice with iCloud (although, in all honesty, they might have come from a slightly different direction with converting the now defunct MobileMe support to iCloud)

Not trying to be a nay-sayer, but this is not comprehensive list of complaints we have heard. We haven’t made the transition on Wooly Tasks yet, so we are not speaking from first-hand knowledge, but best to go into the effort with eyes-wide open.

OpenGL glTexParameters

August 22nd, 2012

Silly me, I thought that whenever you bind a texture for rendering, you need to set the texture parameters at that time. Through a bit of trial and error, and a lot of reading, unless there is a need to change the texture parameters during runtime, you can set them once and forget about them at initial texture loading to the GPU. As long as this texture is valid (not been deleted by glDeleteTextures(…)), then these parameters will remain valid and associated with this texture. Of course, loading of textures should ideally be done once, at the start of the application or game’s level.

// allocate a new texture, bind it and set the initial parameters
GLuint name = 0;
glGenTextures(1,&name);
glBindTexture(GL_TEXTURE_2D,name);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
// set other texture parameters
...
// load our texture data
glTexImage2D(GL_TEXTURE_2D,...);

 

Now, when we want to render our quads (double triangle strips), we just bind our texture (assuming that textureID is value obtained from the code snippet above and saved someplace logical).

glBindTexture(GL_TEXTURE_2D,textureID);

And submit our quad information

GLfloat verticies[8] = {...}; // 4 x,y pairs
GLfloat texCoords[8] = {...}; // 4 s,t pairs
GLubyte colors[32] = {...}; // 4 r,g,b,a quartets
glVertexPointer(2,GL_FLOAT,0,verticies);
glTexCoordPointer(2,GL_FLOAT,0,texCoords);
glColorPointer(4,GL_UBYTE,0,colors);
glDrawArrays(GL_TRIANGLE_STRIP,0,4);

The less OpenGL calls you need to perform, the better your game’s performance will be. Hopefully this bit of information will help.

NSDates and Fractional Seconds

July 18th, 2012

A recent overhaul to Wooly Tasks allowed me to manage and query for Task records quicker, more easily, and more reliably. However, I quickly ran into a silly snap when ordering lists of Tasks based on their due dates.

Would you care for another date?…

The recommended method for adding time to a NSDate is by setting up a NSDateComponents object and adding the components to the date object that you want to change. Behind the scenes, the OS will handle the cases of Daylight Savings time changes and Leap Years correctly. Simply adding a NSTimeInterval does not.

Incorrect:

NSTimeInterval oneHour = 3600; // magic number! 60 seconds * 60 minutes
NSDate *newDate = [date dateByAddingTimeInterval:oneHour];

Correct:

NSDateComponents *components = [NSDateComponents new];
[dateComponents setHour:1];
NSDate *newDate = [[NSCalendar currentCalendar] dateByAddingComponents:components toDate:date options:0];

The NSDateComponents class interface for setting the hour uses a NSInteger, and not a float or double. This is true of all the other components:

...
- (void)setDay:(NSInteger)v;
- (void)setHour:(NSInteger)v;
- (void)setMinute:(NSInteger)v;
...

Dates gone bad…

OK, now we know the correct way to add time to a date, let’s look at something that could bite us in the ass. In the case of Wooly Tasks, we limit due dates to have granularity of every 5 minutes. We also prepopulate a new task with a date that falls on the hour, and is at least 30 minutes from the moment the task was created. So if the current time is 12:34 when we create the task, then we’ll choose 2:00 instead of 1:00 as the due date time. We call this normalizing the due date.

The problem exists, if we create a couple of tasks and normalize the date something like:

NSDate *date = [NSDate date];
NSUInteger unitFlags = NSMinuteCalendarUnit+NSSecondCalenderUnit;
NSDateComponents *components = [[NSCalendar currentCalender] components:unitFlags fromDate:date];
NSInteger hour = ([components minute]<30) ? 1 : 2;
[components setHour:hour];
[components setMinute:-[components minute]];
[components setSecond:-[components second]];
date = [[NSCalendar currentCalendar] dateByAddingComponents:components toDate:date options:0];

This will wind the minutes and seconds back to hh:00:00, and the hour ahead by one (two if the date was less than 30 minutes from the next whole hour). Unless you examine the actual NSTimeInterval of these dates, then several created within a short period of time (for our example, within 5.5 seconds of each other) that might appear to be the same time:

Date 1:

July 18, 2012 4:31:39 PM PDT
364347099.942335
July 18, 2012 6:00:00 PM PDT
364352400.942335

Date 2:

July 18, 2012 4:31:45 PM PDT
364347105.456080
July 18, 2012 6:00:00 PM PDT
364352400.456080

Each date above is shown with four values: the raw date, the raw date in seconds*, the normalized date, and the normalized date in seconds*. (* number of seconds since January 1st, 2001 GMT). What you notice is that the seconds display have a fractional part that doesn’t get reflected by the user readable display.

This becomes problematic in applications that want to sort records by dates as the primary sort key, and another criteria for a secondary sort key. Particularly so when the coarseness of the dates is less than at the seconds level. For instance, if we sorted the above normalized dates, then record with Date 2 would appear before record with Date 1, even though to the user they would appear to be the same. In cases where the secondary sort criteria would have put a record with Date 1 before Date 2, this sorting would have failed to do so.

A Good Date…

There is no way to remove these fractional seconds by using -dateByAddingComponents:toDate:options: because -setMinute:, as noted above, accepts a NSInteger and not a floating point value type. We can easily modify our code above to handle that using our handy-dandy function, trunc():

NSDate *date = [NSDate date];
NSTimeInterval seconds = trunc([date timeIntervalSinceReferenceDate]);
date = [NSDate dateWithTimeIntervalSinceReferenceDate:seconds];
NSUInteger unitFlags = NSMinuteCalendarUnit+NSSecondCalenderUnit;
NSDateComponents *components = [[NSCalendar currentCalender] components:unitFlags fromDate:date];
NSInteger hour = ([components minute]<30) ? 1 : 2;
[components setHour:hour];
[components setMinute:-[components minute]];
[components setSecond:-[components second]];
date = [[NSCalendar currentCalendar] dateByAddingComponents:components toDate:date options:0];

An ARC Transition Tale

July 10th, 2012

If you are not a software developer, this post will probably of less interest to you. Otherwise, please read on…

Recently, I updated Wooly Tasks to use Automated Reference Counting (ARC). The transition from a non-ARC project to an ARC project is fairly straight forward, and mostly automated by Xcode 4. ARC allows the developer to worry less about Cocoa memory management rules, and instead focus on their object graphs and creating great software. ARC is a handy tool, but you now a have some new rules to learn (although, in truth they are probably less confusing as a whole than the old rules). One that is important is object lifespans. Essentially, this means the LLVM compiler can decide to release an object that it deems unused at any moment within the body of the code. We’ll see what kind of ramifications that presents soon.

It’s all fun and games until you shoot your eye out…

Once I had successfully transition (i.e. it compiled and linked), I tested Wooly Tasks using the simulator. To my delight, everything still worked as expected. OK, time to build and install on a device (in this case my iPhone 4S running iOS 5.1).

Launch.

Boom!

Crash. What the #^$#!!

Check with the Simulator again. Fine.

Back to the iPhone. Crash. Gah.

Unfortunately, it crashes due to an autorelease object, so there is no stack dump to figure out what the object is that is causing the issue (this is not entirely true, you can look at the crash log in Xcode, and this would give you plenty of clues…I didn’t think to look there first, unfortunately — lesson learned). All I get is a cryptic console log exception message stating:

“[Not A Type isEqual:] sent to deallocated object 0x….”

Well, huh.

Debugger spelunking time.

So, I started running it in the debugger and setting breakpoints starting from the first UIApplication delegate call and on down the line until I narrow it down to the setting up of the first view controller and displaying its view. Eventually I found the offending code (for brevity, I have left out the values, they were irrelevant to the issue, as is the particular color creation method):

CGColorRef color = [[UIColor colorWithHue:saturation:brightness:alpha:] CGColor];
self.layer.shadowColor = color;

Do you see the problem? Clang’s document on Automatic Reference Counting and lifetime semantics states:

By default, local variables of automatic storage duration do not have precise lifetime semantics. Such objects are simply strong references which hold values of retainable object pointer type, and these values are still fully subject to the optimizations on values under local control.

We have done the equivalent of:

UIColor *uiColor = [UIColor colorWithHue:saturation:brightness:alpha:];
CGColorRef cgColor = [uiColor CGColor];
self.layer.shadowColor = cgColor;

LLVM has every right to deallocate the UIColor object immediately after obtaining the CGColorRef from it, since by all accounts, it is no longer be used. This would then invalidate the data referenced by the cgColor local variable. When we set the shadowColor for the layer, we are potentially (in this case, we definitely were) stuffing an invalidated (but not nil’d) object value into it.

The Fix

The simplest solution was to rewrite the code like:

UIColor *color = [UIColor colorWithHue:saturation:brightness:alpha:];
self.layer.shadowColor = [color CGColor];
LLVM compiler will not be able to insert a release between accessing the CGColor and assigning it to the shadowColor.
And here you thought you could forget all those pesky memory rules.

iOS: UIMenuController

June 12th, 2012

File this one under: For my own future reference.

UIMenuController was introduced as public API in iOS 3.0 (along with UIPasteboard and Copy and Paste functionality). This is now a technology we take for granted in the iOS world, but it really wasn’t that long ago that Apple hadn’t provided this seemingly basic service.

Recently I was using this API in DeepDish GigBook to update some fairly crufty workflow. I am not going to explain how to use UIMenuController, as the documentation is fairly straight forward. What I will mention is a few “gotchas”.

1. There is no target for an UIMenuItem.

It is whomever is the First Responder. In other words, your controller class probably (in most cases) is what will handle the actions, so you want to make sure it can become the first responder. Add the following to your controller implementation:

- (BOOL)canBecomeFirstReponder
{
    return YES;
}

IF you don’t do this, then passing the message -setMenuVisible:animated: to the UIMenuController will have no effect.

2. Implement - (BOOL)canPerformAction:(SEL) sender:(id) in your controller:

There is little reason not to, and many reason why you should. This will be implemented in the same controller that also implemented -canBecomeFirstResponder. This will allow you to enable or disable (effectively hiding) any menu options you may or may not want at any particular time. It avoids having to recreate the menu items list every time the user invokes your menu through whatever gesture.

- (BOOL)canPerformAction:(SEL)action sender:(id)sender
{
    if ( action == @selector(myMenuItemMethod:) ) {
        return YES;
    }
    else if (...) {
        return ...;
    }
    else {
        return [super canPerformAction:action sender:sender];
    }
}

Of course, there might be situations where the same view might support different menu configurations depending on some context, in which case you probably do need to rebuild the menu list each time. But in case where you don’t…

3. Remember that your menu items are persistent:

Whatever menu items you add will remain there until they are set again. If you think about it, this makes sense since UIMenuController is a singleton.

This one bit me due to two reasons. 1) I didn’t have -canPerformAction:sender: implemented, 2) I assumed that menu items list must be rebuilt prior to each invocation of the menu. What happened was a different subview was presented within the main view of the controller, and the subview contained an UITextView. When the user double tapped the text view, and had some text on their pasteboard, the Paste menu option was displayed, along with the other menu options already installed by an earlier menu displayed in the same view. Oops.

The first solution was to nil out the menuItems when the menu was dismissed. This seemed a bit of hack. The better solution was to follow item 2 above since my menu items never changed as long as I was in this particular view. In this case, since a subview only required the basic Copy, Cut, Paste, Select, Select All, etc. the controller would return NO when the controller itself was no longer the first responder. Revisiting our implementation of -canPerformAction:sender: from above:

- (BOOL)canPerformAction:(SEL)action sender:(id)sender
{
    if ( action == @selector(myMenuItemMethod:) ) {
        return [self isFirstResponder];
    }
    else if (...) {
        return ...;
    }
    else {
        return [super canPerformAction:action sender:sender];
    }
}

Cheers!

What’s Happening

June 6th, 2012

It’s been quiet on the Wooly Blog front. Too quiet.

To be honest, it is because we spend our days writing code and not writing prose. But, communication is key, and everybody wants to know their favorite Wooly company is still alive and kicking.

We have noticed that Wooly Tasks is a bit long for an update. All I can say is that a pretty nice update is in the works. What to expect:

  • New task management engine to more efficiently and reliably track and manage the tasks.
  • Printing and Twitter support (paid version only)
  • New UI layout to show the most important information quickly, and additional details when you desire them.
  • On iPad, removed hideous paper pad background. It wasn’t our finest moment.
  • iCloud integration and synching between devices (paid version only).
  • Stability enhancements (ok, we fixed some bugs).

On the Wooly Wind Chill side of things, we are looking into being able to integrate your favorite weather source for tapping into current temperatures and wind speeds. The first version will roll out with just a couple, and subsequent versions will add more.

On the contracting front. We are still helping Deep Dish Designs make their wonderful iPad Music application, DeepDish GigBook. While we can’t state specifics, we do know a new version with some very useful enhancements (do we sound a bit biased?) that both companies worked hard on putting together will come out “soon”. Current shipping version in the App Store is 1.6.2, so when you see a version number greater than that, then that “soon” time has arrived.

Speaking of iOS contracting services. If you have a funded product idea that you want Wooly Beast Software to help you bring to market, please feel free to contact us at info@woolybeastsoftware.com.

Finally, after considerable discussions with management, we have embarked on an exciting new project. In this post, we will not go into a lot of details of what it is, because there are still some things to work out at our end. However, we can say it will involve a bit of this: 

and this:   

and a whole lot of these guys:

That’s about it for now. Next installment we’ll discuss a bit more on what’s going on with our new project, and chronicle the steps up to release.

 

Xcode 4: Renaming projects

January 22nd, 2012

Xcode 4.x is a great leap forward for iOS and Mac OS Developers. Many thanks should be expressed to Apple and its engineers for their hard work in putting together such a toolset. If you were used to Xcode 3.x’s way of doing things, then you might find yourself wondering how to do various operations that seemed to have disappeared. Renaming a project one such feature that took a while to relocate, so I am sharing how it is done in Xcode 4.x. It is much better to rename the project through the mechanism provided by Xcode than trying to rename the project file via the Finder. I have done so in the past, and it wrecks havoc on the project settings.

 

Step 1. Select the project in the Navigator (left side of Workspace. Command-1 to reveal).

 

 

 

Step 2. Make sure the File Inspector is visible. (right side of Workspace. Command-Option-1 to reveal, or third most button in the view button cluster).

 

Step 3. Under Identity, you will see the Project Name text field.

Change the name of the project to the new desired name.

A drop down sheet will appear when you exit the text field. It will be showing you what will change, giving you one last chance to back out…sort of. This last chance inquiry is for settings that are derived from the project’s name (target name, product name, prefix header, etc.).

If you say “Don’t Rename”, the project itself will still be renamed, but the auxiliary portions won’t. This could potentially leave things in an unsavory state. I imagine this is a bug, and as a matter of fact, even had Xcode crash more than once when testing out renaming of the project, but not going through with it.

You may also be asked whether you want to take a Snapshot prior to preforming the renaming. This is entirely up to you and your risk tolerance.


That about covers it. Happy programming!

 

 

Steve Jobs 1955-2011

October 5th, 2011

Steven Paul Jobs 1955-2011

Today, Steve Jobs, an amazing man in his own right, and an undisputed visionary, passed away at age 56. He led an amazing life, did amazing things, and created several amazing companies (NeXT, Pixar, Apple). He, more than many others in history, has done more to positively influence people’s lives and livelihoods.

I am selfishly sadden that I never got to personally meet Steve, even though I have admired him ever since I brought home my first Apple product, an Apple ][+, nearly 30 years ago. That purchase, earned by a summer of construction work during the summer between my sophomore and junior year of high school, led me to the path of developing software as a profession.

When I lived and worked in Sunnyvale, in the early 1990's, I use to ride my bicycle up Foothill Expressway and into Palo Alto (usually stopping at Stanford with a book to read and soak in some of the sun). Often, before heading home, I would ride into the neighborhoods of Palo Alto, knowing that Steve Jobs had his house somewhere there. I was hoping that I might have a chance encounter with him, or at least see his house from the street. I never did, and having seen pictures of his house, I'm pretty sure I was in the wrong neighborhoods, but it sure was fun trying at the time.

Other people who may or may not have made their marks on the world, including noted civil rights leader Rev. Fred L Shuttlesworth, died on the same day. This doesn't mean that Steve was better than these other people. We could all learn from their lives. Steve gave us the gift of showing that hard work, breaking the status quo, and doing things a bit differently is a Good Thing.

May his family find comfort somehow in knowing he is no longer suffering, and is at peace. May the world come together and embrace his propensity of creative thinking and attention to detail.

Rest In Peace, Steve. You inspired me for 30 years, now we continue forth and carry your message into the future.

 

“Stay Hungry, Stay Foolish”