Visit my site @ mugunthkumar.com


Tags » ‘apple’

Save As vs Exporting – Why Apple excels at UI Design?

January 13th, 2010 by Mugunth Kumar

Most users think, Mac UI is all about slick graphics and “cool” icons. Well, that might be true partially, but user interface design isn’t about photoshopping or designing cool looking icons. According to Jakob Nielsen, aesthetics is just one aspect of usability. There is much more to user friendly software than just the “cool factor” or great icons.

Recently, I was using Microsoft’s Excel to edit a dozen large  CSV files. As a matter of fact, in Excel,  whenever you save “anything” you do as a CSV,  you will practically lose out features that aren’t supported natively by the underlying file format. For Example, CSV doesn’t support coloured cells. So when you colour a cell, and try to “save” it as a CSV, Excel pops up this dialog.

Saving as CSV loses of "certain" features

When you click “Yes”, all that Excel does is to “export” whatever content your file has into what the underlying format can support. So since, excel supports coloured cells but CSV doesn’t it ignores your colouring and proceeds saving it to CSV. Excel even goes one step far and doesn’t clear the “dirty flag” because, Excel hasn’t saved *every* change you made into the CSV.

Sounds good so far. But what’s really wrong here? The real problem is, Excel gives you a sense of feel that “everything” have been saved and you are safe. Things become bad when you quit Excel. Because the dirty flag isn’t cleared and the file haven’t been saved completely, Excel prompts you to “save” the file again. Specious, not wanting to take chances, some users like me, save the file again. Again the same thing happens and the end user is still just dumbfounded and asks, But, why the heck should I save it again?

Microsoft UI designers have failed to understand the end users. In this case, it’s because Excel fails to speak the users’ lingo. According to the user, when he “saves” a file, he saves a copy and he is contended that he can always re-open when something bad happens. But excel just “exports” the file into CSV format and tells the user that it “saved” the file (when it in fact didn’t). As a result what happens is data loss. No not just cell colours, in cases, when the users doesn’t know that CSV doesn’t support multiple sheets, excel doesn’t export (or save) the second sheets data and the user just loses the entire content from the second sheet. Disaster! In one of the cases where I work, a co-worker of mine, has got used to these prompts which Excel shows after you “save” your file as CSV

Prompts user to save the "saved" file again

and he just closes Excel assuming that these prompts are nothing but “bugs” in Excel. (Yeah see, he is a half techie and a little knowledge is dangerous.) Things went fine when he didn’t lose data, but just lost some formatting here and there. But the real disaster happened when his second sheet containing over 1000 lines and 3 hour work was lost.

Now, lets’ see how Numbers, the equivalent software from Apple handles this.

Save As panel for Numbers.app

Apple doesn’t even include CSV or other “lossy” formats in the save as sheet. That doesn’t mean, Numbers can’t “save” your data as CSV. But rather Apple calls it as “Export”. Files you export as CSV aren’t yet saved. So, when the user quit Numbers, and get a prompt to save the document, he will not confused.

Because Microsoft does it this way (wrong way), other software makers like Adobe too make the same mistake. Photoshop “saves” a file as PNG and still give you a sense of feel that you have saved the file. Another such example is audacity and paint.net and even those “save as PDF” plugins. They actually don’t “save” your data, but rather export it. Apple gets it right, but the whole world gets it wrong, Unfortunate!.

bit.ly wrapper for Objective-C/iPhone

September 26th, 2009 by Mugunth Kumar

Continuing from my part 1, in this section, we will discuss about how to use this helper in your own application.

Source Code


Download the source code here
MKBitlyHelper 1.0.zip

Documentation

With just three lines of code, you can shorten your URL using this wrapper.

Initialize the helper class with your loginname and apikey.

bitlyHelper = [[MKBitlyHelper alloc] initWithLoginName:@"yourlogin" andAPIKey:@"yourapi"];

In your application, you can either provide your application specific API or user provided API. Logging into the bit.ly api helps in tracking the click throughs and referrals. The classes doesn’t provide a login or APIKey by itself.

