For those of you having trouble running the application, I've also added i386 to the supported architectures. Because of my use of blocks, Snow Leopard is required to run the app.
Ipod Touch Review
# # 8 GB capacity for about 2,000 songs, 10,000 photos, or 10 hours of video # Up to 40 hours of audio playback or 7 hours of video playback on a single charge # Support for AAC, Protected AAC (iTunes Store) and other audio formats; H.264, MPEG-4,
Ipod Touch Review
# One-year limited warranty # iPod touch has 8 GB capacity for about 2,000 songs, 10,000 photos, or 10 hours of video. # iPod touch has a 3.5-inch (diagonal) widescreen Multi-Touch display with 960-by-640-pixel resolution (326 pixels per inch). › See more technical details.
Ipod Touch Review
# iPod touch has one-year limited warranty. # IPod touch plays up to 40 hours of audio playback or 7 hours of video playback on a single charge. # Motion JPEG video codecs in M4V, MP4, MOV, and AVI formats
Tampilkan postingan dengan label Cocoa. Tampilkan semua postingan
Tampilkan postingan dengan label Cocoa. Tampilkan semua postingan
Sabtu, 30 Oktober 2010
Tile Cutter Updated
Had to re-tile a large image, so spent a bit of time converting tile cutter to use NSOperationQueue. After a little playing, I opted for one operation per row, which seems to give the best all-around performance for the widest variety of images. You can download the latest version from here, or pull the source from GitHub.
For those of you having trouble running the application, I've also added i386 to the supported architectures. Because of my use of blocks, Snow Leopard is required to run the app.
For those of you having trouble running the application, I've also added i386 to the supported architectures. Because of my use of blocks, Snow Leopard is required to run the app.
Kamis, 14 Oktober 2010
Outlets, Cocoa vs. Cocoa Touch
I almost always follow Apple's lead on Cocoa and Cocoa Touch conventions. I figure that by the time outside developers like me see something for the first time, Apple engineers have been living with that thing for many months, so they've likely got a much better idea than I do about the best way to use that new thing.
But, after spending time with their stuff, sometimes — not often, but sometimes — I disagree with what appears to be Apple's recommended "best practice" for doing something. I think I've come to the decision that the IBOutlet behavior in iOS is one of these areas.
If you look at Apple's documentation snippets and sample code, you find that they almost always retain IBOutlet properties, like:
There's a good reason for this. In iOS, the documentation explicitly states that you need to retain all outlets because the bundle loader for iOS autoreleases all objects created as a result of loading a nib.
This is different from Cocoa on the Mac, where it wasn't necessary to retain outlets and people rarely did. In fact, we didn't usually bother with accessor or mutator methods for outlets (it was just unnecessary extra typing in most cases), we just put the IBOutlet keyword in front of the instance variable and the nib loader was happy to attach our outlets like that, retaining the objects that needed retaining.
The behavior under Cocoa/Mac is not actually to retain everything in the nib, but rather, to retain any object that doesn't have a parent object to retain it. So, in other words, if an object in a nib will be retained by something else, like a superview, the nib loader doesn't bother to retain it again. But, if it doesn't, the bundle loader retains it so that it doesn't get deallocated.
This is a logical approach and, in fact, was necessary back in the pre-Objective-C 2.0 days because outlets back then were just iVars and there was no easy way for the controller class to retain objects that needed to be retained.
I have to wonder why they would change the fundamental behavior of a foundation object like NSBundle between Mac OS and iOS? NSBundle is not part of Cocoa or Cocoa Touch, it's part of Foundation, and the whole point of Foundation is to have common objects between the different operating systems.
I wrote a small project to test if the Bundle Loader really did behave differently, as documented, by using an instance of UIView in the nib with no superview. Sure enough, when I didn't retain the outlet, I either got an EXC_BAD_ACCESS or a different object altogether when I printed the outlet to NSLog(). The difference is real. The bundle loader on the Mac will retain outlets for you if they need to be retained, which allows you to continue using instance variables, or properties with the assign keyword. This means you don't have to release your outlets in dealloc and you don't have to mess around with anything like viewDidUnload on iOS.
The bundle loader on the iOS, on the other hand, does not retain anything for you, so if an object does not have a parent object to retain it, you have to retain it in your controller class or you will end up with an invalid outlet.
I really don't see the value in changing this behavior. I'm guessing the decision was made for the sake of memory efficiency in the early days of the iPhone. The idea being that you might load a nib with object instances that you aren't actually using, and with the old behavior, those would take up memory as long as the nib was loaded. That doesn't necessarily sound like a good idea on an embedded device with no virtual memory and 128 megs of RAM, which is what the original iPhone and iPhone 3G had.
Despite that, I think the cure here is worse than the disease. If you don't remember to release your outlets in viewDidUnload (which, if I remember right, we couldn't even do in the 2.0 version of the SDK), your outlets will continue to use up memory after the nib is unloaded, obviating any advantage of the lazy loading. Essentially, it's more fragile, because it depends on the programmer doing the right thing and there are few if any situations where a programmer would need to not do the right thing.
By virtue of the bundle loader not retaining outlets, it also requires more rote, boilerplate code to be written in every controller class in every iOS application, yet it runs just as much of a risk of unnecessary memory use, arguably a greater risk. In other words, the cure is no better than the disease.
iPhones are getting more robust and less memory constrained with every new device that comes out. I would argue that it's already time (or, at very least, soon will be time), to bring the behavior of the two bundle loaders together. If they are brought together, they should be brought together using the old Cocoa behavior not the new iOS behavior. When you think of the number of people coding for the iOS now, those extra required dealloc and viewDidUnload lines in every single controller class in every single iOS application are really adding up to a lot of engineering hours lost on boilerplate.
A few weeks ago, I started experimenting with using assign instead of retain for IBOutlets except in cases where the outlet's object didn't have a superview or another object retaining it. If an outlet's not a view or control, then I also use retain. In essence, I'm mimicking the old behavior of the nib in designing my controller classes.
This has led to a lot less typing and less code to maintain because 95% or more of the outlets I create are connected to objects retained by their superview during the entire existence of the controller class.
Now, I'm not necessarily saying you should do what I'm doing. It can be tricky, at times, remembering which objects need to be retained and they can be hard to debug if you get it wrong. Apple has made a recommendation with good reason and I don't think you should disregard that recommendation lightly. That being said, if you're comfortable enough with Objective-C memory management and the bundle loader to be able to distinguish when a nib object will be automatically retained by something else, you could save yourself a fair bit of typing over time.
I normally try to embrace changes Apple makes, but in this case, I just can't convince myself that this was a good change. The old nib behavior of retaining only things that need retaining has been in use for over 20 years, dating back to when desktop computers were less powerful than our iPhones are, and there doesn't appear to be any practical advantage to the change. On the other hand, we'd all benefit from going back to the old Mac OS bundle behavior because we'd have less make-work to do when setting up a controller class. There's also little danger in changing this behavior because code that follows Apple's current recommendations would continue to work correctly.
But, after spending time with their stuff, sometimes — not often, but sometimes — I disagree with what appears to be Apple's recommended "best practice" for doing something. I think I've come to the decision that the IBOutlet behavior in iOS is one of these areas.
If you look at Apple's documentation snippets and sample code, you find that they almost always retain IBOutlet properties, like:
#import <UIKit/UIKit.h>
@interface FooView : UIView
{
}
@synthesize (nonatomic, retain) IBOutlet UIButton button;
@synthesize (nonatomic, retain) IBOutlet UITextField textField;
@synthesize (nonatomic, retain) IBOutlet UIImageView imageView;
@end
There's a good reason for this. In iOS, the documentation explicitly states that you need to retain all outlets because the bundle loader for iOS autoreleases all objects created as a result of loading a nib.
Objects in the nib file are created with a retain count of 1 and then autoreleased. As it rebuilds the object hierarchy, however, UIKit reestablishes connections between the objects using the setValue:forKey: method, which uses the available setter method or retains the object by default if no setter method is available. If you define outlets for nib-file objects, you should always define a setter method (or declared property) for accessing that outlet. Setter methods for outlets should retain their values, and setter methods for outlets containing top-level objects must retain their values to prevent them from being deallocated. If you do not store the top-level objects in outlets, you must retain either the array returned by the loadNibNamed:owner:options: method or the objects inside the array to prevent those objects from being released prematurely.
This is different from Cocoa on the Mac, where it wasn't necessary to retain outlets and people rarely did. In fact, we didn't usually bother with accessor or mutator methods for outlets (it was just unnecessary extra typing in most cases), we just put the IBOutlet keyword in front of the instance variable and the nib loader was happy to attach our outlets like that, retaining the objects that needed retaining.
The behavior under Cocoa/Mac is not actually to retain everything in the nib, but rather, to retain any object that doesn't have a parent object to retain it. So, in other words, if an object in a nib will be retained by something else, like a superview, the nib loader doesn't bother to retain it again. But, if it doesn't, the bundle loader retains it so that it doesn't get deallocated.
This is a logical approach and, in fact, was necessary back in the pre-Objective-C 2.0 days because outlets back then were just iVars and there was no easy way for the controller class to retain objects that needed to be retained.
I have to wonder why they would change the fundamental behavior of a foundation object like NSBundle between Mac OS and iOS? NSBundle is not part of Cocoa or Cocoa Touch, it's part of Foundation, and the whole point of Foundation is to have common objects between the different operating systems.
I wrote a small project to test if the Bundle Loader really did behave differently, as documented, by using an instance of UIView in the nib with no superview. Sure enough, when I didn't retain the outlet, I either got an EXC_BAD_ACCESS or a different object altogether when I printed the outlet to NSLog(). The difference is real. The bundle loader on the Mac will retain outlets for you if they need to be retained, which allows you to continue using instance variables, or properties with the assign keyword. This means you don't have to release your outlets in dealloc and you don't have to mess around with anything like viewDidUnload on iOS.
The bundle loader on the iOS, on the other hand, does not retain anything for you, so if an object does not have a parent object to retain it, you have to retain it in your controller class or you will end up with an invalid outlet.
I really don't see the value in changing this behavior. I'm guessing the decision was made for the sake of memory efficiency in the early days of the iPhone. The idea being that you might load a nib with object instances that you aren't actually using, and with the old behavior, those would take up memory as long as the nib was loaded. That doesn't necessarily sound like a good idea on an embedded device with no virtual memory and 128 megs of RAM, which is what the original iPhone and iPhone 3G had.
Despite that, I think the cure here is worse than the disease. If you don't remember to release your outlets in viewDidUnload (which, if I remember right, we couldn't even do in the 2.0 version of the SDK), your outlets will continue to use up memory after the nib is unloaded, obviating any advantage of the lazy loading. Essentially, it's more fragile, because it depends on the programmer doing the right thing and there are few if any situations where a programmer would need to not do the right thing.
By virtue of the bundle loader not retaining outlets, it also requires more rote, boilerplate code to be written in every controller class in every iOS application, yet it runs just as much of a risk of unnecessary memory use, arguably a greater risk. In other words, the cure is no better than the disease.
iPhones are getting more robust and less memory constrained with every new device that comes out. I would argue that it's already time (or, at very least, soon will be time), to bring the behavior of the two bundle loaders together. If they are brought together, they should be brought together using the old Cocoa behavior not the new iOS behavior. When you think of the number of people coding for the iOS now, those extra required dealloc and viewDidUnload lines in every single controller class in every single iOS application are really adding up to a lot of engineering hours lost on boilerplate.
A few weeks ago, I started experimenting with using assign instead of retain for IBOutlets except in cases where the outlet's object didn't have a superview or another object retaining it. If an outlet's not a view or control, then I also use retain. In essence, I'm mimicking the old behavior of the nib in designing my controller classes.
This has led to a lot less typing and less code to maintain because 95% or more of the outlets I create are connected to objects retained by their superview during the entire existence of the controller class.
Now, I'm not necessarily saying you should do what I'm doing. It can be tricky, at times, remembering which objects need to be retained and they can be hard to debug if you get it wrong. Apple has made a recommendation with good reason and I don't think you should disregard that recommendation lightly. That being said, if you're comfortable enough with Objective-C memory management and the bundle loader to be able to distinguish when a nib object will be automatically retained by something else, you could save yourself a fair bit of typing over time.
I normally try to embrace changes Apple makes, but in this case, I just can't convince myself that this was a good change. The old nib behavior of retaining only things that need retaining has been in use for over 20 years, dating back to when desktop computers were less powerful than our iPhones are, and there doesn't appear to be any practical advantage to the change. On the other hand, we'd all benefit from going back to the old Mac OS bundle behavior because we'd have less make-work to do when setting up a controller class. There's also little danger in changing this behavior because code that follows Apple's current recommendations would continue to work correctly.
Selasa, 19 Januari 2010
Greatly Exaggerated
Several people today tweeted a link to this blog post from John Casasanta of Tap Tap Tap about the death of Mac software. It's an interesting, post, and I'm having trouble deciding if I agree with it or not. I don't want to agree, that's for sure, but there are many valid points made.
My gut reaction, though, from which the title of this post is derived, is to paraphrase Mark Twain by saying the rumors of the Mac Software industry's death have been greatly exaggerated.
One of the assertions in John's post is that iPhone developers don't want to go back and develop for the Mac because the iPhone SDK is "shiny" while Cocoa is "old and crufty". I can't speak for any iPhone developers but me, but I really would like to spend more time with Cocoa. In the nearly two years since I jumped on board the iPhone ship, a lot of really cool things have happened to Cocoa, many of which aren't available to us on the iPhone yet. Blocks, GCD, and OpenCL mean that there are huge opportunities for new Mac applications, and mature garbage collection and instance variable synthesis mean even shorter development times. Heck, there are huge opportunities just to compete with and replace existing consumer applications, never mind for writing new applications. Can you imagine a Photoshop competitor that fully leveraged these new technologies1? Larger companies like Adobe with huge Carbon-based codelines have quite a challenge ahead of them getting their older applications to be 64-bit clean and running on Cocoa, which is a requirement for leveraging much of the cool new stuff. The large corporate software powerhouses are floundering in terms of modernizing their mainstay apps. To say there's not an opportunity there seems wrong to me. It may not be as easy or convenient of an opportunity as represented by the App Store, but there's definitely opportunity.
The Mac's market share is also higher than it's been at any time in at least ten or fifteen years and it seems to be trending up. In terms of actual installed base size, there are more people using Macs than ever in history. Even among people who don't use or like the Mac, the realization that it's not a "toy" operating system is slowly dawning on even the most ignorant of Apple haters. Well, okay, maybe not the most ignorant, but certainly everyone else.
More people are using Mac, so it's hard to imagine how the Mac Software market can be dwindling. If it is, it's likely a failure to take advantage of the opportunities that do exist. Perhaps we're all blinded by the bright, shiny App Store. Maybe stuff's not selling because there's not enough being written or marketed. Maybe we're all still buying into the gold rush stories subconsciously.
There's no doubt that the App Store is a rousing success and that it makes it far easier to reach customers, but hardly every iPhone developer is making a great living at this. TapTapTap is one of the great success stories, and the view from that perspective is very different from the the perspective of developers I've talked to who haven't recouped even enough to have made minimum wage for their time investment in their application. More than one iPhone developer are are looking for greener pastures, though many are having trouble finding one.
I do agree with John on many of the points in his post, however. I agree that it would be great if Apple opened up the App Store to Mac applications, but also agree that it seems unlikely that Apple will do it because they wouldn't have the same level of control. I also sincerely hope that John and I are both wrong on that. I find it odd that I can go into iTunes and buy movies, music, iPhone apps, and even donate to the Red Cross, but I can't buy Mac apps there. I can't even buy Apple's own Mac apps there like iWork and iLife. Last year, I ordered the latest version of iWork, both a single license for my business and a five-license family pack for home. I was able to just buy a serial number for the individual license, but for the family pack, I had to have a box shipped across the country to me. There's something wrong with that picture. I should have been able to just go into iTMS, specify the licenses I needed, then have the software download to my machine automatically. By now, we should have just as seamless and smooth of a buying experience for Mac applications as we do for movies, music, television shows, and mobile apps.
Even without a Mac App Store, though, opportunity is there in the Mac software world. In some ways, the opportunities are better than they've ever been because the potential audience is larger than ever and many of the people who are qualified to create quality Cocoa apps are myopically focused on the iPhone right now. Yes, there's more work involved with Mac apps. You'll have to find a distribution path. You'll have to advertise. You'll have to arrange a payment mechanism. But there are so many targets begging for a good competitor right now, and so many new as-yet uncreated markets that can now exist because of the amount of processing power we can easily leverage in Cocoa. There are many big, slow, corporate-owned, Carbon-based crappy-ass apps that keep making money because they have tons of cash to advertise and because there isn't a viable alternative or, at least, people aren't aware that there is a viable alternative.
We all started on a level playing field in the iPhone nearly two years ago. In fact, it wasn't even level at the start; smaller companies and individuals had the advantage of agility. Hell, a large corporation like Adobe or EA can't decide to enter a new market in the time that some of the earliest iPhone applications were designed, developed, and shipped. Heck, a large corporation often can't even decide who should decide to enter a new market in the time that many iPhone apps were written. TapTapTap was smart enough and capable enough to take advantage of that opportunity, but people entering the iPhone market today have to compete with the big names and the established small names.
Even though the distribution situation is considerably better on the iPhone than on the Mac, the overall competitive landscape really isn't all that different when you look at the market as a whole. How many of the top-ten grossing games right now are titles from big-name companies? Usually, it seems to run between seven and ten of the top ten are big-name titles. On the other hand, what percentage of successful Mac titles are produced by independents? I have to believe it runs at least 10-30%, and I would guess it runs higher.
I don't see the markets as being nearly as different as John does for somebody starting from ground zero today. There are differences, certainly, but there's plenty of room for success — and failure — in both markets.
1- Actually, I can. A couple of years ago, I abandoned Photoshop for Acorn, which is a native Cocoa image editor that rocks. There are a few features that some design professionals might need that it doesn't have (e.g. CMYK support), but what it does, it does so much faster than Photoshop CS4 that it's not even a close race, and yet it costs a fraction of what Photoshop costs. And think about this: Acorn is mostly written by one person. Compare that with the names in Photoshop's dialog box.
My gut reaction, though, from which the title of this post is derived, is to paraphrase Mark Twain by saying the rumors of the Mac Software industry's death have been greatly exaggerated.
One of the assertions in John's post is that iPhone developers don't want to go back and develop for the Mac because the iPhone SDK is "shiny" while Cocoa is "old and crufty". I can't speak for any iPhone developers but me, but I really would like to spend more time with Cocoa. In the nearly two years since I jumped on board the iPhone ship, a lot of really cool things have happened to Cocoa, many of which aren't available to us on the iPhone yet. Blocks, GCD, and OpenCL mean that there are huge opportunities for new Mac applications, and mature garbage collection and instance variable synthesis mean even shorter development times. Heck, there are huge opportunities just to compete with and replace existing consumer applications, never mind for writing new applications. Can you imagine a Photoshop competitor that fully leveraged these new technologies1? Larger companies like Adobe with huge Carbon-based codelines have quite a challenge ahead of them getting their older applications to be 64-bit clean and running on Cocoa, which is a requirement for leveraging much of the cool new stuff. The large corporate software powerhouses are floundering in terms of modernizing their mainstay apps. To say there's not an opportunity there seems wrong to me. It may not be as easy or convenient of an opportunity as represented by the App Store, but there's definitely opportunity.
The Mac's market share is also higher than it's been at any time in at least ten or fifteen years and it seems to be trending up. In terms of actual installed base size, there are more people using Macs than ever in history. Even among people who don't use or like the Mac, the realization that it's not a "toy" operating system is slowly dawning on even the most ignorant of Apple haters. Well, okay, maybe not the most ignorant, but certainly everyone else.
More people are using Mac, so it's hard to imagine how the Mac Software market can be dwindling. If it is, it's likely a failure to take advantage of the opportunities that do exist. Perhaps we're all blinded by the bright, shiny App Store. Maybe stuff's not selling because there's not enough being written or marketed. Maybe we're all still buying into the gold rush stories subconsciously.
There's no doubt that the App Store is a rousing success and that it makes it far easier to reach customers, but hardly every iPhone developer is making a great living at this. TapTapTap is one of the great success stories, and the view from that perspective is very different from the the perspective of developers I've talked to who haven't recouped even enough to have made minimum wage for their time investment in their application. More than one iPhone developer are are looking for greener pastures, though many are having trouble finding one.
I do agree with John on many of the points in his post, however. I agree that it would be great if Apple opened up the App Store to Mac applications, but also agree that it seems unlikely that Apple will do it because they wouldn't have the same level of control. I also sincerely hope that John and I are both wrong on that. I find it odd that I can go into iTunes and buy movies, music, iPhone apps, and even donate to the Red Cross, but I can't buy Mac apps there. I can't even buy Apple's own Mac apps there like iWork and iLife. Last year, I ordered the latest version of iWork, both a single license for my business and a five-license family pack for home. I was able to just buy a serial number for the individual license, but for the family pack, I had to have a box shipped across the country to me. There's something wrong with that picture. I should have been able to just go into iTMS, specify the licenses I needed, then have the software download to my machine automatically. By now, we should have just as seamless and smooth of a buying experience for Mac applications as we do for movies, music, television shows, and mobile apps.
Even without a Mac App Store, though, opportunity is there in the Mac software world. In some ways, the opportunities are better than they've ever been because the potential audience is larger than ever and many of the people who are qualified to create quality Cocoa apps are myopically focused on the iPhone right now. Yes, there's more work involved with Mac apps. You'll have to find a distribution path. You'll have to advertise. You'll have to arrange a payment mechanism. But there are so many targets begging for a good competitor right now, and so many new as-yet uncreated markets that can now exist because of the amount of processing power we can easily leverage in Cocoa. There are many big, slow, corporate-owned, Carbon-based crappy-ass apps that keep making money because they have tons of cash to advertise and because there isn't a viable alternative or, at least, people aren't aware that there is a viable alternative.
We all started on a level playing field in the iPhone nearly two years ago. In fact, it wasn't even level at the start; smaller companies and individuals had the advantage of agility. Hell, a large corporation like Adobe or EA can't decide to enter a new market in the time that some of the earliest iPhone applications were designed, developed, and shipped. Heck, a large corporation often can't even decide who should decide to enter a new market in the time that many iPhone apps were written. TapTapTap was smart enough and capable enough to take advantage of that opportunity, but people entering the iPhone market today have to compete with the big names and the established small names.
Even though the distribution situation is considerably better on the iPhone than on the Mac, the overall competitive landscape really isn't all that different when you look at the market as a whole. How many of the top-ten grossing games right now are titles from big-name companies? Usually, it seems to run between seven and ten of the top ten are big-name titles. On the other hand, what percentage of successful Mac titles are produced by independents? I have to believe it runs at least 10-30%, and I would guess it runs higher.
I don't see the markets as being nearly as different as John does for somebody starting from ground zero today. There are differences, certainly, but there's plenty of room for success — and failure — in both markets.
1- Actually, I can. A couple of years ago, I abandoned Photoshop for Acorn, which is a native Cocoa image editor that rocks. There are a few features that some design professionals might need that it doesn't have (e.g. CMYK support), but what it does, it does so much faster than Photoshop CS4 that it's not even a close race, and yet it costs a fraction of what Photoshop costs. And think about this: Acorn is mostly written by one person. Compare that with the names in Photoshop's dialog box.
Jumat, 16 Oktober 2009
Accessorizer 1.5
I've posted about Accessorizer before. It's just been updated to version 1.5, incorporating a new feature that sprang out of a feature request that was made by yours truly. Actually, it was more of an off-hand comment then a feature request, but Kevin Callahan, the brains behind Accessorizer liked the request and jumped on it with gusto.
The new feature? Accessorizer now has the ability to auto-detect classes that are commonly used as outlets and, if you want it to, will add the IBOutlet keyword automatically to the generated property statements. I've been beta testing this new functionality, and works pretty darn well.
If you do any significant amount of Objective-C programming and haven't tried Accessorizer, I'd really suggest giving it a try. In the application I wrote today for More iPhone 3 Development, I'd estimate that Accessorizer saved me at least five minutes of typing (not to mention greatly reduced the chances of mistakes and typos). I typed in only my instance variables, then a few short keystrokes and about twenty seconds later, I had my property declarations complete with IBOutlet keyword where needed, @synthesize declarations, and both NSCoding methods. You don't have to write too many classes for it to pay for itself if you do this for a living. If you're a hobbyist then, in a way, your time is even more valuable.
And if you're not sure how to use it, or why you would use it, check out the Accessorizer videos in the lower right of the home page.
The new feature? Accessorizer now has the ability to auto-detect classes that are commonly used as outlets and, if you want it to, will add the IBOutlet keyword automatically to the generated property statements. I've been beta testing this new functionality, and works pretty darn well.
If you do any significant amount of Objective-C programming and haven't tried Accessorizer, I'd really suggest giving it a try. In the application I wrote today for More iPhone 3 Development, I'd estimate that Accessorizer saved me at least five minutes of typing (not to mention greatly reduced the chances of mistakes and typos). I typed in only my instance variables, then a few short keystrokes and about twenty seconds later, I had my property declarations complete with IBOutlet keyword where needed, @synthesize declarations, and both NSCoding methods. You don't have to write too many classes for it to pay for itself if you do this for a living. If you're a hobbyist then, in a way, your time is even more valuable.
And if you're not sure how to use it, or why you would use it, check out the Accessorizer videos in the lower right of the home page.
Kamis, 24 September 2009
Barcode Generator Application

