Struggling with graphics

One area of writing code that I’ve never been good at is graphics. I partially attribute this to my lack of artistic ability, but also my distaste for advanced math. For the last day, I’ve been working on a problem to rotate some buttons and move the buttons at the same time. Rotating the buttons is easy:

self.myButton.transform = CGAffineTransformRotate(flashTransform, degrees * M_PI/180);

Moving the button turned out to be hard for me. I tried all kinds of translations and transforms, but came up with nothing. The transforms are matrix math and that just makes me want to turn the other way and run. I searched and searched, tried different things, stayed up late and still couldn’t solve it. This morning I was chatting with a colleague and he suggested just to do the rotation which I knew how to do and then move the buttons. OK, that seemed simple and I know I had tried it. Turns out you can’t move a view using the frame property if there is a non-identity transform on it; however, you can set the center which is just as good, but requires a small extra step. You have to convert the origin point you want to the center.

CGPoint center;
center.x = newOrigin.x + self.button.bounds.size.width / 2;
center.y = newOrigin.y + self.button.bounds.size.height / 2;

Definitely not hard to do, but it tripped me up. The other thing that tripped me up is that in order to resize the button, you have to use the bounds and not the frame if a transform is applied. So with those 2 hints, I was able to finish my task in about 15 minutes. Hopefully next time I won’t be so thick header about this.

Interview technique – crash logs

I periodically have to interview people and I find that I struggle to come up with ways to adequately determine a candidate’s technical knowledge. While they can present their resume and what they’ve done in the past, it is hard to tell how they really think. I don’t ask questions that I couldn’t answer myself as I don’t think that is fair. Many people ask basic computer science questions that I’d probably get wrong as I don’t have a computer science background; so I tend to ask questions to see how a candidate would handle a situation.

So far I’ve had mixed results in weeding out the good from the bad. One skill that I think is of utmost important for a developer is debugging. You might be saying that all developers do that, but some are far better at it than others. Debugging is one of my best skills and I’ve had a ton of experience at it inheriting other people’s projects. With that in mind, I came up with one technical test that could actually tell me if a candidate could debug and that skill goes a long way in development.

Now you ask, what is the question? The other day as I was poking through crash logs, a few stood out at me. Take a look at the following logs and see if you can spot why the apps crashed:

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0:
0   libsystem_kernel.dylib            0x35cab054 semaphore_wait_trap + 8
1   libdispatch.dylib                 0x342961c0 _dispatch_semaphore_wait_slow + 184
2   libdispatch.dylib                 0x342961f4 dispatch_semaphore_wait$VARIANT$mp + 32
3   libxpc.dylib                      0x3200e89a xpc_connection_send_message_with_reply_sync + 206
4   SystemConfiguration               0x374f5be6 _reach_server_target_status + 938
5   SystemConfiguration               0x374f6d56 __SCNetworkReachabilityServer_targetStatus + 14
6   SystemConfiguration               0x374dfaee __SCNetworkReachabilityGetFlags + 198
7   SystemConfiguration               0x374e0f7a SCNetworkReachabilityGetFlags + 190
8   MSNBC                             0x000cb9ec 0x1000 + 829932
9   MSNBC                             0x0006f998 0x1000 + 453016
10  MSNBC                             0x0006abfa 0x1000 + 433146
11  MSNBC                             0x00014d54 0x1000 + 81236
12  MSNBC                             0x0006ab6e 0x1000 + 433006
Last Exception Backtrace:
0   CoreFoundation                    0x3567188f __exceptionPreprocess + 163
1   libobjc.A.dylib                   0x37a18259 objc_exception_throw + 33
2   CoreFoundation                    0x356713b3 __NSFastEnumerationMutationHandler + 163
3   EmSea                             0x001f9c2b 0xe2000 + 1145899
4   EmSea                             0x00199bed 0xe2000 + 752621
5   EmSea                             0x00223453 0xe2000 + 1315923
6   EmSea                             0x002239c9 0xe2000 + 1317321
7   Foundation                        0x351b6c29 __65-[NSURLConnectionInternal _withConnectionAndDelegate:onlyActive:]_block_invoke_0 + 17
8   Foundation                        0x3510e6d9 -[NSURLConnectionInternalConnection invokeForDelegate:] + 29
9   Foundation                        0x3510e6a3 -[NSURLConnectionInternal _withConnectionAndDelegate:onlyActive:] + 199
10  Foundation                        0x3510e5c5 -[NSURLConnectionInternal _withActiveConnectionAndDelegate:] + 61

