BuySellAds.com

Until Dec 3rd, 44% off all Manning books, including Barcodes with iOS! Promo code: mobicftw
Our DNA is written in Objective-C
Jump

Uploading UIImages to TwitPic

One day of the week I hope to do something that’s not really business oriented, I call it my “Friday-Project”. This title comes from my time in IT where you would generally avoid do any major changes to the systems you are maintaining on Fridays because nobody likes to work on fixing these on the following weekend. So Friday is a great day to just experiment, prototype or dream. At Google they are supposedly giving their employees 20% of their working time for such projects, so I am dedicating as much time to playful exploration as well.

Today I want to explore and hopefully finish some code to upload an image to TwitPic. So the first step is to have a look at their API documentation which is not very pretty, but at least it’s complete. There we see that we want to implement the uploadAndPost function.

METHOD: http://twitpic.com/api/uploadAndPost

Use this method to upload an image to TwitPic and to send it as a status update to Twitter.

Fields to post in post data should be formatted as multipart/form-data:

- media (required) – Binary image data
– username (required) – Twitter username
– password (required) – Twitter password
– message (optional) – Message to post to twitter. The URL of the image is automatically added.

Sample response:

<?xml version=”1.0″ encoding=”UTF-8″?>
<rsp status=”ok”>
<statusid>1111</statusid>
<userid>11111</userid>
<mediaid>abc123</mediaid>
<mediaurl>http://twitpic.com/abc123</mediaurl>
</rsp>

For this we need to construct an HTTP POST request to the URL http://twitpic.com/api/uploadAndPost and construct a multipart body with binary image data, Twitter username, password and an optional message. The response will be XML giving us the URL we can use to link to the picture.

Having the parameters intermixed makes it a bit harder especially if you have never constructed a multipart body before. The easiest method of image uploading is if you can specify parameters in the URL, but the designer of this API thought it smarter to have it in the body. But don’t worry, we’ll get this figured out as well.

Read more

App Information String Tokens

For my current project DTAboutViewController I need to be able to specify tokens in my strings that would be replaced by information about the app at runtime. Of specific interest are CFBundleDisplayName and CFBundleVersion which are both in info.plist. Usually you could hard-code these into your app strings or maybe do a global #define, but for my component I wanted to have the most flexibility with the least amount of work in subsequent project that would use that.

So I put together a category extension for NSString which also shows off how to use NSScanner to find tokens and replace them with values from your info dictionary.

NSString+Helpers.h

#import 
 
@interface NSString (Helpers)
 
- (NSString *) stringBySubstitutingInfoTokens;
 
@end

NSString+Helpers.m

#import "NSString+Helpers.h"
 
@implementation NSString (Helpers)
 
- (NSString *) stringBySubstitutingInfoTokens
{
	NSMutableString *tmpString = [NSMutableString stringWithString:self];
	NSScanner *scanner = [NSScanner scannerWithString:self];
 
	NSDictionary *infoDict = [[NSBundle mainBundle] infoDictionary];
 
 
	while (![scanner isAtEnd])
	{
		if ([scanner scanString:@"$" intoString:nil])
		{
			NSString *tokenName;
 
			if ([scanner scanCharactersFromSet:[NSCharacterSet alphanumericCharacterSet] intoString:&amp;tokenName])
			{
				id value = [infoDict objectForKey:tokenName];
 
				if (value &amp;&amp; [value isKindOfClass:[NSString class]])
				{
					[tmpString replaceOccurrencesOfString:[@"$" stringByAppendingString:tokenName] withString:value options:NSLiteralSearch range:NSMakeRange(0, [tmpString length])];
				}
			}
		}
 
		[scanner scanUpToString:@"$" intoString:nil];
	}
 
	return [NSString stringWithString:tmpString];
}
@end

The code works by skipping all characters until it encounters a $, which will be our token identifier. From this position the name of the token is until the first non-alphanumberic character, like a space or period. Then it tries to get a value from the bundle’s info dictionary. If it succeeds the token is replaced in a temporary string, if not it is left unchanged.

Note how I am passing nil into scan functions if I am only interested in skipping characters. If I am interested in the scanned result, then I am passing the address of a pointer to an NSString, that’s the reason for the &tokenName. The scan method creates an autoreleased copy of the scanned string and puts the pointer to this string into the parameter the address of which you have passed. That’s unusual in objective-C and seen more often in pure C code, so be aware of that.