Now, shortening or expanding URLs is as easy as calling these functions.

NSString *shortURL = [bitlyHelper shortenURL:@"http://mugunthkumar.com"];
NSString *longURL = [bitlyHelper expandURL:shortURL];

Disclaimers and other yada yada…

Be forewarned that it may have errors. As Donald Knuth says,

Beware of bugs in the above code; I have only proved it correct, not tried it.

Feel free you use this code and re-distribute it. The source code must retain the copyrights and my attribution in any derivative works of the source code.

On your application, you might opt to attribute me in your app though it’s not mandatory. I would be happy if you do so ;-)

Consuming a RESTful Service (bit.ly) in an iPhone Application

August 14th, 2009 by Mugunth Kumar

Introduction

Of late, many programmers who develop for Windows/Linux have moved to iPhone because of it's runaway success. Among the most successful apps on the Apple AppStore, first comes games (yeah I can hear you, fart apps!!!). Next comes apps like Tweetie and others those consume a web service (REST or otherwise). Games are pretty difficult get started especially if you aren't a game programmer. However, developing iPhone applications that consume a web service is quite easy. In this article, I'll illustrate how to write a iPhone application to consume a web service. I'll take bit.ly's REST service as an example, and at the end, we will be developing a nice "bit.ly" wrapper in Objective-C. For those who are new to REST, it stands for Representational State Transfer. Head on to Wikipedia here for more details. The post itself is split into two parts, one focussing XML and the other JSON.
At the end of the second part, you can download the source code attached.

Bit.ly Documentation

Bit.ly, as you all know is a URL shortening service, that became popular all of a sudden when Twitter started using bit.ly as it's default URL shortening service over tinyurl.com. The REST documentation of bit.ly is available from Google code here.

Some Basics before we dirty our hands with real code

Authentication Types

bit.ly (and many such services) use a kind of HTTP authentication called Basic Authentication. In basic authentication, the username and password that is typed into the client is formatted as
: and the concatenated string is converted to "base64" encoding. This string is passed along with the HTTP Header usually in every API call that does some function which you have to normally log on to see.
There is one more type of authentication, oAuth, which stands from Open Authentication. As of now, bit.ly doesn't use oAuth. Explaining oAuth itself needs a separate article and is outside the scope of this article.

HTTP Request types

When you access a RESTful service, you either request data or post data. In most cases, your HTTP Request type is either a "GET" or a "POST". There are two more types of requests and they are, "PUT" and "DELETE". When to use what, is upto the designer of the RESTful service. You as a consumer, just follow the documentation.
In our case, bit.ly we will be using only "GET" methods.

The real code

You shouldn't be shocked to know that, accessing a RESTful service for data is just a matter of 10 line code.
NSString *longURL = @"http://mugunthkumar.com"
NSString *baseURLString =
@"http://api.bit.ly/shorten?version=2.0.1&longUrl=%@&login=bitlyapidemo&apiKey=";
NSString *urlString = [[NSString alloc] initWithFormat:@"%@%@",
baseURLString, longURL];
NSURL *url = [[NSURL alloc] initWithString:urlString];
NSString *result = [[NSString alloc] initWithContentsOfURL:url];

NSLog(result);
[url release];
[urlString release];
[result release];

Parsing the Result

The result which we "NSLogged" here could be either XML or JSON. In our case, bit.ly by default sends JSON formatted data, which is by far the most commonly used. JSON is lighter than XML for transferring the same amount of data. There are a lot of debate going along on which is good for data transfer. I personally prefer JSON. Of late, JSON is picking up over XML with the advent of JSON parsers. Objective C has a very robust JSON parser called json-framework. We will touch about them later in the next part of this article. The other kind of data format namely XML, is returned by bit.ly, only when you pass

format=xml

