Wednesday, June 30, 2010

Modern ABI & No More @Synthesize

I haven't talked about one of my favorite new features of Xcode 4 and LLVM, because I wasn't sure of the NDA status. However, the cat's out of the bag now, so I feel like it's safe to mention. The iPhone Simulator in Xcode 4 now uses the Modern ABI (yet it's still correctly uses 32-bit datatypes!), so we can use synthesized instance variables in our iPhone applications and use the simulator. On top of that, if you choose to use LLVM instead of GCC, one of the (many) benefits you'll get is that @synthesize declaration is now assumed. If you don't need to specify anything on the @synthesize declaration (like a different setter or getter name) and your property isn't @dynamic, you can justleave it off. This feature isn't turned on by default (yet), but see Pilky's blog post for instructions on enabling this feature.

Less code to write? Boo-yeah! Count me in!

I believe (though I haven't confirmed this yet) that you can write code this way and still target older releases back to 3.0. If anyone knows otherwise, please let me know and I'll spread the word, though.

Monday, June 28, 2010

Code As If…

Sorry for how slow things have been here lately; I'm still suffering from WWDC work backlog, plus I've been spending a lot of time on the new book. This is the first book I've tried to write while also doing full-time client work and it's taking a bit of a toll on me.

I've had a blog post floating around my head since writing Beginning iPhone Development that has never become completely formed. It's about how the process of writing about code has changed the way I write code. I think the thoughts are finally ready to congeal into solid form. So, here goes.

The other day, I saw somebody wearing a T-shirt that said "Dance Like Nobody's Watching". I'm not much of a dancer, but I like the sentiment. However, dancing is not coding. The worst thing you can do is code like nobody's watching. You should code like everybody's watching you.

One thing I noticed after I'd been writing code for public consumption for a while is that I've become much more critical of my own code than I was before I started putting it out there for the world to see. A lot of that comes from pure vanity - I want to minimize the number of stupid mistakes that people are going to call me out on. There are a lot of eyes on the code I write for books and for this blog, and some of those eyes belong to people who are, quite frankly, smarter than me.

It's impossible to always put out perfect code, but I do like to avoid giving the impression of being a sloppy coder or, worse, of being a complete hack. The process I go through with code that goes into a book or blog post goes something like this:
  1. Make it work
  2. Make it work well
  3. Make it read well
The process isn't quite as linear as that makes it look, but that works as a very basic statement of the process. The last step includes the idea of refactoring, but it includes more than that. It's proofreading my code after I'm happy with the way it functions in order to look for ways the code could be written better. I'm not talking about performance here, that goes under #2. This is purely about maintainability and readability. Are my methods and variables using logical names? Is my code easy to read? Is the formatting consistent? Was I being lazy anywhere and doing quick copy and paste coding. Step 3 is about trying to be my own worst critic. You wouldn't send a proposal or other written document out without proofreading it. Your code shouldn't be any different.

I thought that I would revert back to my old ways when I wasn't writing code for public consumption, but it turns out that once acquired, this habit is hard to shake. Frankly, like most developers, I had always assumed that the third step, or at least the more picayune aspects of it, were a waste of time when doing production work.

That hasn't turned out to be true in my experience. In fact, it's been quite the opposite. In almost every case, I spend less time writing code because my code is now more readable, more precise, and generally quite a bit shorter than the way I used to write code. Every time I have to change, fix, or extend existing code, I spend less time doing it, and those little bits add up over the course of even a short job. In the log run, all those little things pay huge dividends.

Here's an example I was working on this weekend for OpenGL ES 2.0 for iOS 4. I'm putting together an Objective-C class to make creating and managing multiple programs and shaders in OpenGL easier. One piece of functionality I wanted to include was the ability to get the program and shader logs out of OpenGL. Without that information, it's awfully hard to identify why a shader won't compile or a program won't link. The end result of my first two steps ("Make it work", "Make it work well"), was this:

- (NSString *)vertexShaderLog
{
GLint logLength = 0, charsWritten = 0;

glGetShaderiv(vertShader, GL_INFO_LOG_LENGTH, &logLength);

if (logLength > 0)
{
char *log = malloc(logLength);
glGetShaderInfoLog(vertShader, logLength, &charsWritten, log);
NSString *ret = [[NSString alloc] initWithBytes:log
length:logLength
encoding:NSUTF8StringEncoding
]
;
free(log);
return ret;
}


return @"No Log Data";
}

- (NSString *)fragmentShaderLog
{
GLint logLength = 0, charsWritten = 0;

glGetShaderiv(fragShader, GL_INFO_LOG_LENGTH, &logLength);

if (logLength > 0)
{
char *log = malloc(logLength);
glGetShaderInfoLog(fragShader, logLength, &charsWritten, log);
NSString *ret = [[NSString alloc] initWithBytes:log
length:logLength
encoding:NSUTF8StringEncoding
]
;
free(log);
return ret;
}


return @"No Log Data";
}

- (NSString *)programLog
{
GLint logLength = 0, charsWritten = 0;

glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);

if (logLength > 0)
{
char *log = malloc(logLength);
glGetProgramInfoLog(program, logLength, &charsWritten, log);
NSString *ret = [[NSString alloc] initWithBytes:log
length:logLength
encoding:NSUTF8StringEncoding
]
;
free(log);
return ret;
}


return @"No Log Data";
}

It was obvious, even as I was writing this code that I wasn't going to leave it like this. You can get away with this kind of unnecessary duplication of code in most projects because it functions fine and most clients and many development managers don't have the technical chops to read your code, but it violates the DRY principle something fierce. This is hardly the worse example of copy-and-paste coding I've ever seen, but code like this shouldn't ever go into production.

I tested this code to make sure the methods worked, then I immediately refactored the two shader log methods by adding a private method declared in an extension. I then changed the two existing methods to simply call the private method, so I was then using the same code for both scenarios.

- (NSString *)shaderLogForShader:(GLuint)shader
{
GLint logLength = 0, charsWritten = 0;

glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);

if (logLength > 0)
{
char *log = malloc(logLength);
glGetShaderInfoLog(shader, logLength, &charsWritten, log);
NSString *ret = [[NSString alloc] initWithBytes:log
length:logLength
encoding:NSUTF8StringEncoding
]
;
free(log);
return ret;
}


return @"No Log Data";
}