Now with this code I gain a very useful way of displaying copyright information as the section footer of my settings table.

- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
{
	return [@"© 2010 Drobnik.com. $CFBundleDisplayName $CFBundleVersion" stringBySubstitutingInfoTokens];
}

This will look like this, the app’s bundle display name is “About” and the version string is “1.0”.

With this method it’s even thinkable to put your own information into info.plist. Like for example the ID of your app which you would use for a direct link to the review page. Some people complain that Cocoa does not have regular expression support, but actually if you know how to use NSScanner properly you can do even more with it than trying to piece together working regexps.

“Are You a Cocoa Crack?” Quiz (2)

It’s been more than half a year since I published the first installment of this Quiz aimed at Cocoa Cracks. Back then people seemed to like the challenges I presented. So I collected a few more nuggets. If you ever stumbled on an crash or strange result that you did not expect, then mail it to me.

These questions will show if you are really the Cocoa Crack you like to believe to be. To see the answer highlight the answer text with your mouse. No peeking! Respond in the comments how many you got correct.

Quiz: Warm Up. Your UI designer gave you a PNG with the instruction “just tile this in the background” of a UIView. Do you have to subclass UIView, overriding the drawRect of the view and performing drawImage for all tiles? Or is there a simpler method?

Answer: You create a UIImage by loading the PNG and then create a “color” from it with [UIColor colorWithPatternImage:image]. Then you apply this as the background color of the view.


Quiz: Suddenly your app crashes and when the debugger opens it first loads lots of stack frames. All you did is override a property like shown below. What’s the bug? Bonus Question: where’s the memory leak?

- (void) setTextColor:(UIColor *)newTextColor
{
	if (newTextColor != textColor)
	{
		[textColor release];
 
		if (newTextColor)
		{
			self.textColor = [newTextColor retain];
		}
		else // default
		{
			self.textColor = [[UIColor whiteColor] retain];
		}
		bubbleView.highlightedTextColor = textColor;
	}
}

Answer: You have an endless recursion. self.textColor is a simplified way to write [self setTextColor:]. So this method keeps calling itself until the stack is full and your app gets terminated. The leak is calling retain on an assignment to a retaining property. But if you fix the crashing bug by removing both self then there is no leak.


Quiz: You want to draw two lines in a drawRect, a horizontal black line and a white line 1 pixel below it. So you write the following code. But instead of the intended result you get this picture in magnification, the black is dark gray and the white is a lighter shade of gray. Why is that and how would you fix it?

CGContextRef currentContext = UIGraphicsGetCurrentContext();
 
// Draw a black line at the top and a white line 1 pixel below
 
CGContextSetLineWidth(currentContext, 1);
 
CGContextSetRGBStrokeColor(currentContext, 0.0, 0.0, 0.0, 1.0); // Black
CGContextMoveToPoint(currentContext, 0, 0); // top left
CGContextAddLineToPoint(currentContext, rect.size.width, 0); // to top right
CGContextStrokePath(currentContext);
 
CGContextSetRGBStrokeColor(currentContext, 1.0, 1.0, 1.0, 1.0); // White
CGContextMoveToPoint(currentContext, 0, 1); // left
CGContextAddLineToPoint(currentContext, rect.size.width, 1);
CGContextStrokePath(currentContext);

Answer: Core Graphics does not work on pixels directly, that’s why you use floating point numbers for coordinates. It works on coordinates and the resulting bitmap is always rendered. Half of the line width is always applied half a unit to each side of the line. To remedy this you need to move the coordinates of the lines by half a unit up or down.

(Thanks to Michael Kaye for sending this in)


Quiz: You have a UITableView and would like for it to have rounded corners. What’s the fastest way to achieve that? Which header is necessary?

Answer: You can have any UIView have rounded corners by setting the cornerRadius property of it’s CALayer. The layer of a UIView is actually what’s responsible for drawing the contents of the view. You need: to import <QuartzCore/QuartzCore.h>


Quiz: You have created a UIViewController which shows a UIWebView and has a navigation bar. You want to set the title on the bar to be the same as the title of the HTML document once loading has finished. Would you need to parse the HTML with NSScanner to find the <title> tag and extract it? Or is there a simpler method?

Answer: In the webViewDidFinishLoad: delegate method you retrieve the title via javascript and set it like that. self.title = [webView stringByEvaluatingJavaScriptFromString: @"document.title"];


