Jul 15, 2010
I previously explained how to use NSUserDefaults to your advantage, basically being the OSX equivalent to the Windows registry. User Defaults are the way how you can persist small amounts of data in a convenient way. They are basically dictionaries that the system takes care of for you with the added benefit of being cached in memory.
Today we’ll up it one notch. Session 124 of the WWDC 2010 videos brought to my attention the fact that there’s also a mechanism to provide default values for the defaults. Up until now I would have retrieved an object from the defaults, checked if it’s nil and then set the value. Consider the following code snipped from SpeakerClock:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSNumber *countdownNum = [defaults objectForKey:@"Countdown"];
countdown = [countdownNum doubleValue];
countdown = self.currentPreset.startDuration;
This works, but it’s not elegant. Wouldn’t it be great if we could pre-register those values so that a simple retrieval always has a result?
Jul 04, 2010
UPDATE: Added handleOpenURL to the flow charts. Added UIApplicationExitsOnSuspend. Untangled some lines.
UPDATE: renamed deprecated handleOpenURL to newer name.
Now that we all are moving our source code gradually to iOS 4 I had to pause and think a bit about where to move which code. A problem that I’m facing frequently when updating a project is that the didFinishLaunching is only called if the app really launches.
That poses a bit of a challenge if you are used to doing things like refreshing images or other files off the internet. An app that is resumed from standby does no longer go through this delegate method. So an app that would always show fresh content upon launch before 4.0 multitasking would no longer load any new content as soon as you build it for 4.0. That’s actually one of the main reasons why I have not yet had time to update MyAppSales to 4.0.
To gain the possibility for “fast app switching” you actually don’t need to do anything. All apps automatically support it because they no longer get terminated if the user pushes the Home button. They get put into a sleep mode while the iPhone still has enough memory for everything else. It’s only if RAM runs out that the OS starts killing apps. There is begins with the ones that have the most memory reserved.
I grabbed the free trial of Omnigraffle and the Non-techie Process Flowchart Stencils by gfraser. Then I researched when all these various delegate methods of UIApplication are being called and drew charts to illustrate the flow.
By inhaling first how it was before multitasking and then upgrading your mental process to backgrounding we can begin to fully appreciate how it all fits together.
Jul 04, 2010
Prior to iOS 3.2 your only option for playing videos on iPhone was to use MPMoviePlayerController and only in full screen mode. It made sense because who really wants to look at stamp sized videos on his mobile phone.
The iPad changed all that and brought along several changes in how you can place videos. All those changes also made it into the iPhone SDKs. Here’s a pitfall that you might not have seen if you didn’t upgrade the SDK on one of your iPhone projects.
Jun 26, 2010
As of SDK 3.2 most of the touch handling code in stock controls has been taken out and replaced with this amazing new technology called Gesture Recognizers. This means besides of using them yourself and creating your own you can also fiddle with behaviors of standard controls if they interfere with your own gestures.
I’m currently working quite a bit on something based on UIScrollView and there I found several things that I needed to tweak.
The first modification I did was to get around a bug in UIScrollView. I did not actually want user zooming in my scroll view, but just use the setting of the zoomLevel to scale images without having to redraw them. And you can only set the zoomLevel to values between min and max.
So, during autorotation, I reduced the min zoom scale, set the new zoom level and then set min and max both to the new zoom. But the problem with this, as of SDK 3.2., is that if you change the min or max zoomLevel property the scroll silently adds a UIPinchGestureRecognizer to itself via the addGestureRecognizer method that now all views have.
Jun 17, 2010
We all know by now that Adobe is almost as evil as …, well let’s say they pioneered a couple of functionalities that where great for the longest time. One being the PDF format which is actually totally built into OSX everywhere. On OSX you’re able to print into a PDF without having to install extra software. Also iOS comes with PDF support and today we’ll look at how we can draw a PDF in a view.
How UIWebView sees it
The first idea you might have is to use UIWebView to display PDFs which is not difficult, just get the URL, make a NSURLRequest and pass this to a web view.
_webView = [[UIWebView alloc] initWithFrame:frame];
_webView.delegate = self;
_webView.autoresizingMask = UIViewAutoresizingFlexibleWidth |
// we don't want interaction, full size
_webView.scalesPageToFit = YES;
_webView.userInteractionEnabled = NO;
_webView.backgroundColor = [UIColor whiteColor];
//fileURL is an NSURL to a PDF file
[_webView loadRequest:[NSURLRequest requestWithURL:fileURL]];
But there is one drawback: you cannot really control how it will arrive on screen. For one thing, UIWebView draws a fat gray border and shadow which might somewhat mess up your UI design.
Wouldn’t it be great if you could draw the PDF somehow into a view? Yes, we can!
Jun 04, 2010
I started out with a simple project of mine, the demo I made for DTNotepadViewController. This is a navigation stack which has a UITableView. From there you can select an entry to get a detail view looking like note paper.
The goal is to convert this iPhone-only app into a hybrid app that uses a split view on iPad.
May 25, 2010
Back in April Oliver wrote an excellent article entitled “Making Your Own iPhone Frameworks”, in which he explained how to do what many developers still proclaim as impossible: how to create custom frameworks that you can use in your iPhone apps! I would recommend that you read Oliver’s article first, especially if you’re wondering what a framework is… or, possibly, why you should consider making your own frameworks. I wont talk about that here :).
To build frameworks Oliver wrote a simple shell script that first creates a typical framework bundle, and then copies resources into the appropriate directories. In this followup article, I’ll show you how to create the framework bundle entirely within Xcode, without any scripts, plugins, product-, or package-types. While this has a few advantages, I’m not claiming that my approach is in any way perfect, and there may be problems that I haven’t encountered yet. As always, this is a work in progress, so if you have any suggestions, please feel free to leave your comments below.
Enough talking. Lets get started –
May 25, 2010
Once a year you are required to refresh your two certificates and all provisioning profiles that use these. Mine had expired and so I made a screen capture to show you how painless the renewal process can be. At the same time it also shows newcomers how to best set up their stuff on the provisioning portal.
Hint: if you find that the Submit button is not working, you can also go into the provisioning profile name field and hit Enter.
For regular development work it’s generally sufficient to have only 3 provisioning profiles:
- “Development” – uses your “iPhone Developer” certificate, a * wildcard app identifier and all your development devices
- “AdHoc” – uses your “iPhone Distribution” certificate, a * wildcard app identifier and all devices you want to do ad-hoc builds for
- “AppStore” – uses your “iPhone Distribution” certificate, and if you don’t do IAP or Push Notifications you can use a wildcard app identifier as well
You don’t need to create a new app identifier on the portal for each new app that you begin. You only ever need unique app identifiers if you publish an app capable of InAppPurchases or Push Notifications.You can change the app identifier with every upload to Apple, contrary to the bundle identifier in the info.plist which has to stay the same for the app to be accepted as an update. New bundle identifier means new app.
Once you have gone through the steps shown in the video you are good to go for another year, until the certificates expire once more.
May 21, 2010
I’m coming out of highly concentrated work (approx 87 hours) on my latest project. It’s an app that allows you to organize a betting pool for the upcoming FIFA World Cup.
The simplest method of communicating with our web-based API we found to be having the server send array or dictionary PLISTs which I could load and parse in a single line of code synchronously. So first I created all the API calls in synchronous blocking mode. When they where working I added a method by the same name prefixed with “async” and would have the blocking code executed on an NSOperationQueue.
If the synchronous method needed zero or one parameter then you can use NSInvocationOperation of calling it and have the queue work it off in the background. In some cases more than one parameter has to be passed. Here an NSInvocation has to constructed with multiple parameters, which I explained previously.
Once the API call is done processing it needs to tell the app about its result. This is done conveniently by sending NSNotifications. And in all the places in the UI where specific notifications should have an effect, you simply subscribe to the notifications by adding an observer for them to the default NSNotificationCenter. NSOperationQueue automatically uses multiple threads and takes care of the autorelease pool. So any operation might either run on the main thread or on a background thread.
Warning: Crash Ahead!
This causes a problem I have only ever seen happen on Simulator, so I’m not sure if it would also happen on the device. Generally you want the NSNotifications to be sent on the main thread as well, especially if they trigger UI activities like dismissing a modal login dialog. I don’t know if Apple will tweak NSNotificationCenter to send on the main thread in the future, but until they do, here’s my drop in solution.