On the first one, the hint is that the app failed to launch in time. I’m going to use these crash logs as a test to see if a candidate can tell me what went wrong. Neither app is mine and while I can’t see the code, I can immediately spot the problems.

In the first crash log, the app calls SCNetworkReachabilityGetFlags on the main thread. This call is a blocking call which means it won’t return until it is done; this call can take a significant amount of time to return and should never be called on the main thread, especially at app startup.

In the second crash log, it isn’t as obvious. What the developer has done is something like:

for (NSString *string in someMutableArray)
{
    if ([string isEqualToString:@"Yuck"])
    {
        [someMutableArray removeObject:string];
    }
}

The array is getting modified while it is being enumerated. The fix is pretty simple.

NSMutableArray *deleteArray = [NSMutableArray array];
for (NSString *string in someMutableArray)
{
    if ([string isEqualToString:@"Yuck"])
    {
        [deleteArray addObject:string];
    }
}

[someMutableArray removeObjectsInArray:deleteArray];

Are you good at reading crash logs?

Can’t believe everything you read

Two years ago, I wrote about open source saying it wasn’t always the answer. I was recently reminded of this when I was searching for a good networking stack for use in an application. While we have a killer (in my opinion) stack that I enjoy using at work in a bunch of our applications, it isn’t open source and therefore I can’t use it. I looked at a bunch of iOS networking stacks and found some too complex, some no longer supported, and some that were good candidates.

After reading the explanation of each one carefully, I came to the conclusion, that one of them completely made up at least part of his explanation on why his stack was better than the rest. The author claimed that the maximum number of simultaneous TCP connections over a 3G connection was 2. This I find incredibly hard to believe. Palm OS had a limit of 1 connection (I believe) and that was eons ago. Could 3G be so bad that we only doubled this? Could/would 3G carriers enforce this? I was unable to find any material supporting what the author said.

I’ve been working with cellular data for over 15 years and have never heard of this kind of limit on any device; there are, of course, bottlenecks when you try to open too many connections and certain OSes have limits to the number of connections.

While the networking stack looked interesting, I immediately stopped reading and completely discounted it. The author’s story sounded compelling, but as far as I can tell is a complete work of fiction.

I did end up using a very simple network stack that a colleague had developed on his own time; it doesn’t do everything I’d like, but it meets my immediate needs.

Growl and Mountain Lion’s Notification Center

One of the neat features of Mac OS X 10.8, Mountain Lion, is the notification center. Having all notifications is cool and when I saw Hiss, a replacement for Growl, I immediately installed it and loved it for a few minutes. However, it has one major flaw and that is it doesn’t have an AppleScript dictionary so SuperDuper! gets hung up at the end of copies because it tries to send an AppleEvent to Growl and a have a script that posts notifications of new email from Outlook.

I went down the path of creating a replacement for Hiss and got the AppleScript part going, but didn’t bother with the Growl part. So now I had 2 incompatible halves of a solution.

Then I started poking at the Growl source and figured that I could just write a plugin (Mountain Lion only) that posted the notifications. About 20 minutes later, my plugin was complete.

You can download my plugin here.

Unzip the file, double click it and set it as the default style. There are no configuration settings. This requires Growl 1.4 available on the Mac App Store.

This plugin comes with no warranty nor support. The next version of Growl will eliminate the need for this plugin, so you’ll want to remove it when the next version of Growl comes out.

If you like this, please consider sponsoring my wife in the MS Challenge Walk.

Enjoy!

Counterfeit goods

Last week I went searching for a Mophie Juice Pack Plus battery for my iPhone as I’ve been traveling more and my iPhone doesn’t quite last all day when I use it. I did a Google search (after I decided that I wanted it over the other batteries) and found prices ranging from about $50 to $100. The list price is $100 so all the prices in that range seem legitimate. The $50 price on Amazon looked too good to be true. After reading through a bunch of reviews, I discovered the reason. It would appear that some Amazon sellers are selling counterfeit products.