Quiz: You have written code to load some UIImages in the background (performSelectorOnBackgroundThread or NSInvocationOperation). The loading code calls the method below to resize the loaded image. This has “always working before”, but suddenly you keep getting a EXC_BAD_ACESS on the line marked. You have double checked all retains and even set NSZombieEnabled to YES because usually you get this message if you are using an overreleased object. But that did not fix the problem. What’s the reason for the crash and how would you fix it?

+ (UIImage*)imageWithImage:(UIImage*)image
			  scaledToSize:(CGSize)newSize;
{
	UIGraphicsBeginImageContext( newSize );
	[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];   // &lt;- crash
	UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
	UIGraphicsEndImageContext();
 
	return newImage;
}

Answer: UIKit is not thread-safe. Therefore all drawing via UIKit needs to happen on the main thread. The UIGraphicsBeginImageContext works to create the context, but the memory for it is owned to the main thread and trying to access it with drawInRect from another thread is causing this exception. To fix it you need to rewrite this method to create your own bitmap context on the non-main thread so that you then own the memory for it. After creating the bitmap context you draw the image to it with CGContextDrawImage and then create a new CGImage with CGBitmapContextCreateImage. From the CGImage you create a UIImage to return from the method.


Quiz: Off the top of your head: how many methods do you know of having a piece of code contained in one method being performed in the background? Which?

Answer: Correct Answers are: performSelectorOnBackgroundThread and creating an NSInvocationOperation from the selector as those work on an existing method. Creating an NSOperation sub-class or manual threading with NSThread are also valid answers, but those require that you move the code into a new class or need to be well versed with threading voodoo.


So how many answers did you know? Be honest! If you also have a Cocoa riddle like these to contribute please mail them directly to me (oliver@drobnik.com) and I will publish them in this format.

UIImageView + Touch Handling = UIButton

gdscei asks:

“Hello, how can i make an image view work as a button? I want it to be assigned to the ‘reload’ action of WebView.
Can someone give me instructions how to do this?”

Often people start out constructing their UI visually, starting with this line of reasoning “I want to show an image. Ah, UIImageView”. So they create the visual appearance of their UI either by clicking it together in Interface Builder or – if slightly more advanced in their coding skills – creating those image views in code.

So if we create a new view-based project in XCode, we could modify the viewDidLoad of the main view controller like this to show the image:

- (void)viewDidLoad {
    [super viewDidLoad];
 
	UIImageView *imageView = [[UIImageView alloc] initWithFrame:
		CGRectMake(100.0, 100.0, 57.0, 57.0)];
	imageView.image = [UIImage imageNamed:@"Icon.png"];
	[self.view addSubview:imageView];
	[imageView release];
}

The next logical step in reasoning right after displaying the icon is now to get touch handling somehow. And that’s where you will get stuck because UIImageView is a dead end when it comes to reacting to the user’s finger.

Read more

Making a "Follow us on Twitter" button

I am working on the ultimate “About Page” component at the moment. And of course this won’t be complete without a button to follow the developer on Twitter. Tapbots is one company that has the best role model for modeling this. They have this little button here at the bottom of their about page:

There is something amazing that happened when I tapped on this “Follow us on Twitter” button: it opened up the tapbots user right in Tweetie 2! I was astonished at first, but then it dawned on me that on the iPhone you can have your app respond to a custom URL scheme and obviously some Twitter clients support going to the user’s profile page. I have only Tweetie 2 installed and incidently this supports just that.

Read more

DTLEDNumberView

When experimenting with the iPhone’s built-in LED font I found it severely lacking in terms of usability. It’s designer has had the glorious  idea of not making all numbers the same size. This means that if you have any kind of changing label (like for example a digital clock) then the contents of the label will jump around as digits change size. This is especially annoying going from or to a one which is extra slim.

Generally my instinct is to use regular smooth fonts for display of numbers, but I find that every 2 or 3 months I get into a situation where the classic LED look would be the perfect gimmick. For example I am still pondering how to make the UI of GeoCorder more attractive and one idea was to have the measurements be displayed in LED numbers.

So I set out to create a reusable solution for this problem. A quick search on Google gave me this image from iStockphoto. It does have their watermark, but I was not going to simply off their images. Instead I used it as a template to construct a resolution-indendent drawRect for my DTLEDDigitView. The resolution was just big enough so that I could find the edges in my image editor and make the appropriate connections.

