Finally, the past six months has come to some fruition: Greenopia
Category Archives: iphone
Fixed a memory leak in Flow Cover.
Meh. This one was a nasty little bug. And now its fixed.
The problem is that in FlowCoverView, the dealloc routine was resetting the EAGLContext object early. This caused the rest of the dealloc call to fail, which then resulted in the overall view to fail to be released.
The fix is to rewrite the dealloc routine for FlowCoverView. Around line 230, replace the old -dealloc routine with:
- (void)dealloc
{
[EAGLContext setCurrentContext:context];
[self destroyFrameBuffer];
[cache release];
[EAGLContext setCurrentContext:nil];
[context release];
context = nil;
[super dealloc];
}
The first call to EAGLContext setCurrentContext makes sure the context is current, so all operations done on the various texture maps and OpenGL objects are done in the right context. Then everything is released–and at the end, the EAGLContext is then released, and so is the view.
I’ve also uploaded a new version of FlowCover which puts the FlowCover view on a second view; press the “test” button to have it pop up.
A new version of the code has been uploaded here. Download and incorporate into your code as you will.
Oh, and I also modified the code license; essentially you do not have to include mention of me in the binary redistribution; just the source code.
The importance of sending a view size changed event on a mobile device.
On Windows Mobile 5 (and I assume the same is true of 6 and 7), the small bar at the bottom which shows the current meaning of the two smart buttons is not a separate chunk of real estate taken away from the rest of the application; instead it is a floating HWND object. It is up to your application to know if that HWND object is present, and to make sure you don’t obscure the HWND.
On the iPhone with the v2.2 and v3.0 OS, the slide-up keyboard is essentially a floating window which overlays your UI. It is your responsibility to know if the keyboard is present, and if so, resize the contents of your view accordingly. That means if you have a table view with an edit text field that is graphically in the area where the keyboard will appear, you have to figure out a way to move the table contents up and down as the keyboard appears and disappears.
I contend that the region of the screen devoted to the keyboard or custom keypad or the like should not be handled as pop-up windows overlaying your user interface. Instead they should be handled as events that resize the main “window” of your user interface. And instead of hooking a half-dozen different events that could change the form factor of the screen, all of these events should be handled exactly the same way they’re handled on a desktop application: with a resize event sent to the “window”, which then percolates down the view chain.
Unfortunately it appears no-one agrees with me. And so we’re stuck doing all sorts of complicated stuff–including Android, which tears down and rebuilds the “Activity” (the thing which manages the views in a UI) rather than simply send a resize event.
Judging an iPhone Development Contest
This evening I’m going to USC to judge an iPhone development contest being held at USC. It should be interesting–and a lot of fun. Part of my goal is to keep an eye out for good talent we may want to poach, and part of my goal is to judge the applications according to concept, user experience, implementation and business model.
Now me, I’m not good on the business model side of the fence: I tend to think of a business model as being “make a good product and sell it for a reasonable price”, which means half of the business models used nowadays in the tech industry makes no sense to me. But what do I know? On the other hand, user experience, and implementation: now all that I’ve got in spades, and I intend to be an opinionated bastard tonight, turning it into a teachable moment if at all possible.
So… How do people use their phones?
Way back in June when I started working for the startup I’m working for now, I made an observation about how people will use their smart phones–a fact which was ignored, and which I believe is hurting our app now. And it reflects how we use different computing form-factors in general.
A desktop is not a laptop is not a pocket computer.
A desktop is an immersive environment. Consisting of a very large display screen and keyboard, a desktop computer is something that generally has a fixed location, but can have a lot of attached or non-portable devices that allow you a great deal of power. Desktop computers are perfect for the daily grind of working at a fixed location.
Laptop and portable computers are less immersive simply because they are smaller. In general, you use a laptop computer by sitting down at a given fixed location, setting up your environment (pull out laptop, open it up, turn it on, find a wireless connection, plug it in), and working. Battery life for a laptop is not all that important unless you set up in an area without an outlet–at which point battery life is invaluable. Battery life is also invaluable if you use a laptop to go from meeting to meeting, where setup time needs to be as short as “take out, flip open.”
Phone computers are the least immersive device, and the one that interests me the most because it is the one that is the least understood. The few people I’ve talked to about phone computers have talked about creating compelling immersive environments for the phone–and tackling the problem of figuring out how to create an immersive environment on a tiny form factor. But phone computers are not immersive.
Certainly there are “immersive” games being designed for the iPhone computer. But there are also a lot of people who seem surprised that some of the most successful applications for the iPhone are things like fart jokes. The reality is that these successful tiny applications are not simply successful because the App Store is improperly structured–though this contributes. No, they are successful because people use the iPhone differently than they use laptop computers.
You see, most people use the phone in the following way:
(1) They pull it out of the pocket and press the “unlock” key.
(2) They tap a few keys. Perhaps they’re getting someone’s phone number, or placing a call, or pulling the finger.
(3) They then put it back into their pockets.
In other words, the tiny, non-immersive form factor combined with a non-existent setup time (as compared to laptops or desktops) means that most interaction with the phone is going to be a very quick cycle of “pull it out, ask a question, get an answer, put it back.”
Now there are times when people are using their phones for an extended period of time. But that extended period of time will stem from two sources. First, a user may be stuck on a subway or in an airport and have nothing to do–at which point they’ll use the phone as a source of entertainment. They’ll pull it out and watch a movie or TV show, or browse the web, or play a game. Because they’re in a circumstance where they’re killing time, however, the game or program should be able to save state quickly, and be entertaining immediately. A first person shooter that has no objective but quickly blowing people away makes more sense than a ‘capture the flag’ game or a game which takes some extended period of time to complete the level: you don’t know when the user will be back on the subway or stuck in an airport. And he may only be killing five minutes.
The second reason why a user will continue using an application (IMHO) is when he pulls it out, asks a question–then doesn’t get the answer he’s looking for, so re-asks the question in a different way. But this is not a good model of user interaction: the user is not interacting with your application because they’ve suddenly gone into an immersive interaction. They’re frustrated! because they’re not getting the answer they want.
Because of this, information-providing applications should provide information quickly. All the usual rules of computer-human interaction apply: 1/4th of a second is the longest delay between touching something and having it react. Two to four seconds is the longest delay for doing some computation–and during this time a spinning animation should be shown. If there is something that requires more time (such as getting the GPS location or hitting a server), a status display should be put up if this takes more than 5 seconds, letting the user know exactly what the software is doing. And if the entire interaction takes longer than perhaps 15 seconds, you better have a very good reason why–because chances are the user is going to flip the application off and put it away, unless he really needs the information.
But the bottom line is this: if your application provides information, it needs to work in a very quick cycle of “pull the phone out, ask a question, get an answer, put the phone away.” If you are designing your application to be an immersive environment or to function in any way other than in a “pull it out, ask a question, get an answer, put it away” loop, you’re designing your application for failure.
KISS in practice.
I was having a conversation with a co-worker, where I complained that the biggest problem with some of the code we’re working on is that it was over-engineered. I reminded him of Gall’s Law:
“A complex system that works is invariably found to have evolved from a simple system that worked. The inverse proposition also appears to be true: A complex system designed from scratch never works and cannot be made to work. You have to start over, beginning with a working simple system.”
He asked me a question about client-server interaction, and rather than shooting off a 140 character reply it seems to make sense to answer the question more fully here.
To summarize, we are building an application that communicates to a remote server using JSON over HTTP. The remote system is built on top of Drupal. (Honestly it’s not how I would have done it, because there seems to be too many moving parts already–but the folks who built the server assure me that Drupal is God, and who am I to complain?)
Now on an error there are several things that can go wrong. The remote server can return a 4xx or a 5xx HTTP error. It can return a JSON error. Or it could return an HTML formatted error (I guess they have some flag turned on which translates all remote errors into human-readable error messages.) The client is hardened against all of these return possibilities, of course, and is also hardened against a network failure or against a server being unresponsive.
So here’s the question: how should the client respond to these wide variety of errors?
On the server side, of course, there needs to be logging. We even do some device-level logging, and a mechanism is in place on our iPhone client to transmit that log in the background to the server if there is a problem. Because clearly from a developer’s perspective a 404 is not a 501 is not a 505 is not a “server is unresponsive” is not an “illegal character in the API” is not a “network down” error. So clearly we need to know what is going on so we can fix it.
But what does the end user need to know?
In my mind, handling this is very simple: what can the user affect?
In the case of a mobile device, the user can retry again later, or he can make sure he’s got good network reception. Period.
So in the event of a failure, the client’s behavior should be simple: if a connection fails, then test to see if the network is up. If the network is down, tell the user “I’m unable to talk to the remote server because your network is down.” And if the network is up, tell the user “Sorry, a problem occurred while talking to the server.”
And that’s it.
If the network is down, the user can try to turn it on: he can take the device out of airplane mode, or move to where he has reception, or turn on the WiFi. But it’s up to the user–we just have to tell him “Um, the network is down.” And let him decide how he wants to handle the problem–or even if he wants to handle the problem: it could be he clicked on our application while at 38,000 feet over the Atlantic.
If we can’t hit the server, but the network is up, then there is nothing the user can do about it. All we can do as software developers is make sure whomever is maintaining the servers that they should investigate the outage. All we can tell the user, however, is “sorry, no dice; try again later.”
And hope to hell our servers are reliable enough we don’t drive users away.
Making it more complex is silly. It doesn’t serve the user who may be stressed out by messages he can do nothing about anyway.
Managerial Abuse.
One of the most interesting comments I ever read in any documentation was something I encountered years ago in Apple’s documentation. It was a technical note discussing using the Apple Macintosh Toolbox, and the key point was essentially that you should not just follow the rules, but you should go the extra step and follow the “gestalt” of the rules. A similar technical note observed that you should not abuse certain managers and use them for functionality they were not designed to handle. Ultimately it was about writing code that not only used the API according to the letter of the law, but also used the API in a way which observed the spirit (and the underlying design goals) of the API.
I have found this in general to be very sound advise, and it amuses me greatly (in a sick and perverted way) to watch programmers stretch the rules because they thought something should be done one way, and suddenly their stuff stops working because their changes went against the grain of the design rules of the platform they’re writing code on.
The latest example: I’m working on a program which at one point needs to access web pages on the iPhone and display them. The developer I’m working with has some very strong ideas as to how the HTTP protocol should work–and apparently his strong ideas have little to do with common HTTP practice. For example, the two common ways to pass parameters to an HTTP server is (a) ‘GET’ parameters, and (b) ‘POST’ parameters in the body of the request. So what does he want to do? Put the parameters in the HTTP header as ‘X-company-xxx’ extensions. And he wants the iPhone to always send these parameters, even from the UIWebView class within the iPhone.
So how did he want to accomplish this feat?
On the iPhone every web request through UIWebView triggers a callback to the -shouldStartLoadWithRequest: delegate method to the UIWebView delegate. The parameter passed is a NSURLRequest.
But it turns out this is actually a NSMutableURLRequest when the user clicks on a link. So, his solution was to cast the NSURLRequest (as advertised in the interface) to an NSMutableURLRequest, verify that it responds to the setValue:forHTTPHeaderField: callback, then populate the new values he wants to send back:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)req navigationType:(UIWebViewNavigationType)navigationType
{
NSMutableURLRequest *request = (NSMutableURLRequest *)req;
if ([request respondsToSelector:@selector(setValue:forHTTPHeaderField:)]) {
[request setValue:@"myValue" forHTTPHeaderField:@"X-Company-parameter"];
}
return YES;
}
Upon reading the above, if your reaction is “hey, that’s pretty clever”, please leave your name and address in the comments section of my blog so I can make sure I never work with you ever, in any professional capacity. However, if your reaction was “ick”, then your reaction was the same as mine. It took two people to convince me to let it go–with my ultimate reaction being “hey, it’s your code. Just as long as you deal with it when it bites you in the end, go for it.”
And guess what? It bites you in the end. By overriding this method and manipulating the request, for whatever reason, map URLs (that is, http://maps.google.com URLs which would otherwise bring up the Apple Google map application) break in this situation.
Managerial abuse bites you in the ass in the end because you start making assumptions about how the underlying system works. And if the system doesn’t work that way, then a future revision to the operating system will break your application hard, and sometimes in very hard to detect ways.
And in this case, this story abused two things: (1) It abused a channel normally reserved for low-level client/server interaction to send information in HTTP that should otherwise be sent in the traditional way with GET or POST parameters, or that should otherwise be handled with cookies. (This abuse puts additional requirements on how client code should behave when interacting with a web site, and these other requirements may effectively pre-empt porting the client to operating systems which don’t provide a mechanism to stuff HTTP header fields on web browser initiated clicks.) (2) It abused an existing API by coercing a non-mutable object through pointer casting into a mutable object, assuming the underlying object will always be mutable.
Thus, life is made unnecessarily complex, and for no better reason than the fact that a developer wants to invent an ad-hoc standard outside of the “gestalt” or design guidelines of the existing spec–only so he can show off just how clever he can be.
Three Ways To Load A Nib. Only Two Work.
Someone I’m working with told me that you can load a NIB on the iPhone in the following way:
TestViewController *c = [[TestViewController alloc] initWithNibName:@"TestNib" bundle:[NSBundle mainBundle]]; [self presentModalViewController:c animated:YES];
However, this doesn’t appear to work. When chasing down the code, by the time TestViewController -(void)viewDidLoad gets called, self has changed; however, deep inside the lazy load of presentModalViewController the old pointer seems to be used because I get an exception indicating the view reference of the underlying UIViewController (that TestViewController descends from) was uninitialized.
There are two other ways to load the Nib.
First is using -(NSArray *)loadNibNamed:owner:options:
NSArray *a = [[NSBundle mainBundle] loadNibNamed:@"TestNib" owner:self options:nil]; TestViewController *c = [a objectAtIndex:0]; [self presentModalViewController:c animated:YES];
This seems to work, though the top level objects have been offset by one since v2.0 of the iPhone OS. (That is, this code will only work on v2.1 or later; if you build for v2.0 you must add one to the objectAtIndex index.)
The second way is the recommended way given in Apple’s documentation here:
// In my top level class
@interface TestRetainViewController : UIViewController
{
TestViewController *fController;
}
@property (nonatomic, retain) IBOutlet TestViewController *fController;
[[NSBundle mainBundle] loadNibNamed:@"TestNib" owner:self options:nil]; [self presentModalViewController:fController animated:YES];
This assumes there is a reference in the TestNib.xib file which points from the file owner object to the NIB.
One hitch about the second method, using an array: the array that is returned has a reference count of 1, but also has been set to autorelease. Thus you should either retain the array or the items in the array you want. The hitch about the third method, of course, is that because you’ve declared a property with retain semantics, you must also release the object on dealloc:
- (void)dealloc
{
[fController release];
[super dealloc];
}
You also can test to see if the NIB was already initialized in the call to loadNibNamed, however, in theory during NIB loading the reassignment to fController should release whatever was already loaded there before.
What tripped me up about the last project I worked on was that I was in such a rush to get very complicated NIBs built for an over-engineered UI, I created circular references and (more importantly) I wasn’t releasing any of the objects loaded via the NIB loading process. Turned out object connections on the iPhone are established using -setValue:forKey:, which does an automatic retain, and that means you need to release the reference in the -dealloc method.
What’s worse, if you don’t explicitly create the @property (or equivalent setXXX call according to the key/value rules, I believe simple assignment with retain is called–which means if you do multiple calls to loadNibNamed: above on TestNib but without the @property declaration, you’ll leak as each call simply overwrites the pointer.
Basking in the glow of the Mothership.
I have my WWDC ticket! Wahoo!
So you have an iPhone 3G and want to use the SIM on the Google Android dev phone.
The steps I found on the ‘net seems to work.
Remove the SIM card from your iPhone and insert it into the Google Android developer phone. When you start the phone for the first time, when the phone asks for your Google account, you need to press the menu button, and select “APN”. Add a new APN entry on the Dev phone with the following settings:
Name: att
APN: wap.cingular
Password: CINGULAR1
All other fields are left blank. Click menu, save, then work your way back to the login prompt, and sign in as usual.
It appears the good news is that once you get the phone set up, it will operate (albeit without phone or 3G wireless) without the SIM card, which makes the phone useful in a limited fashion for development. And if you do need to test the card on 3G, you can just move the SIM card back–though unfortunately it’s a real pain in the ass to extract the SIM card from the Google phone without tweezers. (On the other hand it’s impossible to remove from the iPhone without a pin, so I guess they’re even.)