- (NSString *)vertexShaderLog
{
return [self shaderLogForShader:vertShader];
}

- (NSString *)fragmentShaderLog
{
return [self shaderLogForShader:fragShader];
}

- (NSString *)programLog
{
GLint logLength = 0, charsWritten = 0;

glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);

if (logLength > 0)
{
char *log = malloc(logLength);
glGetProgramInfoLog(program, logLength, &charsWritten, log);
NSString *ret = [[NSString alloc] initWithBytes:log
length:logLength
encoding:NSUTF8StringEncoding
]
;
free(log);
return ret;
}


return @"No Log Data";
}

That's definitely better than the original version. I got rid of the obvious duplication between the two nearly identical shader log methods. The only difference between the original two methods was the GLuint (unsigned integer) value passed into the two OpenGL ES function calls.

This code still bothered me, though. Look how similar the shader and program log functionality is. It's identical except for the two function calls and, I realized, those two function calls take exactly the same parameters. It had been a while since I had used them, so it took my brain a few seconds to drudge up how C function pointer worked, but once it did, the path for refactoring this code became obvious. A single method could be used for all three of these cases if I took function pointers to the two OpenGL API calls as method parameters.

Now, this second refactoring is one a lot of people would probably say isn't worth the hassle. It's too much. It doesn't pass a "cost-benefit analysis". The result is not going to be that much shorter, so how can you justify the time? I used to think exactly the same way before spending so much time writing code for public consumption, but now I've become convinced that refactoring like this does pass the cost-benefit analysis. I wasn't putting enough weight on the value of good code when doing that analysis. When you come back to code weeks, months, or years later, you won't remember all the little details. With well-written code, you won't have to.

The truth (in my experience, at least) is that refactored code is enough easier to maintain that it's worth taking the time to do it. Like everything, the more you do it, the better you get at it, and the faster you can do it. Eventually, it becomes second nature. You end up writing better code in roughly the same amount of time that you used to write sloppy-but-functional code. Plus, every time you visit that code in the future, you have a little less code to search through. Whenever you have to debug that code, you have a little less code to step through. Every time you fix the code, you have less code to fix.

If I had an error in the original version of these log functions, I would almost certainly have the same exact error in three places. When I discovered such an error, do you think I would remember to fix it in all three places? Maybe, if I wrote the code recently enough to remember. If somebody else were fixing my code, do you think they'd know they had to fix it in three places? Maybe… but more likely they wouldn't.

Here's the final version of the method I settled on for the book¹:

typedef void (*GLInfoFunction)(GLuint program, GLenum pname, GLint* params);
typedef void (*GLLogFunction) (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog);

- (NSString *)logForOpenGLObject:(GLuint)object
infoCallback:(GLInfoFunction)infoFunc
logFunc:(GLLogFunction)logFunc
{
GLint logLength = 0, charsWritten = 0;

infoFunc(object, GL_INFO_LOG_LENGTH, &logLength);

if (logLength > 0)
{
char *log = malloc(logLength);
logFunc(object, logLength, &charsWritten, log);
NSString *ret = [[NSString alloc] initWithBytes:log
length:logLength
encoding:NSUTF8StringEncoding
]
;
free(log);
return ret;
}


return @"No Log Data";
}

- (NSString *)vertexShaderLog
{
return [self logForOpenGLObject:vertShader
infoCallback:(GLInfoFunction)&glGetShaderiv
logFunc:(GLLogFunction)&glGetShaderInfoLog
]
;

}

- (NSString *)fragmentShaderLog
{
return [self logForOpenGLObject:fragShader
infoCallback:(GLInfoFunction)&glGetShaderiv
logFunc:(GLLogFunction)&glGetShaderInfoLog
]
;
}

- (NSString *)programLog
{
return [self logForOpenGLObject:program
infoCallback:(GLInfoFunction)&glGetProgramiv
logFunc:(GLLogFunction)&glGetProgramInfoLog
]
;
}


Now, if you work for somebody else, especially if you work in a large corporation, you may be measured on a series of metrics including something like "Lines of Code Written" (LOC). While I understand the need for accountability, most corporate metrics are (to be blunt) a bullshit abuse of statistics. The absolute worst metric ever devised is LOC. If you're working somewhere that's still in the coding dark ages and measuring you by LOC, run like hell, or at least lobby for a change in that policy. Measuring performance based on LOC encourages even good engineers to write sloppy, horrible code.