Basically you cut out the 8 which has the best contrast on all sides and then you get the coordinates of each corner of each bar. To make it resolution-indendent you then multiply each value with a unit size for width and height so that this scales nicely. The main reason why I wanted it to be resolution-independent is that this will look nice very small but also on the many extra pixels that are available on the iPad. So if you use DTLEDNumberView you don’t have to worry about static LED number images being scaled into fuzzyness. My solution is always crisp.

Then I added code to turn on and off single bars depending on the digit property. Also I wanted to be able to control the dot, so I added a property for that. Activated bars are paths filled with this distinct red, non-activated bars are 100% white with 30% alpha so they will lighten any background slightly. That’s all about the drawing.

Very useful when creating custom views like this is to fill in the sizeThatFits method with some algorithm that will adjust the width and/or height accordingly. In this case I am using it to find a scaling where the aspect ration of the numbers still fits in.

Then I took the DTLEDDigitView and made a view to add to itself as many such digits as a property numberOfDigits would decide. Optionally there is a property numberOfDecimalPlaces which decides how far from the right the comma is. The final touch is to have a value property and to adjust all the individual digits accordingly if it changes.

Here’s my demonstration video, it simply adds PI every tenth of a second so that you see the numbers change, also behind the comma.

I can immediately think of a number of useful customizations, like changing the colors for active and inactive and maybe adding a neon glow to the active bars. But for lack of a concrete application with it’s requirements I won’t fiddle around with it until there is one. I need either myself or somebody else to have an app to add this component to so that I know the final tidbits necessary.

The whole thing took me about a day to make so I’ll set the introductory price at 50 Euros. If you’d like to use this technique in your own apps, drop me an e-mail so we can discuss what extra features you would require to make the purchase.

GeoCorder 1.0.4

It’s been almost a year since my last update to GeoCorder, which is a handy little tool to quickly record GPS tracks and mail them to yourself for viewing in Google Earth or geotagging photos. It’s a very simple tool which I wrote to get GPX tracks for my own testing. If you believe the reviewers it serves it’s purpose very well

Since then SDK 3.0 was released and with it the possibility of sending attachments in E-Mails. Before that time I had to resort to sending the files via my own web server, but with this update this is now no longer necessary. And lately some reviewers started to complain about this old mode so I finally found a day to sit down and polish it up, fulfilling all the reviewer’s requests.

Changes

  • NEW: Set a distance filter to conserve battery life
  • NEW: Export via E-Mail now uses InApp E-Mail (if available)
  • InApp E-Mail: optional compression of sent GPX files
  • InApp E-Mail: GPX file now named with timestamp
  • German localization
  • Minor UI tweaks

The update covers GeoCorder and GeoCorder [FREE] and has been submitted to Apple for approval.

UPDATE: 29 hours later the update(s) are through the review process. That’s new record for me.

Developer Name Calling

I decided to concentrate on the iPhone platform back in Fall 2008 shortly after the general availability of iPhone SDK 2.0.  Since then I was frequently facing the necessity of describing what I do in a few words. Generally I described myself as “iPhone Developer”. But then two generations of the iPod Touch became just as important in sales as 3 generations of the iPhone and now Apple is releasing yet another category of device running iPhone OS, namely the iPad.

So the name “iPhone Developer” does not really feel like it encompasses all 3 device types. Especially if you are talking to laymen who don’t know about the OS being the common ground between all of them. So I asked the Twitterverse, with interesting and sometimes hilarious results.

“What should we call a developer who concentrates on developing for iPhone, iPod Touch and iPad”?

Read more

Understanding UIFont

Have you ever really TRULY looked at the documentation of UIFont?

I had to, because I was looking for some metrics information that I could use to custom draw UILabels. And if you want to be independent of what font is set, then you have to get certain metrics, but the Apple SDK documentation of UIFont leaves a bit to desire.

When I asked which characters would be good representatives of a font, I was sent a link to this blog “celebrating the beauty of the ampersand”. Fine, an ampersand will be there as well…

Read more

How to deal with contracting customers who won't pay

If you do a bit of contracting besides or publishing your own apps then you will have to deal with a wide spectrum of human beings. Some appreciate every tiny tidbit of love you put into their apps. Some of the more entrepreneurial kind will constantly come with new ideas but always assume that those where part of the initial agreement.

I’ve had an encounter with an illustrious specimen of the second kind and so I thought it would be therapeutic for my hurt pride to ask the tweeting community about their opinion. Here are the responses for a view of what other iPhone developers generally think about this topic. I got a big number of responses which for the most part contain good food for thought.

Read more