-
Automator to the rescue
This past week, I finally upgraded my wife's MacBook to Snow Leopard (yes, I realize it is a year late). The upgrade went fine, but last night my wife told me that her DYMO Labelwriter 4XL
wasn't properly printing PayPal shipping labels. I wrote a few months ago about printing labels on the DYMO. I'm not sure what happened to my wife's machine, but I had to solve this problem. I went down the path of scripting it and sending the label to DYMO's software. Unfortuantely DYMO's software is junk and threw exceptions when I used their demo AppleScripts. So, I had to find an alternative.
After a ton of work, I managed to hack together an Automator workflow that used Pixelmator, Preview, and some GUI scripting. It isn't really pretty, but amazingly it works.
While my script works, I can't guarantee it will work for everyone, but here it is in case anyone wants to use it as a basis for their own. Download the script
-
End of Microsoft Office on my Mac
Last week after a colleague ask a client to send a Word document as a PDF, I asked him how he got away without Office on his computer and he said he used iWork. I tried this route several years ago, but had to install Office when I started by job 2 years ago to use some wacky templates. It dawned on me that I no longer had a reason to keep Office on my machine.
I purchased a copy of iWork '09 (yeah, I realize that iWork '11 will be out before I know it) and received it today. I deleted Office and install iWork. I use a text editor for composing things, but every once in awhile I need to use a word processor and a spreadsheet. iWork should fit the bill quite well for this.
On the off change that someone sends me an Office document I can't read, I can ask for a PDF or try loading it into Google Docs. It feels so refreshing to get Office off my machine. I know that things have changed for Office 2011, but it seems like it just keeps getting more and more bloated. Freedom!
-
Review: Blade CX3
First off, I have to admit that I'm getting addicted to RC helicopters which if I don't watch myself is going to get quite expensive! Now that I have that off my chest, I've now purchased my third helicopter, this time a Blade CX3
. This helicopter is a huge step up in terms of size from my Blade mCX2
.
When I first got the helicopter, I was a little afraid to fly it. The bigger the helicopter, the more it would cost to repair. I flied it around my office a little bit, but due to its size, it's pretty hard to do much with it. However, I did get the hang of it (it's quite loud) and decided to give it a whirl outside. Well, I was a bit overconfident and on my first flight outside, it ended up on the roof and I caught it as it came crashing down on me. Luckily I was able to repair the fuselage damage with some clear tape and it was as good as new.
I've been having a lot of fun with it and am excited to fly it outside. However, there has to be very, very little wind to do anything with it. The times I've flown it outside, the wind is just a little too strong so that when I try to go forward full speed, it goes no where. It is teaching me how to control it in adverse conditions which is kind of interesting.
One of the maneuvers that I've pretty much perfected on the mCX2 is landings in a single spot. On the CX3, this is much harder because of the ground effect created by the blades; flying it low is kind of difficult due to this (the blades are pushing down a bit of air causing the helicopter to go up). This is something that I'm keep attempting.
The CX3 doesn't use anything that is the same as my mCX2, so I've already started collecting spare parts in the event of a crash. I've also had to pick up an extra battery as the 6 minute flight time is a bit short when it takes 2 hours to recharge the battery.
Many of the points below are similar to what I wrote about the mCX2. The two helicopters are quite similar as beginner helicopters.
Pros
- Not too hard to control.
- Moderate size allows me to fly outside.
- Replacement parts aren't that expensive.
- Comes with battery charger.
- Heading hold gyro attempts to keep the nose facing in the direction of travel.
- It's quite fast when flying inside.
Cons
- Size makes it a bit large to fly inside and do anything interesting (very small circles).
- Only comes with 1 battery.
- Long recharge time (2 hours).
- Navigation lights are optional (they look cool on the mCX2).
- It's noisy. In the house, it's hard to really hear anything when it's flying.
- Time consuming to disassemble. I added a heat sink to it and it took me about an hour to take it apart and install the heat sink. Maybe it was just me, but I had a problem removing one of the motors to get the heat sink in.
Summary
The CX3, like the mCX2, is a beginner helicopter. I kind of see it as a stepping stone from the mCX2 as it is larger and can fly outside. I'm glad that I got the mCX2 first as it let me learn to fly and maneuvers. I haven't abandoned my mCX2, but I find the CX3 a bit more challenging and more exciting. If you're interested in RC helicopters and don't have much room to fly, the mCX2 is the way to go. If you have more room and want to fly outside, the CX3 is the better choice.
I'm having a great time with my helicopters and am getting pretty good at flying.
-
Objective-C/Cocoa Tips
[Updated 7 November 2010.]
I've been writing Objective-C and Cocoa code for almost 8 years, but it feels like a lot longer. There is good reason for that and it's that during that time I haven't just worked on projects during the day, I worked on projects at night, so the 8 years is more like 10-12 years of writing code. During that time, I've written a ton of code and come up with a lot of tips to help me. Each developer has his/her own style, so I'm sure that some people will take objection to some of what I say. However, a number of projects I've worked on could really have used this information to be more solid.
Without further ado:
- When you start a project, set the Organization in the project so that all new files created have the correct copyright. Pretty much every project I've worked on has most of the files stamped with the wrong copyright.
- Never use [self autorelease] or [self release]. These make code very hard to trace and WILL lead to a crash when another developer comes along and releases an object thinking there is a memory leak. Code should be restructured so that whoever instantiated the object releases it. In addition, CLANG will flag objects that aren't released as a potential memory leak and having to sift through the CLANG messages every time analyze is done.
- Follow Apple's guidelines on method naming. Methods that return an object that must be released by the caller must begin with "alloc" or "new" or contain "copy" in it. (create also seems to be in there as well). Methods that return an autoreleased object must NOT start with "alloc" or "new" or contain "copy" in it. These are important so that CLANG can analyze your code and not flag things that require you to have to go through each issue and trace the code.
- Never subclass core objects such as NSString, NSArray, NSSet, etc. If you need additional functionality either use a category or make a new class that has the object as part of it.
- If an object is added to an array, an NSOperationQueue, etc., make sure the object is released or autoreleased.
- Don't use [NSObject new]; use [[NSObject alloc] init]; This is simply for readability. While they are equivalent, every time I see an alloc/init, I know I have to do a release or autorelease. "new" isn't as widely used and someone could accidentally do self.object = [NSObject new] which would cause a memory leak if the object property is retained.
- Use assign properties for objects in limited cases such as XMLNodes or delegates. In most cases properties should be retained or copied.
- Don't do a lot in the init methods. Also, be careful of using self.xxxx in an init method as there can be side effects in the assignment if you are using KVO or have your own setter. (The side effects part comes right from a WWDC presentation.)
- For properties that are retained, don't do self.xxx = [[NSObject alloc] init]. This is a memory leak. You can add autorelease to the end or do the assignment in a few steps, i.e.
NSObject *obj = [[NSObject alloc ] init]; self.xxx = obj; [obj release];
If you don't want KVO, you can eliminate using self. However, make sure you release the object before assigning it.
- Only use threading if you absolutely must and use NSOperations as much as possible. Threading is tricky and I've only seen a few places where it has been done right.
- Never make different build products using scripts, define values, and configurations. Use build targets. If you don't, your project file will change all the time and people will keep checking in a slightly modified project file.
- Don't put unnecessary things in the .pch file, create a Defines.h for that. Use the .pch file for including other files, one of which can be Defines.h. Put the Defines.h at the top of the project to make it easier accessible.
- Don't name every file in the project with the same prefix. If you are sharing code with other projects, then making those have the same prefix, that is fine, but if you have 100 files that start with SG, it becomes quite annoying.
- Don't sprinkle UNIX like code everywhere and don't use UNIX calls when Cocoa calls are available.
- If you use CoreData, first read as much as you can about CoreData. Second, explicitly set the managedObjectModel and don't let the OS do it for you. The OS will merge all the managed object models in your bundle and create 1 model. This is problematic when you have to do migrations.
- If using CoreData, use the XML data store until you are comfortable with the data model. Verify the metadata in the XML before you switch to sqlite.
- Networking code is hard. Make sure you don't use synchronous calls even in threads as you can't handle cancels. Use NSOperations for the calls. Debugging the code is even harder than writing, so don't over complicate it.
- Don't do version numbering in Info.plist files as you have to update 3-5 items each time you change the version number. See my post on an easy way to do this.
- Don't use NSAssert everywhere. Do actual error checking and handle conditions where necessary. While NSAsserts are usually compiled out for release builds, NSAsserts just annoy me to no end and basically serve no purpose to me.
- Make sure builds compile with no warnings. Don't ship code with build warnings unless there is some type of compiler issue preventing this from happening.
- Don't turn on unnecessary flags in Xcode; making warnings into errors makes it hard to test code. If you abide by the item above, you don't need to make warnings into errors.
- Before checking in files, always do a diff from your changes to what's in source control. Don't check in files just because you change 4 spaces into a tab. This also helps review the code and make sure you didn't leave in test code.
- Never store a value using NSNotFound. Seems pretty obvious to me. Apple says:
Prior to Mac OS X v10.5, NSNotFound was defined as 0x7fffffff. For 32-bit systems, this was effectively the same as NSIntegerMax. To support 64-bit environments, NSNotFound is now formally defined as NSIntegerMax. This means, however, that the value is different in 32-bit and 64-bit environments. You should therefore not save the value directly in files or archives.
- Never release an NSOperationQueue from within an NSOperation. That's like pulling the rug out from under you while you're standing on it!
- Be careful with type casting.
NSUInteger value = (NSUInteger) -1;
could have very strange consequences. Likewise, doing:
NSUInteger value = (NSUInteger) NSNotFound;
May not do what you want it to do and the results could be different on 32 and 64 bit machines.
These are just some tips that I've learned/developed over the years. I write a lot of code and have been involved in a number of projects that need TLC. Feel free to comment if you have more tips or want to debate anything I have written; these aren't the be all, end all to writing code, but they do help me write code that will stand the test of time (I recently got involved in a project that has code I wrote over 6 years ago that is still in use!)