Well, this is really old news by now. I wanted to post something about it earlier, but never seemed to find the time.
Apparently there was a mixup at MacTech magazine, and my two-part article on developing productivity applications was printed out of order. Part II came out in February's issue. I'm not sure whether Part I will follow in March.
However, there is an upside to this. The good folks at MacTech have released both articles in their entirety onto the web. So, I encourage you to check them out:
Part I: http://www.mactech.com/articles/mactech/Vol.25/25.03/iPhoneProductivityApplicationsPart1/
Part II: http://www.mactech.com/articles/mactech/Vol.25/25.02/iPhoneProductivityApplicationsPart2/
I'm also currently working on a third iPhone article, this time focusing on immersive apps, images and Quartz 2d.
-Rich-
Wednesday, February 25, 2009
Wednesday, February 4, 2009
Things that bug me about Objective-C (and iPhone development)
Ok, before I get started, don't get me wrong. Objective-C is still one of my favorite programming languages. But, as I continue to use it, I can't help but feel that it has some rough edges.
First, it has the same essential flaw as Java. It's not a pure Object-oriented language. There is this dichotomy between things that are objects and things that are not. For example, you cannot put a raw int or a c-style array into an NSArray--not without wrapping it first.
In some ways, this gives us a lot of power. We can drop down and write lower-level code when the performance demands require it. And, when working on a limited device (like the iPhone), those demands can be frequent. But I feel it's a bad design choice. It encourages mixing C and Objective-C, and I think the two programming styles are best kept separate.
I guess the biggest problem with Objective-C is really just C. Anytime I have to use C code, I loose many of the strengths and benefits of using Objective-C. I also expose myself to pointer and array-overrun errors. These are often the hardest to debug, since they may appear as mysterious errors in unrelated parts of the application.
And then we get to the iPhone. I love Xcode and I love the iPhone, but sometimes the two just don't play well together. Yes, debugger, I'm looking at you. I mean, really. What's up with the breakpoints? Sometimes they work. Sometimes they don't. Sometimes I can trick them into working again by cleaning all targets and rebuilding. Other times I have to reboot the computer. One time I could only fix the problem by reinstalling Xcode.
OK, that's it. Enough complaining for one day.
-Rich-
First, it has the same essential flaw as Java. It's not a pure Object-oriented language. There is this dichotomy between things that are objects and things that are not. For example, you cannot put a raw int or a c-style array into an NSArray--not without wrapping it first.
In some ways, this gives us a lot of power. We can drop down and write lower-level code when the performance demands require it. And, when working on a limited device (like the iPhone), those demands can be frequent. But I feel it's a bad design choice. It encourages mixing C and Objective-C, and I think the two programming styles are best kept separate.
I guess the biggest problem with Objective-C is really just C. Anytime I have to use C code, I loose many of the strengths and benefits of using Objective-C. I also expose myself to pointer and array-overrun errors. These are often the hardest to debug, since they may appear as mysterious errors in unrelated parts of the application.
And then we get to the iPhone. I love Xcode and I love the iPhone, but sometimes the two just don't play well together. Yes, debugger, I'm looking at you. I mean, really. What's up with the breakpoints? Sometimes they work. Sometimes they don't. Sometimes I can trick them into working again by cleaning all targets and rebuilding. Other times I have to reboot the computer. One time I could only fix the problem by reinstalling Xcode.
OK, that's it. Enough complaining for one day.
-Rich-
Wednesday, January 28, 2009
Lessons in iPhone Development
I've been spending a lot of time working on iPhone projects, and I've learned a couple of important lessons (the hard way).
1) Computationally intensive code runs slow on the iPhone. When it comes to raw number crunching, code ran 60 times slower on the iPhone than on my old MacBook Pro. If it takes one second on the simulator, it will need at least a minute on the phone.
Even worse, something that is so fast that you cannot even see it in the simulator may take several seconds to complete. This can cause all sorts of unexpected problems. The lesson here, test everything on the phone as early as possible.
2) The camera image picker is apparently designed to be used only once then thrown away. The photo library picker (even though they're the same class) doesn't seem to have this limitation.
I put both in tabbed windows, so the user could easily switch images. The user could return to the photo library picker as many times as they wished. However, the camera picker would only take a single picture, then it would only display the last picture taken. There seems to be no way to reset it.
Bottom line, use them as modal views and toss them. Instantiate a new picker the next time you need one.
3) Memory management is hard. Even when I thought I'd been careful, when I tested it in Instruments, I had leaks all over the place.
4) Using Objective-C serialization to save off large collections of objects can be very slow. Encoding the collection into a NSData object, then saving that can vastly improve performance. At least, it did for me.
I'm sure there's more, but that's all I can remember at the moment.
-Rich-
1) Computationally intensive code runs slow on the iPhone. When it comes to raw number crunching, code ran 60 times slower on the iPhone than on my old MacBook Pro. If it takes one second on the simulator, it will need at least a minute on the phone.
Even worse, something that is so fast that you cannot even see it in the simulator may take several seconds to complete. This can cause all sorts of unexpected problems. The lesson here, test everything on the phone as early as possible.
2) The camera image picker is apparently designed to be used only once then thrown away. The photo library picker (even though they're the same class) doesn't seem to have this limitation.
I put both in tabbed windows, so the user could easily switch images. The user could return to the photo library picker as many times as they wished. However, the camera picker would only take a single picture, then it would only display the last picture taken. There seems to be no way to reset it.
Bottom line, use them as modal views and toss them. Instantiate a new picker the next time you need one.
3) Memory management is hard. Even when I thought I'd been careful, when I tested it in Instruments, I had leaks all over the place.
4) Using Objective-C serialization to save off large collections of objects can be very slow. Encoding the collection into a NSData object, then saving that can vastly improve performance. At least, it did for me.
I'm sure there's more, but that's all I can remember at the moment.
-Rich-
Wednesday, October 22, 2008
Where does the model go in iPhone MVC Apps?
I've just finished debugging a iPhone demo application for an article. I ran into an interesting problem, however.
Apple's documentation strongly pushes using a Model-View-Controller design for iPhone applications. That's good. Having struggled to debug large applications that didn't use MVC, I definitely see the benefits.
Here, the application should be separated into three distinct partitions. Roughly speaking, the model controls the state. The view displays information to the user, and the Control manages the other two.
In my iPhone app, the views are built in Interface Builder. Each view has its own UIViewController. But, where should the model go? Where should it live? How do I connect it to my view controllers?
Here's the problem, most of the views are instantiated in my code. I can easily pass in the model when I instantiate the class. My root view, however, is instantiated by the nib, secretly and mysteriously in the background.
So far, the best solution I've found is to access the root view in my application delegate as follows:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
model = [[Model alloc] init];
id rootController = [navigationController visibleViewController];
[rootController setModel:model];
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];
}
This is not as clean as I'd like, but it's better than the other options I've come up with. In particular, there's an intriguing Proxy Object in interface builder, which sounds like an ideal solution--but I can't make it work and I haven't found any documentation on it yet.
If anyone out there has any suggestions, please let me know.
-Rich-
Apple's documentation strongly pushes using a Model-View-Controller design for iPhone applications. That's good. Having struggled to debug large applications that didn't use MVC, I definitely see the benefits.
Here, the application should be separated into three distinct partitions. Roughly speaking, the model controls the state. The view displays information to the user, and the Control manages the other two.
In my iPhone app, the views are built in Interface Builder. Each view has its own UIViewController. But, where should the model go? Where should it live? How do I connect it to my view controllers?
Here's the problem, most of the views are instantiated in my code. I can easily pass in the model when I instantiate the class. My root view, however, is instantiated by the nib, secretly and mysteriously in the background.
So far, the best solution I've found is to access the root view in my application delegate as follows:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
model = [[Model alloc] init];
id rootController = [navigationController visibleViewController];
[rootController setModel:model];
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];
}
This is not as clean as I'd like, but it's better than the other options I've come up with. In particular, there's an intriguing Proxy Object in interface builder, which sounds like an ideal solution--but I can't make it work and I haven't found any documentation on it yet.
If anyone out there has any suggestions, please let me know.
-Rich-
Tuesday, September 16, 2008
Last Time Machine Update
Ok, this is the last thing I'll say on the subject (probably).
Forget everything I've ever said about hosting Time Machine backups on a shared drive. Yes, it's technically possible. But, trust me. Don't do it. Just don't. It's not worth the heartache.
Go out and buy a Time Capsule. Wireless backups that actually work! I've been running mine for two months now, and I haven't had a single hiccup. Much, much better than the shared drive option.
-Rich-
Forget everything I've ever said about hosting Time Machine backups on a shared drive. Yes, it's technically possible. But, trust me. Don't do it. Just don't. It's not worth the heartache.
Go out and buy a Time Capsule. Wireless backups that actually work! I've been running mine for two months now, and I haven't had a single hiccup. Much, much better than the shared drive option.
-Rich-
Thursday, August 7, 2008
Object Lesson in Single Points of Failure
So, I bought my wife a new iPhone. Before we attached it to her computer, I decided to update all the software, and (of course) the machine choked and died. I tried everything I could think of, but I couldn't get it back up and running. We took it to the Genius Bar, and the genius in question tried everything he could think of. No luck. According to our tests, the hard drive was fine, but Leopard would not install properly.
I decided to re-partition and reformat the hard drive. But, before doing that, I wanted to make sure the user drive was backed up. I took the 500 G disk we were using for Time Machine backups and attached it directly to my wife's machine, and copied over her user directory. Then I partitioned, reformatted the disk and reloaded Leopard. Everything went well.
Until...
My lovely wife walked by, accidentally snagged her hand on the USB cable for the hard drive, and knocked it to the floor. Now it only fell a few feet onto soft carpet, but when I plugged it back in, it refused to mount and only made a strange clicking sound.
All our backups were on that drive. The time machine backups. The new backups I'd just made. Everything. All of it gone. Poof.
Now, I have secondary backups for my most important files. But, alas, my wife did not.
It's easy to feel over-confident when you have backups. But backups can fail. Whenever you only have a single copy of your data, even if it's only for a split second, you're at risk.
Lesson learned. It's not a new lesson, but one I seem to need to be reminded of from time to time. Single points of failure are bad.
-Rich-
I decided to re-partition and reformat the hard drive. But, before doing that, I wanted to make sure the user drive was backed up. I took the 500 G disk we were using for Time Machine backups and attached it directly to my wife's machine, and copied over her user directory. Then I partitioned, reformatted the disk and reloaded Leopard. Everything went well.
Until...
My lovely wife walked by, accidentally snagged her hand on the USB cable for the hard drive, and knocked it to the floor. Now it only fell a few feet onto soft carpet, but when I plugged it back in, it refused to mount and only made a strange clicking sound.
All our backups were on that drive. The time machine backups. The new backups I'd just made. Everything. All of it gone. Poof.
Now, I have secondary backups for my most important files. But, alas, my wife did not.
It's easy to feel over-confident when you have backups. But backups can fail. Whenever you only have a single copy of your data, even if it's only for a split second, you're at risk.
Lesson learned. It's not a new lesson, but one I seem to need to be reminded of from time to time. Single points of failure are bad.
-Rich-
Monday, August 4, 2008
Thoughts on Matlab
I've been using Matlab a lot at work lately.
Now, by all rights, this should be a language that I love. It's a dynamic, highly expressive language.
However, something about it just sets my teeth on edge.
To be fair, I think I can divide my complaints into two groups: issues that are my fault and issues that are the languages fault.
Matlab treats everything as matrices. OK, that's a bit of an exaggeration, but not much of one. More to the point, Matlab works best when you are performing operations on an entire vector or matrix at once--rather than iterating over the data and performing the operation on each element individually.
A lot of the built in functions and operations are designed to work across entire matrices. In fact, these functions often operate equally well on scalar values or matrices. For example,
Personally, I think this obfuscates the code. It's often difficult to tell wether we're looking at scalar, vector or matrix operations. Still, I'm willing to accept this as my own personal issue. Indeed, it is part of a larger weakness on my part. Basically, I have trouble decomposing problems into matrix operations.
OK, it's easy to do on simple cases. But, lets say I'm building a neural network. I'm storing my weights in matrices. Now, I want to minimize the amount of iterating that I'm doing--but I often have trouble seeing the opportunities to parallelize my operations. It can be done. I've built my neural network code, and I've spent a considerable amount of time replacing iterations with matrix operations. But, I don't find it a natural-feeling way to code.
One of my co-workers has commented that I write Matlab code like I'm writing Java. I think that statement shows, not only my lack of Matlab skills, but her weaknesses in Java. I can tell you without hesitation, my Matlab code is nothing like my Java code. But, the underlying criticism still stands. I am often fighting against the language, not working with it.
I see a lot of people doing this with languages I love, and I get incredibly frustrated when they then unfairly criticize those languages. So, I'll accept the blame here, and try to do better in the future.
I do think there are some real issues, however. First off, the language is often inconsistent. For example, in
Also, the environment seems a bit buggy. For example, with a single-processor machine, it is incredibly easy to put your code into an infinite loop that locks up your computer. On a dual-core, this is less of a problem, since I can ctrl-c my way to freedom, but on a single core, Matlab grabs control and won't let go.
Also, the IDE doesn't have many of the features we've come to expect from a modern development environment. There's a taste of debugging and profiling, but they are not as useful as other environments. The IDE lacks any real refactoring tools, and I haven't found any tools for running unit tests.
Finally, I don't like the way it organizes the code. Basically, each function must be in its own file. Yes, you can include multiple private, helper functions within a file, but they cannot be called from the outside. Also, I often want to test my helper functions, so I need to place them in their own file anyway, at least during development.
This really limits my ability to keep my code base organized. In other languages, I can have files of related functions, and folders of related files. Matlab removes one entire dimension. Yes, I can still group similar functions into a hierarchy of folders--and put those folders in other folders, and so on and so forth. Then I need to remember to add the entire tree to my path. It just feels really clunky to me.
So, the take-home message is this, Matlab is a great language for doing mathematical exploration of ideas and building quick prototypes, but it lacks the software engineering tools needed to build robust, large-scale projects.
-Rich-
Now, by all rights, this should be a language that I love. It's a dynamic, highly expressive language.
However, something about it just sets my teeth on edge.
To be fair, I think I can divide my complaints into two groups: issues that are my fault and issues that are the languages fault.
Matlab treats everything as matrices. OK, that's a bit of an exaggeration, but not much of one. More to the point, Matlab works best when you are performing operations on an entire vector or matrix at once--rather than iterating over the data and performing the operation on each element individually.
A lot of the built in functions and operations are designed to work across entire matrices. In fact, these functions often operate equally well on scalar values or matrices. For example,
X < Y could be two scalar values (in which case, it will return 0 for false or 1 for true), or it could be two, equal-sized matrices (in which case, it will return a matrix of 0s and 1s). Personally, I think this obfuscates the code. It's often difficult to tell wether we're looking at scalar, vector or matrix operations. Still, I'm willing to accept this as my own personal issue. Indeed, it is part of a larger weakness on my part. Basically, I have trouble decomposing problems into matrix operations.
OK, it's easy to do on simple cases. But, lets say I'm building a neural network. I'm storing my weights in matrices. Now, I want to minimize the amount of iterating that I'm doing--but I often have trouble seeing the opportunities to parallelize my operations. It can be done. I've built my neural network code, and I've spent a considerable amount of time replacing iterations with matrix operations. But, I don't find it a natural-feeling way to code.
One of my co-workers has commented that I write Matlab code like I'm writing Java. I think that statement shows, not only my lack of Matlab skills, but her weaknesses in Java. I can tell you without hesitation, my Matlab code is nothing like my Java code. But, the underlying criticism still stands. I am often fighting against the language, not working with it.
I see a lot of people doing this with languages I love, and I get incredibly frustrated when they then unfairly criticize those languages. So, I'll accept the blame here, and try to do better in the future.
I do think there are some real issues, however. First off, the language is often inconsistent. For example, in
X < Y, the X and Y could be either scalar or matrix values. However, X && Y must be scalars. If you want to do logical operations on matrices, you must use and(X, Y). To me, this makes no sense. Why should logical operations be different than comparisons?Also, the environment seems a bit buggy. For example, with a single-processor machine, it is incredibly easy to put your code into an infinite loop that locks up your computer. On a dual-core, this is less of a problem, since I can ctrl-c my way to freedom, but on a single core, Matlab grabs control and won't let go.
Also, the IDE doesn't have many of the features we've come to expect from a modern development environment. There's a taste of debugging and profiling, but they are not as useful as other environments. The IDE lacks any real refactoring tools, and I haven't found any tools for running unit tests.
Finally, I don't like the way it organizes the code. Basically, each function must be in its own file. Yes, you can include multiple private, helper functions within a file, but they cannot be called from the outside. Also, I often want to test my helper functions, so I need to place them in their own file anyway, at least during development.
This really limits my ability to keep my code base organized. In other languages, I can have files of related functions, and folders of related files. Matlab removes one entire dimension. Yes, I can still group similar functions into a hierarchy of folders--and put those folders in other folders, and so on and so forth. Then I need to remember to add the entire tree to my path. It just feels really clunky to me.
So, the take-home message is this, Matlab is a great language for doing mathematical exploration of ideas and building quick prototypes, but it lacks the software engineering tools needed to build robust, large-scale projects.
-Rich-
Subscribe to:
Posts (Atom)