When passing data to a web site, especially via "GET" requests (e.g. calling + stringWithContentsOfURL:encoding:error:) it's important to ensure content is properly escaped. This is also true on the iPhone when you are attempting to use a "mailto:" URL to invoke the native e-mail client from your app.
One obvious way to do this is by calling NSString's "- (NSString *)stringByAddingPercentEscapesUsingEncoding:(NSStringEncoding)encoding" method. While this does a good job, it is not perfect and will miss things like "/", which may make some web services cry. The best way to do this encoding is to use:
CFStringRef CFURLCreateStringByAddingPercentEscapes (
CFAllocatorRef allocator,
CFStringRef originalString,
CFStringRef charactersToLeaveUnescaped,
CFStringRef legalURLCharactersToBeEscaped,
CFStringEncoding encoding
);This method lets you specify what you want encoded and what you want left raw. I threw together a really quick sample command line tool to show you the difference. Here are the salient lies:
NSString *url = @"<b>some HTML content</b> <a href=\"http://theresurgence.com/search/node/bible\">study materials</a>" ;
NSLog(@"Original text: [%@]", url) ;
NSLog(@"NSString percent escapes: [%@]",
[ url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]) ;
NSLog(@"CFURL percent escapes: [%@]",
CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(CFStringRef)url, NULL, CFSTR("!*'();:@&=+$,/?%#[]"), kCFStringEncodingUTF8));
And, here is the output:
Original text: [<b>some HTML content</b> <a href="http://theresurgence.com/search/node/bible">study materials</a>] NSString percent escapes: [%3Cb%3Esome%20HTML%20content%3C/b%3E%20%3Ca%20href=%22http://theresurgence.com/search/node/bible%22%3Estudy%20materials%3C/a%3E] CFURL percent escapes: [%3Cb%3Esome%20HTML%20content%3C%2Fb%3E%20%3Ca%20href%3D%22http%3A%2F%2Ftheresurgence.com%2Fsearch%2Fnode%2Fbible%22%3Estudy%20materials%3C%2Fa%3E]
Big difference without tons of additional code. Plus, you can use CFURLCreateStringByReplacingPercentEscapesUsingEncoding just as easily to unescape any string.
UITableViewCells with just three UILabels and the second has static-height UITableViewCells three UILabels and one UIImageView. For those two, the following settings are pretty important (translate Interface Builder settings to iPhone SDK calls if you are working – as I am – purely in code):

tableView:cellForRowAtIndexPath:. When I was prototyping, I had a good portion of the transformation code in that method and have since moved it to the XML parsing routines. Since I was not able to set my cells to be opaque, limiting the number of "inner" UIViews was also high on the priority list. I did not need to background load the images in the cells, so I did not have to resort to using a subclass of UITableViewCell but I *did* implement a very rudimentary caching system which helped to speed things up a bit:
NSMutableDictionary called "heights" (the key is the row number) which caches the row heights of each cell since one of the UILabels can drastically vary in height. You need to do something like the following in tableView:heightForRowAtIndexPath::
UILabel's frame size each time in tableView:cellForRowAtIndexPath: and also retrieve said hight and calculate the number of rows in tableView:cellForRowAtIndexPath::
UITableView. Rather than go through the effort of parsing HTML on the iPhone (as I already parsed the XML file) I built this simple method from some half-finished snippets I found. It has worked in all of the cases I have needed, but your mileage may vary. It is at least a working method (which cannot be said about most of the other examples). It works on the iPhone and in standard OS X coding.
- (NSString *)flattenHTML:(NSString *)html {
NSScanner *theScanner;
NSString *text = nil;
theScanner = [NSScanner scannerWithString:html];
while ([theScanner isAtEnd] == NO) {
// find start of tag
[theScanner scanUpToString:@"<" intoString:NULL] ;
// find end of tag
[theScanner scanUpToString:@">" intoString:&text] ;
// replace the found tag with a space
//(you can filter multi-spaces out later if you wish)
html = [html stringByReplacingOccurrencesOfString:
[ NSString stringWithFormat:@"%@>", text]
withString:@" "];
} // while //
return html;
}
Cocoa is cool and Objective-C is a great language, but I like/prefer Python and the PyObjC bridge makes my life easier and programming actually interesting/fun for me.
This Xcode project is an example of how easy it is to create useful custom views in PyObjC with an example of a graph view that displays a circular queue/buffer. Everything is done starting with an Xcode project which is available for download (76KB compressed archive) and modification. Here is a preview of what you can use out of the box:


The easiest and smallest part of the project is the RingBuffer class that implements a very simple circular queue/buffer and provides direct access to the list that stores the information:
# # RingBuffer.py class RingBuffer: def __init__(self, size): """ init with # of elements in the queue """ self.data = [ None for i in xrange(size) ] def append(self, x): """ take away one and put one in """ self.data.pop(0) self.data.append(x) def get(self): """ return the list so we can manipulate it """ return self.data
There's not a lot of rocket science there, but it's amazing how much code you can eliminate by taking advantage of Python's inherent capabilities. In this case, list initialization is a breeze and removal/insertion of new elements could not be easier.
Next up is the CBGraphView class itself:
It seems that 2009 is starting off with a Twitter phishing problem. Users are being "tricked" into clicking on links that then do all sorts of bad things.
While these attacks can come via "regular" URLs, we will eventually see phishers use sites like TinyURL to mask their destination, making it that much harder on desktop and in-stream protection mechanisms.

If you run OS X 10.5 (Leopard), I offer you Throw Them Back (592K compressed archive) as a way to stay a step ahead of the bad guys. This version (0.9) has two modes. The most useful one is where you start the app up, then copy a URL to the clipboard and invoke the global shortcut key (Command-Control-J :: this will be a configurable option in the next release) which will take the URL, expand it (if necessary) and run it through the PhishTank screening service to see if it is a "bad" site. PhishTank is run by OpenDNS and is a great service, but it is not comprehensive (no service would be). While you can pretty much trust the items tagged as phishing (indicated by a fish icon that will pop up in the window), you should not assume that a lack of notification equals an OK site.
If you are determined to press on even if you do not recognize an expanded URL (or are unsure about a standard URL), use the arrows next to the URL fields to bring up a drawer that will render the site filtered through Google Mobile. That should take care of any malicious code and let you see if this is a site you really want to visit.
The URL you pasted is put back on the clipboard, so you can use it anywhere you like and you can copy the short or expanded URL from the displayed fields.

The second mode is where you just enter or paste a URL right into the field in the window. While that is useful, it is not nearly as speedy.
I have a bunch of items on the TO DO list, including:
I welcome feedback and suggestions in the comments or on Twitter (@hrbrmstr).
| If you do like the software, please consider clicking the button on the right. I'm seriously contemplating making version 1.0 (this is version 0.9) something you have to pay for to get all the additional features. If you act now, you will receive free upgrades forever for just $3.99USD. Version 1.0 pricing will be $4.99USD. |
from objc import YES, NO, IBOutlet, IBAction
from Foundation import *
from AppKit import *
'''
a great deal of work is done in the nib/xib file.
it has the window and button and the menu that is set as
the status item. each menu item is wired either to a method
below or one in the first responder.
'''
class xAppDelegate(NSObject):
statusBar = None # holds our NSStatusBar
mStatusMenu = None # we store our status bar menu item here
mbImage = None # the image that will be our initial status item
redImage = None # an alternate status item
statusSub = objc.IBOutlet() # the menu that will be attached to the status bar item
prefsWindow = objc.IBOutlet() # the mock "prefs" window
button = objc.IBOutlet() # button in the mock "prefs" window that will turn status item red
# show "preferences" - called from menu item
@IBAction
def editPreferences_(self, sender):
self.prefsWindow.makeKeyAndOrderFront_(sender)
NSLog("Editing Preferences")
# returns our status bar icon to the starting image
@IBAction
def makeItNormal_(self, sender):
self.mStatusMenu.setImage_(self.mbImage)
NSLog("making it normal")
# turns our status bar icon to all red - called from button press
@IBAction
def makeItRed_(self, sender):
self.mStatusMenu.setImage_(self.redImage)
NSLog("making it normal")
# when we load the nib, get the images as well
def awakeFromNib(self):
self.mbImage = NSImage.imageNamed_("image.jpg")
self.redImage = NSImage.imageNamed_("red.jpg")
# we wired up the "Quit" item in our status bar menu to "terminate:" in the first responder
# this gets called when we really are going down
def applicationWillTerminate_(self, notification):
NSLog("We're going down")
# when the app instantiates our class, set the menu bar
def applicationDidFinishLaunching_(self, sender):
statusBar = NSStatusBar.systemStatusBar() # grabs the system status bar
# we may change the status bar item to a larger image, so variable length
self.mStatusMenu = statusBar.statusItemWithLength_(NSVariableStatusItemLength)
self.mStatusMenu.setImage_(self.mbImage) # set the initial image
self.mStatusMenu.setHighlightMode_(True) # we want visual feedback when clicked
#self.mStatusMenu.setTitle_("Status Menu") # if you uncomment this, you get a "word" menu vs image menu
self.mStatusMenu.setMenu_(self.statusSub) # sets the menu from the NIB
The source code is commented fairly well, but upon launch, the awakeFromNib and applicationDidFinishLaunching methods will be called and you should be able to follow what is happening. As the code states, a great deal of work is done in the nib/xib file where everything is wired up:


I've got a decent number of folks on Twitter who are also in my OS X Address Book and I wanted an easier way to keep their Twitter avatars in sync than just manually downloading and updating the images. Enter Taabu [297K DMG], my Twitter Avatar to OS X Address Book Updater.
As long as your OS X Address Book contacts have one URL field with their http://twitter.com/twitterid account in it (and you are following them), you will be able to use Taabu to update their OS X Address Book pictures with their Twitter images.
This currently works for up to ~98 contacts (all depends on your current Twitter API rate limit status, which you can use the widget in the previous post to keep track of) and is fine for me since I have far fewer than that I need to sync. Post a comment if you need that functionality as it will mean some coding to allow processing of your local contacts in batches (due to the rate limit situation). There's a "README" in the DMG download that gives a bit more info and some additional screenshots.
Requests, bug reports, complaints, accolades, etc are all welcome. (And, yes, there is a spelling error in "Downloadig" - will fix when I post the next release which will also contain the full, ugly Objective-C source code :-)