I would have expected Amazon to better screen their sellers especially when they are fulfilling the orders for these merchants and are offering it via Amazon Prime. This also happened with an OtterBox case we bought for my wife; the build quality is not up to par and didn’t come it the retail packaging. Does it matter? Now that the case is falling apart, I’d have to say yes.

How can you protect yourself from counterfeits? First off, a tip off is “does not come in retail packaging to save you money”. Second, if the price is too low, there is likely a problem. However, I’m taking another stab at an OtterBox off eBay. In this case the seller says that it came from a store that they closed and it is in retail packaging; the packaging has AT&T on it and not OtterBox. After a little research, I found that the seller is an AT&T reseller, so this adds legitimacy to the seller. Third, is it shipping direct from China? Not everything that ships from China is counterfeit, but companies usually ship to distributors in the US and ship from the US.

Of course, buyer beware. Safe shopping!

Another advantage of VoIP

When we switched to Ooma awhile back, I had in the back of my mind that someday we’d move and be able to take our phone number with us. I didn’t realize it would be so soon, but with this move, transferring our phone was one of the easiest tasks. I just unplugged the box, took it to the new house and plugged it in. Once the cable modem was connected, the phone worked. I just had to update our service address in Ooma for 911 service and I was in business again.

This is, yet another, reason that I really like Ooma. We’ve saved a ton of money, we have 2 lines, get voicemail sent as email, and I can quickly block telemarketers via the web interface.

Removing geotagged info from a video

When I post pictures to eBay or somewhere else that I’ve taken at my house, I strip the geotagged information in it as I’m a bit paranoid. I wrote a small app which basically does this for JPG images. The core of the app is below.

However, how do you do this with videos as the iPhone geotags video? At first I tried emailing the video and then exporting it via QuickTime Player to 480p format. That didn’t seem to work as I think it was already 480p and therefore didn’t convert. Next, I imported the video into iPhoto, dragged it out to the desktop, opened it up in QuickTime Player and then exported to 480p. Since the initial video was 1080p, QuickTime Player actually had to do a conversion and the process stripped the geotagging info.

I’m sure I could have written an app to do this, but I haven’t played around enough lately with the QuickTime APIs to know how to do this.

The source code below is © 2011 Scott Gruby. Redistribution in source or object form is permitted granted that attribution is given to me.

- (void) processFile:(NSString *) inPath
{
    NSString *extension = [inPath pathExtension];
    if ([extension caseInsensitiveCompare:@"jpg"] == NSOrderedSame || [extension caseInsensitiveCompare:@"jpeg"] == NSOrderedSame)
    {
        NSURL *pictURL = [NSURL fileURLWithPath:inPath];
        CGImageSourceRef sourceRef = CGImageSourceCreateWithURL((CFURLRef) pictURL, NULL);
        if (sourceRef)
        {
            NSDictionary* metadata = (NSDictionary *)CGImageSourceCopyPropertiesAtIndex(sourceRef,0,NULL);
            NSMutableDictionary *metadataAsMutable = [[metadata mutableCopy] autorelease];
            
            
            [metadataAsMutable setObject:(id)kCFNull forKey:(NSString *)kCGImagePropertyGPSDictionary];
            [metadataAsMutable setObject:(id)kCFNull forKey:(NSString *)kCGImagePropertyIPTCDictionary];

            CFStringRef UTI = CGImageSourceGetType(sourceRef); //this is the type of image (e.g., public.jpeg)
            
            //this will be the data CGImageDestinationRef will write into
            NSMutableData *data = [NSMutableData data];
            
            CGImageDestinationRef destination = CGImageDestinationCreateWithData((CFMutableDataRef)data,UTI,1,NULL);
            
            if(destination)
            {
                //add the image contained in the image source to the destination, overiding the old metadata with our modified metadata
                CGImageDestinationAddImageFromSource(destination,sourceRef,0, (CFDictionaryRef) metadataAsMutable);
                
                //tell the destination to write the image data and metadata into our data object.
                //It will return false if something goes wrong
                BOOL success = NO;
                success = CGImageDestinationFinalize(destination);
                
                if (success)
                {
                    //now we have the data ready to go, so do whatever you want with it
                    //here we just write it to disk at the same path we were passed
                    success = [data writeToURL:pictURL atomically:YES];
                }
                CFRelease(destination);
            }


            [metadata release];
            CFRelease(sourceRef);
        }
    }
}