along with the URL as an additional parameter. For parsing XML, there are two parsers. One is NSXMLParser and the other is a faster libxml2. Though libxml2 is faster, use it on your iPhone app only when you are going to parse over 10MB of XML data. When your XML data is small (as in our case), the performance gap between NSXMLParser and libxml2 is very meagre. In case of bit.ly, the shorten api returns < 1KB of data. Most RESTful service return very little data (mostly in the order of few hundred kilo bytes) I prefer NSXMLParser for one reason. You code is cleaner than it would be if you use libxml2. In this article, I'll go take you through both ways of handling the data.

Parsing XML

[parser initWithContentsOfURL: url];
[parser setDelegate:self];


[parser setShouldProcessNamespaces:NO];
[parser setShouldReportNamespacePrefixes:NO];
[parser setShouldResolveExternalEntities:NO];

[parser parse];
[parser release];

Parsing XML data using NSXMLParser couldn't be simpler. You just have to create an object (parser) of type NSXMLParser, initialize it and call parse.

Things to note

However, there are a couple of things to note.

1) You can initialize the parser object either with NSURL or with NSData. Both methods work equally well.
2) You OUGHT to set the delegate to self. Otherwise there is no way for the NSXMLParser to notify you of events.
3) The next three lines are optional. You usually set it to YES if you want to get notified of those events as well.
4) The call to [parser parse] is blocking. This means, it will not return until the complete content is parsed. So, you can (and should) release any associated memory at the next line.

Callbacks from NSXMLParser

NSXMLParser has around 14 callback methods. But it's enough if you implement just three of them. They are,

parser:didStartElement:namespaceURI:qualifiedName:attributes:
parser:didEndElement:namespaceURI:qualifiedName:
parser:foundCharacters:

The didStartElement is called when the XMLParser encounters a opening XML element. You usually initialize temporary variables and read attributes if any in this function. In case of bit.ly, you just have to read the "shortUrl" element. Just handling this element alone will do.

ShortURL from bit.ly

ShortURL from bit.ly

Declare the following NSStrings, currentShortURL, actualShortURL and currentElement.
Write the following code into the didStartElement Block.
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
currentElement = [[elementName copy] autorelease];
if ([elementName isEqualToString:@"shortUrl"]) {
currentShortURLString = [[NSString alloc] init];
}

Now, in the foundCharacters block, write the following code.
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if ([currentElement isEqualToString:@"shortURL"]) {
[currentShortURLString appendString:string];
}

In the didEndElement block write,
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:@"shortURL"]) {

actualURLString = currentURLString;
}

Now when the parsing ends, just after the [parser release] function, actualShortURLString will contain the shortened URL.

End of story. If you couldn't follow the code in this blog post, you can always download the source code attached (in next part). For more detailed information on parsing using NSXMLParser follow this article.

Parsing JSON

Parsing JSON is much simpler than XML. In fact, I hate to call it as "parsing" as you don't even have to write a parser!!! By using the open source json-framework kit for iPhone you can easily "convert" a JSON string into a NSDictionary. Now let's have a look at the code.

JSON Parsing Code

JSON Parsing is far much simpler than XML. Infact, the code attached below uses JSON.

Parsing the bitly information is as simple as writing these three lines of code.
SBJSON *jsonParser = [SBJSON new];
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSDictionary *dict = (NSDictionary*)[jsonParser objectWithString:jsonString];

The return string is a dictionary of key value pairs.To read a value, you can call objectForKey function within NSDictionary.

In most cases, including bit.ly, JSON return strings always contain other dictionaries nested within itself. To read a value within a dictionary, just nest your calls  like this.
NSString *shortURL = [[[dict objectForKey:@"results"]
objectForKey:f_longURL]
objectForKey:@"shortUrl"];

Source Code and Documentation

The source code and documentation on how to use this is explained in post 2.


10 visitors online now
10 guests, 0 members
Max visitors today: 19 at 05:00 pm SGT
This month: 58 at 03-01-2010 02:57 am SGT
This year: 59 at 02-12-2010 06:23 am SGT
All time: 59 at 12-19-2009 09:48 pm SGT