In my example here, I spent some of my time improving my code by removing 25 lines of code. I spent time taking it from 64 lines of code down to 39 lines of code. As an developer, I shouldn't be punished for doing that!

In real-life situations, we often convince ourselves that there's not time for refactoring while we code. After all, we have to make that deadline, and there's always a deadline! We can always come back and refactor the code later when we have more time, right?

Only you won't. You won't come back until you absolutely need to, and by that point, it'd probably be faster to rewrite it. If you work for somebody else, they're unlikely to let you go back and spend time "fixing" something that works perfectly well. That's especially true if you have a non-technical manager. Besides, you'll probably be onto your next deadline already and feeling time pressure all over again.

In the long run, good code is worth the time it takes. Often, it's worth it in the short run as well.

Make time to refactor, and not after the fact make it part of your development process. Do it up front, before it goes to test, because you won't come back. Proofread your code before you ever send out a build.

Or, in other words, code as if everyone was able to see and understand your code.

Addendum


There's another point I want to make. Not only should you code as if there were lots of eyes on your code, you should actually get lots of eyes on your code if you can. You will miss stuff even if you make proofreading and refactoring part of your development process. You will sometimes even miss stupid stuff. Case in point, I got an e-mail shortly after posting this from Brent Simmons of NetNewsWire fame. Brent very kindly took the time to proofread the code and pointed out one bug and several improvements that could be made.

Here are his suggestions:
  1. Return early if logLength < 1, so that the main functionality doesn't have to be indented.
  2. Return an autoreleased string, per Apple's coding conventions
  3. Return nil in the case of no log data, rather than a string that would have to be compared to determine if there was log data or not.
  4. Change the name of the char * and NSString variables to something slightly more meaningful. (Since the method is logForSomething, it returns a variable named log.)