For grins and giggles, I tried compiling an Xcode project I created back in 2002. Well, technically, it was a Project Builder project created in 2002 that was converted to an Xcode project a couple of years later, but the bulk of the code was written back in 2002. I wanted to see how much work would be involved in taking a project that was written when Puma was the current version of Mac OS and Macs were shipping with PowerPC processors and getting it to compile to work in 32/64 bit mode for Intel Macs.
Code changes required? Not a one.
There were a bunch of warnings that I would address if this were shipping software, since a couple of methods I used back then have been deprecated. None of them have yet been removed, so the application works (as far as I can tell) exactly as it did back in 2002. The project configuration was where almost all of the work was in updating, and there wasn't much of that, to be honest. Total time investment, about 20 minutes.
That's pretty damn amazing, different architectures, different register size, and a seven-year-old codebase written when I knew a heck of a lot less about Cocoa. Despite all the amazing changes to Snow Leopard, this old code still works flawlessly.
If you're interested in a free Barcode application, you can download the compiled application right here. If you have a version of the OCR-A font installed, it will attempt to use it (you can get a free one here), otherwise it will fall back on the system default monospace font.
I will push the project changes to Google Code when I have some free time.
Rabu, 23 September 2009
Opacity - Export as Source Code
Okay, I don't ordinarily repost items covered by Daring Fireball since most of you probably read it anyway, but this one's just too cool and too relevant not to include. The vector art program Opacity now has the ability to export your graphic as source code, presumably as CoreGraphics calls that you can use in your Mac and iPhone applications.
Now, in most cases, you don't want resources contained in code - you should just store the graphic file as a resource in your application's bundle - but there are times when this would be hugely helpful, like when you want to animate the vector art, or when the specific appearance of the image depends on values only available at runtime.
Now, in most cases, you don't want resources contained in code - you should just store the graphic file as a resource in your application's bundle - but there are times when this would be hugely helpful, like when you want to animate the vector art, or when the specific appearance of the image depends on values only available at runtime.
Selasa, 22 September 2009
More Housecleaning
Here's another category I found while cleaning out my dev folder. It's another bit of Quicktime code for Cocoa. This is a category on QTMovie that makes it easier to deal with standard movies (i.e. ones with one video track and any number of audio tracks).
This same category exists in the MovieStepper project, but that version won't compile for 64-bit Cocoa applications because Apple has removed access to the underlying Quicktime data structures like Track and Media. This version uses only QTKit objects to accomplish the same tasks, and thus will compile for both 32-bit and 64-bit applications.
QTMovie-Frame.h
QTMovie.m
This same category exists in the MovieStepper project, but that version won't compile for 64-bit Cocoa applications because Apple has removed access to the underlying Quicktime data structures like Track and Media. This version uses only QTKit objects to accomplish the same tasks, and thus will compile for both 32-bit and 64-bit applications.
QTMovie-Frame.h
//
// QTMovie-Frame.h
// MovieStepper
//
// These are methods designed to be used on movies that contain only
// sequential frame data, e.g. straight movies. These methods make
// the assumption that the framerate is constant and that each frame
// is displayed for the same length of time. Do not use these methods
// on movies that have tracks other than a single video track and
// some number of audio tracks.
//
// This code may be used freely in any project, commercial or otherwise
// without obligation. There is no attribution required, and no need
// to publish any code. The code is provided with absolutely no
// warranties of any sort.
#import <Cocoa/Cocoa.h>
#import <QTKit/QTKit.h>
@interface QTMovie(Frames)
- (long)numberOfFrames;
- (void)gotoFrameNumber:(long)frameNum;
- (long)currentFrameNumber;
- (int)displayFPS;
- (float)desiredFPS;
- (NSImage *)frameImageForFrame:(int)frameNumber;
- (NSSize)size;
@end
QTMovie.m
//
// QTMovie-Frame.m
// MovieStepper
//
// Copyright 2009 Jeff LaMarche. All rights reserved.
//
// This code may be used freely in any project, commercial or otherwise
// without obligation. There is no attribution required, and no need
// to publish any code. The code is provided with absolutely no
// warranties of any sort.
//
// This code has been updated to work in 64-bit mode where access to
// the underlying Quicktime Carbon structures has been removed.
#import "QTMovie-Frames.h"
@implementation QTMovie(Frames)
- (long)numberOfFrames
{
NSArray *tracks = [self tracksOfMediaType:QTMediaTypeVideo];
for (QTTrack *track in tracks)
{
QTMedia *media = [track media];
NSNumber *frames = [media attributeForKey:QTMediaSampleCountAttribute];
if (frames != nil)
return [frames longValue];
}
return -1L;
}
- (void)gotoFrameNumber:(long)frameNum
{
int frames = [self numberOfFrames];
double percentDone = (double)frameNum / (double) frames;
QTTime duration = [self duration];
QTTime newTime;
newTime.timeScale = duration.timeScale;
newTime.flags = duration.flags;
newTime.timeValue = duration.timeValue * percentDone;
[self setCurrentTime:newTime];
}
- (long)currentFrameNumber
{
QTTime now = [self currentTime];
QTTime duration = [self duration];
if (now.timeValue == 0 || duration.timeValue == 0)
return 0;
double percentDone = (double)now.timeValue / (double)duration.timeValue;
int frames = [self numberOfFrames];
return (int) ((double)frames * percentDone)+1;
}
- (Fixed)rawFPS
{
NSArray *tracks = [self tracksOfMediaType:QTMediaTypeVideo];
for (QTTrack *track in tracks)
{
QTMedia *media = [track media];
QTTime duration = [[media attributeForKey:QTMediaDurationAttribute] QTTimeValue];
long numFrames = [self numberOfFrames];
double frameRate = numFrames*(double)duration.timeScale/(double)duration.timeValue;
return X2Fix(frameRate);
}
return -1;
}
- (int)displayFPS
{
return FixRound([self rawFPS]);
}
- (float)desiredFPS
{
return FixedToFloat([self rawFPS]);
}
- (NSImage *)frameImageForFrame:(int)frameNumber
{
QTTime restoreTime = [self currentTime];
[self gotoFrameNumber:frameNumber];
NSImage *ret = [self currentFrameImage];
[self setCurrentTime:restoreTime];
return ret;
}
- (NSSize)size
{
return [[self attributeForKey:QTMovieNaturalSizeAttribute] sizeValue];
}
@end
Senin, 21 September 2009
More Desktop Code
Although my focus for the last 20 months has been the iPhone, I've tried to stay at least in touch with Cocoa for the Mac. As a result, I tend to start a lot of small projects designed to help me learn, re-learn, or brush up on some specific area of functionality. A lot of these projects just end up gathering dust on my hard drive and are never used in any kind of production application, so since I'm doing a little housecleaning, I thought I'd post some of these projects that might be useful to iPhone developers wanting to get into Mac development or for newer Mac developers.
I've written several Cocoa applications over the years that work with Quicktime, including Crimson FX, a simple rotoscoping and special effects application. Back when I wrote these, most of the Quicktime functionality had to be accessed through Carbon calls. Since then, there have been several major releases of Quicktime, and Cocoa has gained some very robust Quicktime support by way of QTKit.
To familiarize myself with Cocoa's current Quicktime functionality, I wrote a small application that loads in a Quicktime movie and allows you to step through it frame-by-frame or to scrub through the frames using a slider. There's also a custom view that displays a filmstrip timeline, similar to the way iMovie displays a timeline.