When wireless doesn’t work

In the house we just sold, I had a primarily wired network with only a few things wireless. This worked out pretty well as I had gigabit Ethernet switches in a few places and everything was quite reliable. Since we moved into a rental, running Cat6 cable everywhere was not a choice, so I had to go wireless in the house. I chose my office location in a central part of the house as it had coax close to it and WiFi would cover the entire house.

Since my choice for handling TV involved a SiliconDust HDHomeRun, I didn’t have to have coax directly to the TV; I just had to have coax near my network. This wasn’t a problem as I put the box next to the cable modem and my Time Capsule router. My Mac Mini and Apple TV that are hooked to our TV are connected over 802.11n to my Time Capsule and appear to function adequately for the first few days.

However, I started to notice that some of the shows that I recorded were jumpy. I suspected that this was due to lack of bandwidth. The HDHomeRun sends a stream of about 16 MBit/second for each show it is recording to my Mac Mini. 802.11n should be able to handle this without problems. My first step was to replace my Time Capsule with a newer version that supposedly had better performance. (I also went from 1 TB to 2 TB). Unfortunately, this didn’t solve the problem. I noticed the biggest issue when 2 shows were being recorded which meant that I was streaming about 32 MBit/second and then if we were watching a show, it added about another 10 MBit/second to the mix. So the Mac Mini was trying to push a lot of data and receive a lot of data over WiFi.

The next step in solving this problem (which I’ll know next week if it is the fix) was to run 50 feet of Cat6 cable from my office around a corner and over some blinds to reach the Mac Mini.

It appears that WiFi is decent for normal operations and some streaming, but is no replacement for a wired network. In theory 802.11n should be able to handle what I’m throwing at it, but the router can’t handle it, the Mac Mini can’t handle it, or the protocol isn’t up to what I want to see.

Facebook app ruined design

This past week, we launched a major update to an app where we got to start over from scratch with a new design and a completely new code base. While I never encourage a developer to read reviews on the App Store (the reviews are sometimes written by clueless people who have an axe to grind; some are legitimate gripes).

A number of the reviews said that they liked the old design better than the new design. The old design had a grid layout using the Three20 library that Facebook open sourced and uses in their app. This grid layout is not used in any Apple app and is pretty much against all the design guidelines from Apple. In addition, our old design used page curls and a very strange navigation paradigm that made sense to no one that has ever used other iOS apps. Our new design follows Apple guidelines as close as possible, uses standard navigation, standard buttons, etc.

I think that many people are so used to poorly designed apps that they take them as standard, so when an app comes along that more closely resembles Apple guidelines, they think it is ugly and works poorly. It is kind of sad that people can’t see the difference between ugly, hard to use apps and elegant apps. Apple spent a significant amount of time coming up with design guidelines and making an SDK that allows developers to follow the guidelines.

I’ll make it my mission to educate users one at a time on what apps are well designed and which ones aren’t.

The value of hotel WiFi

It now seems that hotel WiFi is the norm with many places I stay having free access. However, sometimes even at free, it just isn’t worth it. At times, the speed can be so slow and problematic that it is more frustrating than anything to use. Up until May, I had a Sprint MiFi 3G router, so having poor hotel WiFi wasn’t an issue and for the most part, I didn’t even use the hotel WiFi. However, it is now important if I have any hope of getting something done in my hotel room.

In my last 3 trips to Portland, the hotel I’ve stayed at, Hotel Monaco, has WiFi that is a) free and b) works quite well. I’ve been able to stream Netflix, download apps, upload things, and even carry on FaceTime calls with excellent results.

I wonder if there is a site that rates hotel WiFi. Does good WiFi matter in a hotel room? With our always connected society, it almost might. I can do many things on my iPhone over 3G, but having WiFi is so much nicer.