I absolutely agree with every single one of these suggestions and am a little embarrassed about leaking the string, to be perfectly honest. Here's Brent's rewrite of my function that I plan to use in the book (with Brent's permission):

- (NSString *)logForOpenGLObject:(GLuint)object 
infoCallback:(GLInfoFunction)infoFunc
logFunc:(GLLogFunction)logFunc
{
GLint logLength = 0, charsWritten = 0;

infoFunc(object, GL_INFO_LOG_LENGTH, &logLength);
if (logLength < 1)
return nil;

char *logBytes = malloc(logLength);
logFunc(object, logLength, &charsWritten, logBytes);
NSString *log = [[[NSString alloc] initWithBytes:logBytes
length:logLength
encoding:NSUTF8StringEncoding
]
autorelease]
;
free(logBytes);
return log;
}


Thanks, Brent!


1 This may, of course, change if my tech reviewer finds an issue with it

Saturday, June 19, 2010

WWDC 2010 Post Mortem

WWDC. The Dubdub. Christmas in June.

If you've followed this blog for any length of time, you know Apple's annual developer conference is my absolute favorite week of the year, and it just seems to get better every year. For the days leading up to leaving for San Francisco, I'm like a kid on Christmas eve. I can't sleep from excitement and the time passes way too slowly.

Every year, there are less "must-see" technical sessions for me, personally. That was especially true this year because something like 60% of the attendees were first timers who haven't shipped their first app yet and the session schedule was designed accordingly, with quite a few beginner and intermediate level sessions. But WWDC is so much more than the sessions (and those come out on video anyway). Your first year or two attending, it's all about the sessions, but by this point for me, it's about the sessions that focus on new technologies, labs and, most importantly, a chance to catch up with people I only see once or twice a year. Well, it wasn't just new technology sessions. For obvious reasons, I also attended all of the OpenGL ES sessions this year, and they were great. They were much deeper technically than last year, and were much more focused on the OpenGL ES 2.0 programmable pipeline.

Even thought it was the same number of attendees as the last two years (5,200 attendees plus the various engineers and other staff), this year felt way busier than past years. Lines to get into sessions were often very long, and many sessions filled up. Some even filled up an overflow room. Although we've seen long lines for sessions going back to the introduction of the iPhone, it's never been like this year. Last year, for example, for the State of the Union addresses, I meandered into the overflow room ten minutes late and found a seat in one of several empty rows. This year, I sat on the floor of the overflow room for the overflow rooms. I guess that's good - people were serious about learning this year.

One negative aspect of the massive influx of newbs this year was a certain loss of etiquette. I've always been super impressed by the way my fellow WWDC geeks treat the staff and the facilities. I've never seen garbage left around or more than isolated cases of people being rude to the catering or cleaning staff. This year, unfortunately, that respect was somewhat lacking. During the keynote line, hundreds of people just left their litter laying around on the floor. It was really disgusting and I was embarrassed at that moment to be part of the group. And it didn't end with the keynote line, either, unfortunately. I saw many examples of people not bothering to pick up after themselves, or being rude to the staff. Even a few instance of people being rude to Apple engineers who were trying to help them with problems. I almost feel like I need to add a few items to my annual first timer's guide with things I had assumed any decent person would already know, like throw out your garbage, treat people with respect, and be nice to people who are trying to help you.

Let's be better next year, okay? Almost everybody I met or talked to seemed like super people, so I'm hoping this was just a one-time anomaly. I really, really would like it to be an isolated occurrence. Enough said on that topic.

Although the new iPhone 4 was the belle of the keynote ball, the real buzz at WWDC this year, as you probably know by now, was Xcode 4. For the first time in history, Apple has released the session videos to all registered developers for free, so if you haven't done so yet, you should go watch the Developer Tools State of the Union and the handful of Xcode 4 sessions. Apple's Developer Tools teams have been working really hard for quite a long time on this upcoming release, and even in the early preview state it's in, I already wish I could use it full-time. Fortunately, the Xcode team foresaw this and they made the project file format 100% backwards and forwards compatible between Xcode 3 and Xcode 4, so I can work in Xcode 4 then switch to Xcode 3 to do my ad hoc and release builds.

Honestly, one of my favorite parts of this particular WWDC was having the opportunity to buy a few rounds of drinks for some of the engineers who worked on Xcode 4. I'm not sure if those engineers have forgiven me yet, so I'm not going to call them out by name, but it's important to me during WWDC to show my appreciation to as many as I can of the people who make all the cool stuff I work with everyday. Steve Jobs gets a lot of credit, and rightly so, but he doesn't do it alone. It was really nice to see him call out some of the people who worked on iPhone 4 and iOS 4 during the keynote, but there are a lot of unsung heroes working at Apple, and most of them don't get a lot of recognition for teh awesome they bring. WWDC is the one week a year where we get to show our appreciation in person.

The User Experience lab appeared to be the biggest hit among the labs this year. Each morning, within minutes of the Moscone West doors opening up, there was a long line extending around the corner waiting for the UX lab to open. People waited in line literally for hours to get a UX review. I guess word got out this year about how good those reviews were. I know I saw several people raving about them last year. In general, I think people have really started to grok the fact that the labs represent an incredible opportunity to get questions answered by the people who really know the answers. If you're having a problem or an issue with a certain part of the system, likely you can find someone who actually works on that part of the system to answer your questions.

As for MartianCraft, we gave out all of our away team shirts pretty quickly this year. Sorry to those who wanted one but didn't get one. We way underestimated demand for the shirts and just didn't have enough with us to give them to everyone who wanted one. We'll be better prepared next year, and we're looking into making the shirts available online for anybody who's interested, but that probably won't happen until we've dug ourselves out from the hole that got created as a result of all three of us not working for a week.

Thursday, June 17, 2010

Grand Slam!

Apple has set a new record for WWDC video avialability this year, getting them out not even a week after the event ended. Amazing.

Even more amazing, they're not selling them this year. Registered developers can access them for free. Want to know what all the fuss is about with Xcode 4? Go watch the videos.

Monday, June 14, 2010

Announcing OpenGL ES 2.0 for iOS 4

Okay, it's finally time for me to announce Super Secret Project B, which is a new book I'm writing on OpenGL ES 2.0 for iPhone, iPad, and iPod touch.

Yes, I know I said I wouldn't be writing any books in 2010, but the nice folks at the Pragmatic Programmers approached me after I made that statement with an economically feasible way for me to write a book this year. I couldn't say no.

My original plan had been to take my OpenGL ES from the Ground Up blog posts, supplement them, and turn them into a book with step-by-step projects to reinforce the points of each posts. My week at WWDC has caused me to change that approach. I went to all the OpenGL ES sessions and spent a fair amount of time bending the ear of Allan Schaffer, Apple's Graphics and Games Evangelist, as well as a number of Apple engineers who work on or with OpenGL. After a lot of hard thought, I came to the conclusion that the approach needed to change. Although modern hardware supports the fixed pipeline, Apple has stopped making phones that require OpenGL ES 1.1. The iPhone 3GS, iPhone 4, and iPad all not only support OpenGL ES 2.0, but they all require it if you want to take full advantage of the hardware.

OpenGL ES from the Ground Up, however, focused on the OpenGL ES 1.1 fixed pipeline.

Since OpenGL ES doesn't maintain backward compatibility the way workstation OpenGL does, much of the material from the fixed pipeline, such as lights, the model view and projection matrix, and the stock functions for submitting vertex, texture, and normal data are all gone from OpenGL ES 2.0. Instead, you have to handle all that work manually when you write your shaders. Shaders add some complexity to the process, but give you a tremendous amount of power and the ability to write more efficient OpenGL code.

In the Desktop world, it still makes sense to learn immediate mode first, then regular fixed pipeline, and then finally the programmable pipeline, because workstation OpenGL maintains nearly 100% backwards compatibility across releases, and you can get up and running quickly. On Workstation OpenGL ES, you can even mix and match the different modes, accessing the model view matrix and lights from your shaders. That's not the case with OpenGL ES, so spending a few hundred pages teaching things that won't be applicable to the programmable pipeline seemed like a poor use of time, both mine, and my readers'.

But, for the new programmer, the programmable pipeline is really hard to grok. I've been banging my head this past week looking for a way to present that rather complex topic in a way that people without prior graphics or OpenGL ES experience will be able to understand.

Thanks to a lot of people willing to talk with me, I think I've come up with an approach that will work, and I'm really excited about it. So, if you find OpenGL ES confusing, especially if you find the programmable pipeline and shaders confusing, look out for OpenGL ES 2.0 for iOS4. I don't have a release date yet, but I will post here when I have updated information about the production schedule.

Tuesday, June 8, 2010

WWDC 10 Update

Well, we're well into the second day at WWDC and it is, as always, amazing, exhilarating, exhausting and, most of all, fun.

Unfortunately, there's not a heck of a lot that I can report on. Other than the keynote yesterday, which was heavily covered by both liveblogs and technical media. The iPhone 4 looks amazing. I haven't seen it myself, but I've talked to several people who have and without exception they just gush over the it, especially the screen.

But there's stuff going on here that's got me so much more excited than even the new phone. A lot of really smart people at Apple have been working very, very hard to give developers some really cool stuff and I just wish I could share it, because they really wowed me and many others I've talked to.

It's an exciting time to be an iPhone iOS developer.

Update: Okay, it's Xcode 4, it's not available to non-attendees, but it has been announced, so I can say what it is that has wowed us. Apple has completely revamped the developer tools with a new workflow. The current beta is still unfinished, but it's extremely impressive.

Friday, June 4, 2010

MartianCraft Away Team

red_shirt_tease.png

This is a teaser photo of part of the MartianCraft T-shirt that Rob designed for WWDC. We've got a small assortment of these to give away at WWDC. We haven't yet figured out how we're going to decide who gets to be red-shirts on our Away Team, but we'll get it figured out before Monday, and hopefully it won't require you to embarrass yourself too badly.

I'll post some more pictures as we get closer to WWDC.

Thursday, June 3, 2010

Briefs Rejected by the App Store

Rob Rhyne explains what's going on with Briefs, his iPhone-based prototyping tool. Unfortunately, it's not good news.

Oh, Hey! I'm Teaching Again.

banner.png

I'm teaching up with Julio Barros of E-String Technologies to hold a three-day iPhone SDK programming workshop in New York City the week after WWDC. The class starts on Wednesday, June 16 and runs through Friday June 18. No prior iPhone programming experience is required, though some prior programming knowledge and a general understanding of C-style syntax is recommended.

Almost WWDC

wwdc-2010.pngWell, it's the Thursday before WWDC and, as always, I'm swamped yet super-excited. The Pre-WWDC Pilgrimage is all planned. If you expressed interest, you should have received an e-mail with the details about how to pay if you want to take the bus.

I shy away from making predictions before big events because I don't have any inside information and I'm likely to be more wrong than right with anything but the safest predictions (like a new model iPhone being announced). However, I do think there's something big this year that hasn't leaked yet. Something completely unexpected. Chances are, if there is, it will leak the night before the keynote. The number of people who find out about new projects increases exponentially in the 24 hours leading up to the actual presentation, and leaks become nearly impossible to prevent at that point, but I have a gut feeling there's something we haven't heard about yet, but I haven't the foggiest idea what it might be.

Of course, I think a new iPhone model is almost a foregone conclusion, and perhaps some moderate hardware refreshes on the Mac side, though I think the focus of this WWDC is clearly going to be the iPhone OS. We might see a price drop, speed bump, or something similar on the Mac side, but I don't think we're going to see any Mac line completely refreshed or much time devoted to the Mac in the keynote. It's within the realm of possibility that the Mac Mini, which is sorely overdue, or the Mac Pro, which is also sorely overdue, to get revamped, but probably not. I expect Steve to spend a fair amount of time giving us details about how many iPhones and iPads have been sold, how many applications have been downloaded, and whatnot. I expect to hear more about GameCenter and to see some silly montage about some developer's success story with the App Store.

I've seen rumors about a iPhone OS-based AppleTV. Maybe. Steve's comments at D8 might have been the sort of mis-direction he's known for, and the AppleTV is definitely in need of a refresh if it's going to continue being sold, but I think Steve was telling the truth about the subsidized TV box market, so if there is an AppleTV refresh, it's going to be combined with something else: a partnership, new business model, or something that will make it a viable, profitable product.

Steve will almost certainly have us watch a new commercial, either for the new iPhone or some other new product. If he's really excited about it, he'll make us watch it twice.

For the most part, I really don't care what gets announced. The incredible interest in the iPad and growth of the iPhone as a platform already provide me with more to explore than I have time for. I'm looking forward to sitting in the RDF on Monday with 6,000 other Apple geeks. It's an extraordinary experience watching Jobs work, especially in person. He's a master showman, and my only complaint about the last few Stevenotes has been all the time he's given to third party developers who lack his presentation skills. I really do hope there's more Steve and less awkward third-party developers on stage this year, though I suspect the format will be similar to previous years.

Last year, I didn't do the Keynote line-thing. I visited with people in the line much of the morning because I was still on East Coast time, but then I went back to my hotel and had breakfast, then went back over to Moscone West just before 10:00. This year, however, I'm going to do the early-morning geeky wait-in-line thing. My fellow Martian Rob is attending his first WWDC and I feel like the line is something you have to do your first time, and I don't him to do it alone. Besides, it is fun. And, hey, maybe there will be strippers again, because strippers never seem out of place at a developer conference, especially walking around at 6:00 in the morning in 55° weather wearing bikinis and high heels, right?

If you're going to WWDC and want to say hi, the best way to find me is to follow me on Twitter. I spend most of the day at Moscone West and am pretty easy to find. If I'm not in a session, I usually park at a table to work and tweet my whereabouts.

Monday, May 31, 2010

Accessorizer 2.0 is out!

acc_saw_clock_icon_512_version14.pngAccessorizer by Kevin Callahan is one my absolute favorite utilities, as I've mentioned before. Well, now, there's a new reason to love it. Kevin just released 2.0 over the weekend. And there's great news for those of you who have bought previous versions: it's a free upgrade.

If you do any serious amount of Objective-C programming, Accessorizer should definitely be in your toolbox.

Friday, May 28, 2010

Core Data and Threading

I've had a number of people ask me lately about the best way to handle using Core Data in a multi-threaded application. I began to put together a tutorial and sample code based on Apple's documentation, which advises to pass NSManagedObjectIDs between threads to get around the fact that threads can't share instances of NSManagedObjectContext or NSManagedObject. I've used this approach in several projects and it works.

While googling around doing research, however, I came across a post by Marcus Zarra on the Mac Developer Network.

Marcus knows Core Data really well, having written a book on the topic, so I figured I'd take a look at what Marcus had to say on the matter. I'm glad I did. Marcus illustrates a really great approach in his post that obviates the need to pass ManagedObjectIDs around between the thread in many situations. You still need to do that if you need to pass a specific object between threads, but if you're doing something like loading or creating managed objects in the background to be displayed in a table, this is so much easier and better.

I won't spoil the surprise, but it's a handy tool for your Core Data toolkit. If you have any thought about using Core Data in a multi-threaded application, you should definitely check it out.

Wednesday, May 26, 2010

The Martian Invasion: Announcing MartianCraft

About four months ago, I joined together with my friend and co-author, Dave Mark and with Rob Rhyne, developer of the awesome Briefs prototyping tool, to form a new mobile software development company specializing in the iPhone and Android platforms. This software development firm is what I've somewhat cryptically been referring to "Super Secret Project A"¹, but its real name can now be revealed as: MartianCraft.

Our original plan had been to do a public announcement long before now, but something unusual (yet good) happened. Before we ever made our announcement, before we ran our first advertisement, before the ink was even dry on our incorporation papers, we got busy. Really, really busy. Our little covert, unannounced software development firm kept us too busy for the first few months to take on new clients. Even finding time to do all the various things that a new business needs to have done was quite a challenge.
Screen shot 2010-05-25 at 7.37.56 PM.png
Having now finished two relatively major projects and a number of smaller ones, we've now got a chance to catch our breath and get all our ducks in a row. We've even got business cards (well, they're coming soon, at least) and some T-shirts to wear at WWDC. We may even have a few extra of those to give out.

We also have something else: the bandwidth to take on a new client or two. If you're looking to have an iPhone, iPad, or Android application developed, or if you've got an existing application in need of a little help drop us a line! We're also available for onsite training, code and architecture reviews, weddings, bar mitzvahs, and bachelor parties! Well, maybe not the last few.

1 Super Secret Project B will be revealed shortly after WWDC, so stay tuned!

Monday, May 24, 2010

Downloading Images for a Table without Threads

It is common practice in many networking libraries in many languages to spawn threads to handle asynchronous communications in the background while the rest of the program continues to function. Although this approach does work on the iPhone, it's really not the right way to do it. I've recently run across two different blog postings that show how to download images for display in an iPhone table view, and they both did synchronous network communications using threads.

Here's my Public Service Announcement for today: Don't. Please… just, please don't, okay? Don't spawn threads for asynchronous communications unless you would have used threads in the same situation if there was no network code..
Note: A few people have suggested that this post is misleading because threads are used behind the scenes. Yes, it is true that the iPhone OS will spawn a small number of non-main threads as the result of using certain networking APIs. You still should be using the asynchronous APIs for your network communications and should not be spawning threads so you can make synchronous networking calls without blocking.
I don't like to knock other people's tutorials. In programming, there are multiple ways of doing nearly everything, and often more than one approach has merit in certain situations, so I'm always hesitant to say that the approach someone else uses is "wrong" if it works. But, this is one of those cases where there is a clear and compelling reason not to do it one particular way. However, because the "right" way is not necessarily intuitive, especially for people whose networking experience has all been thread-based, I thought it worth a short tutorial to show how to download asynchronously for display in a table without spawning any threads.

But first, why shouldn't we use threads this way? Well, simply put, threads have overhead. It's not a huge overhead, but it's non-zero and, in fact, it's non-trivial given the processing power and physical memory available on iPhone OS devices. The overhead of threading absoulutely makes sense in some situations; asynchronous networking is not one of those situations. Apple provides asynchronous APIs specifically for this purpose and they're designed to give the best performance in light of available system resources.

But, don't take my word for it. Here is what Apple says on the matter, in a guide written to help Windows programmers make the transition to programming for the Mac (emphasis mine):
One of the complexities of socket use involves the use of separate threads to handle the exchange of data. In a server environment, where hundreds of sockets are open simultaneously, the code that checks all these threads for activity may cause a significant performance hit. In addition, with threads, data synchronization is often an issue, and locks are often required to guarantee that only one thread has access to a given global variable at a time.

[...]

Event-driven code is more complex than code using blocking threads, but it delivers the highest network performance. When you use a run loop to handle multiple sockets in the same thread, you avoid the data synchronization problems associated with a multiple-thread solution.
When Apple says something as specific as this, they usually have a darn good reason for it. This is Apple's polite way of saying "don't use threads for networking, you idiot". They're a lot more polite than I am, obviously.

As you probably know, your application's main thread (the one that gets created automatically when your application is launched) has a loop (contained in UIApplication) that's always running. It's called your application's run loop and it keeps running as long as your application is executing. Every time through this loop, UIApplication does a whole bunch of stuff. It checks for inputs from the hardware and mach messages from the OS, for example, and it looks to see if there are any NSTimers running whose targets need to be called. Among the tasks it does is to check for incoming network data. There are more things the run loop handles, but that last one is the important for today's discussion.

Conceptually speaking, CFNetwork is not the easiest framework to grasp, but it is extremely efficient. It can handle hundreds, maybe even thousands of simultaneous downloads without causing the main thread to seize up. It's considerably more efficient than using synchronous network calls on a thread and not really any harder once you know how to do it.

Let's Try Downloading on the Main Thread



I've written a small iPhone app that downloads images from Deviant Art. You just enter somebody's Deviant Art username into a text field and the application will grab the the images in that person's gallery, download them asynchronously, and display each one in the table once it's finished downloading:

Screen shot 2010-05-24 at 4.28.42 AM.png

Notice that there's an activity indicator showing that some images are in the process of being downloaded. This is all happening on the main thread. I spawn no explicit threads in this application, and yet the UI stays responsive. You can also tap a row to view the image larger, but that's not really important to the process being illustrated.
Note:Although most DeviantArt galleries are SFW, there are many that aren't, so just be aware of that. Edit: Turns out that warning was unnecessary - since we haven't authenticated, DeviartArt filters out all the NSFW images automatically.

Creating the Download Object


In your own applications, you may approach things somewhat differently, but for this sample application, I'm going to put the code to download the image in its own data model class called DeviantDownload. I'm going to override the accessor method for the image so that the first time that accessor is called, it will kick off the download. If I call the image accessor method and get nil, the calling code can make itself the download's delegate to get notified when the download finishes.

In this application, downloads don't get triggered until the first time an image scrolls onto the screen. That may not be what you want in your application, but it will keep things nice and simple for this example. Here's the declaration of our download class:

#import <Foundation/Foundation.h>

#define DeviantDownloadErrorDomain @"Deviant Download Error Domain"
enum
{ DeviantDownloadErrorNoConnection = 1000,
}
;

@class DeviantDownload;
@protocol DeviantDownloadDelegate
- (void)downloadDidFinishDownloading:(DeviantDownload *)download;
- (void)download:(DeviantDownload *)download didFailWithError:(NSError *)error;
@end



@interface DeviantDownload : NSObject
{ NSString

*urlString; UIImage

*image; id <NSObject, DeviantDownloadDelegate> delegate;

@private NSMutableData

*receivedData; BOOL

downloading;
}

@property (nonatomic, retain) NSString *urlString;
@property (nonatomic, retain) UIImage *image;
@property (nonatomic, readonly) NSString *filename;
@property (nonatomic, assign) id <NSObject, DeviantDownloadDelegate> delegate;
@end


Pretty straightforward, right? I define an error domain and an error code for the one error situation our application generates (the rest come from NSURLConnection). After that, I declare a protocol that defines the methods our delegate has to implement. There are only two: one that gets called when the download finishes successfully, and another that gets called if it fails. In the sample application, our error checking is minimal, but you will do real error checking in your apps, right? RIGHT?! Yes, you will, because that's the way you roll. In a real app, you might also add a third delegate method that to inform the delegate what percentage of the download is complete, but I'll leave that one as an exercise for the student.

Next, I declare the DeviantDownload object, which only has four instances variables, one of which is private. urlString is the url of the image to download, image is the downloaded image, and delegate is the object that wants to get notified about the status of the download. Finally, receivedData is just a buffer to hold the downloaded data until I have it all and can create the image from it.

Okay, let's look at the implementation of our download object:

#import "DeviantDownload.h"

@interface DeviantDownload()
@property (nonatomic, retain) NSMutableData *receivedData;
@end


@implementation DeviantDownload
@synthesize urlString;
@synthesize image;
@synthesize delegate;
@synthesize receivedData;
#pragma mark -

- (UIImage *)image
{
if (image == nil && !downloading)
{
if (urlString != nil && [urlString length] > 0)
{
NSURLRequest *req = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:self.urlString]];
NSURLConnection *con = [[NSURLConnection alloc]
initWithRequest:req
delegate:self
startImmediately:NO]
;
[con scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSRunLoopCommonModes
]
;
[con start];



if (con)
{
NSMutableData *data = [[NSMutableData alloc] init];
self.receivedData=data;
[data release];
}

else
{
NSError *error = [NSError errorWithDomain:DeviantDownloadErrorDomain
code:DeviantDownloadErrorNoConnection
userInfo:nil
]
;
if ([self.delegate respondsToSelector:@selector(download:didFailWithError:)])
[delegate download:self didFailWithError:error];
}

[req release];

downloading = YES;
}

}

return image;
}