This is neither a full-featured, nor a production-ready application, but if you're interested in writing a Cocoa application that needs to do more with Quicktime than simply play a movie, you may find some of the code in here useful. In addition to the filmstrip view, there's also a category that adds several methods to QTMovie for dealing with the individual frames of a movie's video track.
You can find the project here. As always, there are no restrictions on the use of this code, and I welcome any improvements or bug fixes you might come up with.
I've written several Cocoa applications over the years that work with Quicktime, including Crimson FX, a simple rotoscoping and special effects application. Back when I wrote these, most of the Quicktime functionality had to be accessed through Carbon calls. Since then, there have been several major releases of Quicktime, and Cocoa has gained some very robust Quicktime support by way of QTKit.
To familiarize myself with Cocoa's current Quicktime functionality, I wrote a small application that loads in a Quicktime movie and allows you to step through it frame-by-frame or to scrub through the frames using a slider. There's also a custom view that displays a filmstrip timeline, similar to the way iMovie displays a timeline.

This is neither a full-featured, nor a production-ready application, but if you're interested in writing a Cocoa application that needs to do more with Quicktime than simply play a movie, you may find some of the code in here useful. In addition to the filmstrip view, there's also a category that adds several methods to QTMovie for dealing with the individual frames of a movie's video track.
You can find the project here. As always, there are no restrictions on the use of this code, and I welcome any improvements or bug fixes you might come up with.
Senin, 03 Agustus 2009
A Mac App Store
Back before WWDC, one of my long-shot predictions was the creation of a Mac App Store following the same business model as the iPhone App Store. It didn't come true, and now with the various issues surrounding the App Store, I've changed my mind that it would be a good idea. I've come to the conclusion that I like not having Apple as the gatekeeper for what Apps can do.
But, it's nearly impossible to argue that the App Store isn't convenient. It has its issues, but its a great idea, which is why the App Store is flourishing despite all the negative press.
Now, a third-party called Bodega is extending the idea to Mac applications, and it's a snazzy little application.

