wopen 0.2

I’ve updated my wopen bash function to open the .xcodeproj file if no .xcworkspace is available.

Copy the alias from here https://gist.github.com/coryalder/5609996

Place in your .bash_profile or .bashrc file (~/.bash_profile).

Example usage:

cd projectdirectory
wopen

issues open projectdirectory.xcworkspace if that file exists, or open projectdirectory.xcodeproj if that file exists, and errors out nicely if neither do.

PhotoDog

My new app PhotoDog was approved late last night! I’ve spent much of the day sending out press releases, and organizing my social media presence (Instagram and Twitter accounts, mostly). I won’t write much about that here, as this blog is mostly for technical details, but one thing I’ve very proud of is that this marks the first production app that uses my UIActivity for Instagram. Presumably someone else has used it, it’s got a respectable number of stars and forks on GitHub, but this is the first App Store app using it that I know of.

PhotoDog screen shot 1PhotoDog Screenshot showing DMActivityInstagram

I’ll be glad to see it get some battle-testing. :)

CocoaPods tip #0912: faster .xcworkspace opening

UPDATE: 0.2 available here http://objectivesea.tumblr.com/post/50874228125/wopen-0-2

My typical CocoaPods workflow:

  1. Switch to terminal
  2. cd to your project directory
  3. Edit Podfile
  4. type pod update
  5. Quickly Cmd-tab back to Xcode to close the project before CocoaPods rewrites it
  6. Type open .xcodeworkspace
  7. Resume working

The step that trips me up the most of all of these, is ironically step #6. xcw is a hard sequence of letters to type at the best of times.

Solution! wopen

Put this in your .bash_profile or .bashrc:

function wopen {
    open ${PWD##*/}.xcworkspace
} # open Xcode workspace

Now typing wopen will open the .xcworkspace file of the same name as the current directory.

Typical usage: pod update; wopen

0 notes

Best Practices: UIButtons and their IBAction/IBOutlets

Declare the UIButton outlet:

@property (weak, nonatomic) IBOutlet UIButton *cancelButton;

Declare the action method:

-(IBAction)cancelButtonAction:(id)sender;

Now when you are writing code you will never confuse the outlet and the action. You will always know what this means:

[self cancelButton];

or even worse:

self.cancelButton;

It’s a simple, easy to remember best practice. If you don’t follow this, or a similar convention (cancelButton/cancelAction) it WILL bite you in the ass one day.

AFNetworking - Cancelling operations

I recently ran into trouble trying to cancel operations in AFNetworking.

Two issues came up. The first was finding my previous query, to cancel it. The second was receiving some kind of notification that the operation was cancelled. The failure block isn’t fired when operations are cancelled.

Since my app uses GET requests, cancelAllHTTPOperationsWithMethod:path: was failing to find my operation. It was looking for a full path, query string and all. Since the query parameters are off somewhere else in my app, it was much easier to just override this method, and write code to match just the URL, ignoring the query string. Along the way, I improved on this StackOverflow question regarding trimming the query string off an NSURL.

The next bit required digging into the GitHub issues for AFNetworking to resolve. The default behaviour of AFNetworking is to call the failure block if the HTTP request fails, the success block if it succeeds, and do nothing if you cancel it. The logic is that if you are cancelling it, you can probably deal with the cancellation however you want. Details are available in AFNetworking/Issue#479. The workaround for this is to set the completionBlock property manually, instead of using setCompletionBlockWithSuccess:failure:.

Get the maximum value in an NSSet using KVC

You can get the maximum value in an NSSet full of NSNumbers using Key-Value-Coding like so:

NSSet *set = [NSSet setWithArray:@[ @1,@2,@3,@4,@5 ]];
NSNumber *maxValue = [set valueForKeyPath:@"@max.self"];

Value of maxValue is now @5.

It took me ages to find the correct KVC syntax for this. Source is linked below, and has a bunch of other cool uses of KVC.

funwithobjc:

(This was prompted by a recent question on StackOverflow.)

Key-value coding is one of my more favorite things about Cocoa (up there with NSPredicate). Basically, it allows you to access properties of objects by name (ie, as a string) rather than invoking a method (er… sending a message)…

7 notes

DMActivityInstagram

A UIActivity class for sharing images to Instagram.

iOS 6 introduced the new UIActivityViewController, which presents sharing options like Facebook and Twitter (as well as printing and copying). I wanted to adapt this for CatPaint, which currently uses ShareKit for sharing. My current Instagram sharer stopped working in iOS 6, and I figured now would be a good time to implement Instagram sharing using this new technique.

Usage is simple:

DMActivityInstagram *instagramActivity = [[DMActivityInstagram alloc] init];

NSArray *activityItems = @[self.imageView.image, @"CatPaint #catpaint", [NSURL URLWithString:@"http://catpaint.info"]];

UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:@[instagramActivity]];
[self presentViewController:activityController animated:YES completion:^{}];

Hopefully this code will be helpful for other people implementing their own UIActivity sharers, and getting Instagram support in to their apps.

I would love if someone took an axe to the visual design of the resizer view. It’s not my best work (especially on iPad it looks funny).

The resizer view is only needed if your app creates non-square images.

This is not in use in a shipping app yet, but it will be soon.

Python syntax checking in BBEdit using Flake8

I adapted jshell’s PyFlake gist (https://gist.github.com/1157742) to work with flake8, and my python setup. Took a bit of tweaking to get the regex right. I’ve bound it to Cmd-Shift-L, and I’ve been using it early and often.

Check it out if you’re a BBEdit/Python person: https://gist.github.com/3317713

0 notes

Interesting NSURLConnection quirk

You would expect this code always return a response, sometimes return data, and when there was no data, you could look at the response and the error to determine what happened. Not so! The response object is nil if it hits a NSURLErrorUserCancelledAuthentication (-1012).

NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (!data) NSLog(@"Network error: HTTP %i - %@", [response statusCode], error);

Changed to the code below, for now. Not sure how to deal with it long term though, may have to move away from my sendSynchronousRequest from within an NSBlockOperation technique of network queuing.

NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (!data || !response) NSLog(@"Network error: HTTP %i - %@", [response statusCode], error);

Addendum (setting up raspberry pi)

This is pretty cool / useful: https://github.com/pabloav/raspi-setup/

if only for https://github.com/pabloav/raspi-setup/blob/master/setup.d/05-airplay

0 notes