- (NSString *)filename
{
return [urlString lastPathComponent];
}

- (void)dealloc
{
[urlString release];
[image release];
delegate = nil;
[receivedData release];
[super dealloc];
}

#pragma mark -
#pragma mark NSURLConnection Callbacks
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[receivedData setLength:0];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[receivedData appendData:data];
}

- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
[connection release];
if ([delegate respondsToSelector:@selector(download:didFailWithError:)])
[delegate download:self didFailWithError:error];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
self.image = [UIImage imageWithData:receivedData];
if ([delegate respondsToSelector:@selector(downloadDidFinishDownloading:)])
[delegate downloadDidFinishDownloading:self];

[connection release];
self.receivedData = nil;
}

#pragma mark -
#pragma mark Comparison
- (NSComparisonResult)compare:(id)theOther
{
DeviantDownload *other = (DeviantDownload *)theOther;
return [self.filename compare:other.filename];
}

@end


To make memory management more readable, I first declare a property for receivedData in a class extension. This creates a property that is accessible in my class but that isn't advertised to other classes. After that, I synthesize the four properties (three public declared in the header and one private declared in extension)

The first method I've written is an accessor for image. Remember, @synthesize creates an accessor and mutator if one doesn't already exist in your code, so by providing an accessor but not a mutator, @synthesize will create a mutator for me, but will use this method as its accessor. I don't want to download more than once, so I use the instance variable downloading to keep track of whether I've already kicked off a download. If image is nil and I haven't previously kicked off a download, I kick one off asynchronously.