In some ways, Bodega outdoes Apple's iTunes Store. The interface is clean and easy to use, and it's filled with lots of little touches reminiscent of the Delicious Generation. For example, when you move the window around when the "Featured" option is selected, the little hanging signs you can see in the picture above swing with gravity and creak as they move. It's an unnecessary, yet completely satisfying little touch.
This project is still in its infancy, but it shows a lot of promise and it's one I'm definitely going to keep an eye on.
But, it's nearly impossible to argue that the App Store isn't convenient. It has its issues, but its a great idea, which is why the App Store is flourishing despite all the negative press.
Now, a third-party called Bodega is extending the idea to Mac applications, and it's a snazzy little application.

In some ways, Bodega outdoes Apple's iTunes Store. The interface is clean and easy to use, and it's filled with lots of little touches reminiscent of the Delicious Generation. For example, when you move the window around when the "Featured" option is selected, the little hanging signs you can see in the picture above swing with gravity and creak as they move. It's an unnecessary, yet completely satisfying little touch.
This project is still in its infancy, but it shows a lot of promise and it's one I'm definitely going to keep an eye on.
Minggu, 12 Juli 2009
A Category on NSDate
Here is a category on NSDate that makes a few somewhat common tasks that require several lines of code and turns them into a single method all. Among these methods are one that takes a date with a datetime value and turns it into a date without time, a method that calculates a new dates that is a certain number of days after the date, and a method that calculates the difference between two dates given in days.
Nothing earth-shattering, but may save you a few lines of code here and there.
NSDate-Misc.h
NSDate-Misc.m
Nothing earth-shattering, but may save you a few lines of code here and there.
NSDate-Misc.h
#import <Foundation/Foundation.h>
@interface NSDate(Misc)
+ (NSDate *)dateWithoutTime;
- (NSDate *)dateByAddingDays:(NSInteger)numDays;
- (NSDate *)dateAsDateWithoutTime;
- (int)differenceInDaysTo:(NSDate *)toDate;
- (NSString *)formattedDateString;
- (NSString *)formattedStringUsingFormat:(NSString *)dateFormat;
@endNSDate-Misc.m
#import "NSDate-Misc.h"
@implementation NSDate(Misc)
+ (NSDate *)dateWithoutTime
{
return [[NSDate date] dateAsDateWithoutTime];
}
-(NSDate *)dateByAddingDays:(NSInteger)numDays
{
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *comps = [[NSDateComponents alloc] init];
[comps setDay:numDays];
NSDate *date = [gregorian dateByAddingComponents:comps toDate:self options:0];
[comps release];
[gregorian release];
return date;
}
- (NSDate *)dateAsDateWithoutTime
{
NSString *formattedString = [self formattedDateString];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"MMM dd, yyyy"];
NSDate *ret = [formatter dateFromString:formattedString];
[formatter release];
return ret;
}
- (int)differenceInDaysTo:(NSDate *)toDate
{
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [gregorian components:NSDayCalendarUnit
fromDate:self
toDate:toDate
options:0];
NSInteger days = [components day];
[gregorian release];
return days;
}
- (NSString *)formattedDateString
{
return [self formattedStringUsingFormat:@"MMM dd, yyyy"];
}
- (NSString *)formattedStringUsingFormat:(NSString *)dateFormat
{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:dateFormat];
NSString *ret = [formatter stringFromDate:self];
[formatter release];
return ret;
}
@end
17.28
ipod touch review