At the end of the method, I return image, even though it will still be nil until the download is complete. That's okay, that will be the calling code's indication that they should become the download's delegate.

The next method, filename just returns the last part of urlString, which is the filename. I don't want to display the whole URL in the table.

The dealloc method is pretty standard stuff, so we can skip it.

The next four methods are the asynchronous callbacks for NSURLConnection. The first, connection:didReceiveResponse: is called when a connection is made. I set the length of receivedData to zero here because if there's a redirect, this will get called multiple times and I want to flush out the payload from the earlier redirected connections. That extra data, when it exists, would prevent our image from being created.

connection:didReceiveData: gets called periodically during the download, whenever there's data sitting in the buffer for us. All I do here is tack the newly received data onto the end of what's already been received.

In connection:didFailWithError:, I release the connection and notify our delegate. Because this is a data model object, I don't show an alert or anything. Dealing with the error isn't this object's responsibility. Once it reports it, its job is done; it'll let the controller figure out what to do with the error. This keeps our object firmly in the "model" component of the MVC paradigm and maximizes the chances I'll be able to reuse this object at some point.

Finally, in connectionDidFinishLoading:, I create an image from the received data, assign it to the image property and notify our delegate.

The last method, compare: is implemented to let us determine if two DeviantDownload objects represent the same file. I'll use this to look at two downloads and see if they are downloading the same file, which we don't want to do. Deviant Art uses a server farm to serve images, so the same image can have multiple URLs, but for a particular user, the filename must be unique, so I compare that.

Using the Download Object


In the table view controller, I pull down a list of the URLs for the given user. I'm not going to go into detail of the logic that does this, but in short, I asynchronously pull down JSON data for the user's gallery in chunks of 24 images, creating new DeviantDownload objects for each one and adding them to the NSMutableArray that drives our table. In our tableView:cellForRowAtIndexPath:, here's what I do:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{

DeviantDisplayCell *cell = (DeviantDisplayCell *)[tableView dequeueReusableCellWithIdentifier:[DeviantDisplayCell reuseIdentifier]];
if (cell == nil)
{
[[NSBundle mainBundle] loadNibNamed:@"DeviantDisplayCell" owner:self options:nil];
cell = loadCell;
self.loadCell = nil;
}

DeviantDownload *download = [downloads objectAtIndex:[indexPath row]];
cell.cellLabel.text = download.filename;
UIImage *cellImage = download.image;
if (cellImage == nil)
{
[cell.cellSpinner startAnimating];
download.delegate = self;
}

else
[cell.cellSpinner stopAnimating];

cell.cellImageView.image = cellImage;
return cell;
}


The first part of this method is standard table view cell stuff, but then I grab the DeviantDownload object for the row being displayed. If the image accessor method returns nil, I show the cell's activity indicator (aka "spinning wait-a s-cond doohickey") and assign the controller as the delegate of the download. If the object doesn't return nil, I make sure the activity indicator isn't animating and stick the download's image into the cell's image view. The first time this gets called for any particular row, image will return nil, which will trigger the download to start.

I also implement the DeviantDownload delegate method that gets called when the download is complete:

- (void)downloadDidFinishDownloading:(DeviantDownload *)download
{
NSUInteger index = [downloads indexOfObject:download];
NSUInteger indices[] = {0, index};
NSIndexPath *path = [[NSIndexPath alloc] initWithIndexes:indices length:2];
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:UITableViewRowAnimationNone];
[path release];
download.delegate = nil;
}


All I do here is figure out the index of the object that I've been notified has finished download and I build an index path based on it. I then tell the table to reload that one cell's row. Doing that will trigger tableView:cellForRowAtIndexPath: to get called again for the row that has completed and this time that method will get a valid image and will stop the activity indicator and show the downloaded image instead.

Ta da! That's it. It's really not any harder than using threads or NSOperationQueue once you get a feel for using the run-loop based approach.

If you want to try it out, you can download the full project right here. As always, the code is free for use without any restrictions or limitations, I'd just ask that you don't republish it unchanged and claim credit for it.

 
Design by Wordpress Theme | Bloggerized by Free Blogger Templates | coupon codes