Mac
Mac AppStore Launch
3The Mac AppStore (MAS) is coming to a Mac near you on the 6th January 2011, but is it going to change the software landscape on the Mac forever ?
Number of applications:
If there is one thing that we can be sure of, it is that the number of applications available for Mac OS will increase due to the introduction of the MAS. There will be iOS developers jumping on board (who are in for a shock when they see NSTableView), and also developers coming “Back to the Mac” after spending some time doing iOS development.
Quality of applications:
Quality and Quantity are two very different things. Just because the quantity of applications increases, that doesn’t mean that the number of high quality applications (that we have come to expect on the Mac) will increase accordingly. I (unfortunately) think that there will be a lot of substandard applications released for the Mac, simply because of the MAS making distribution easier. I do however think that there will be a few gems uncovered because of it.
Price of applications:
When the Mac AppStore was first announced, developers contemplated raising their prices to compensate for Apple taking a 30% cut of the revenue (compared to <10% for most other providers), now developers are thinking the opposite … lets lower prices. I don’t think that this will be as extreme as the “race to the bottom” on the iOS AppStore, as Mac applications usually take longer to build than there iOS equivalents. This is mainly because iOS has a more modern set of APIs, and on the Mac you have to support extras like Drag and Drop, Keyboard Shortcuts etc.
I think that Mac AppStore application pricing will fall into 4 main categories:
- < $5 – Simple single purpose applications
- $10 – Simple applications with an iOS sized feature set
- $20 – $40 Fully featured applications
- $40+ Professional applications like Microsoft Office, Adobe creative suite etc
Application Sales:
The simple fact is that people are more willing to give their payment details to Apple, rather than entering them on an indie developer’s website. If, and it is a big if, you get a prime place on the Mac AppStore (featured,top 25s etc) your sales are likely to be huge. For all the other applications on AppStore, time will only tell if it dramatically increases sales beyond the number of sales gained from the security of purchasing through Apple. I do believe however that non MAS sales will suffer a lot. The people that currently purchase applications online are likely to be “tech savy”, and therefore they will know about the MAS. Why would these users not switch to purchasing all of their applications through Apple ? the fact is they will.
Hello AppStore bye bye Serial codes:
There are a few benefits of distributing applications through the AppStore rather than handling distribution yourself. One of the major pains is payments and serials, which can take up a considerable amount of an application’s development time. This along with handling updates, is now removed from a developers workload with the introduction of the MAS, saving developers time and a lot of headaches.
Conclusion:
On the whole I can only see the Mac AppStore being a positive thing for Mac users and developers alike. Developers have a central place to sell their products from, and they don’t have to worry about getting it listed on numerous application sites. Users will have a an application (pre installed on their Mac !!!) which will allow them to search, view and securely purchase thousands of applications using just their Apple ID.
This could be a very big year for the Mac…
MacRuby – First Impression
6What not Objective-C !!! whats going on, I hear you cry. Well I thought I would mix things up a bit, after all it has got Mac in the name.
I am a firm believer that learning a new language, makes you better at developing with the ones you already know. Different languages often attack problems from different angles, depending on the language’s capabilities (built in classes etc) and common design patterns. Im sure people that are new to iPhone/Mac programming, where shocked about how often they had to type the word delegate.
So why Ruby ?
I admit it, I have played with Ruby before and the fact that I quite like it did help its cause, but that isn’t the main reason. The main reason is the fact you can use it for almost anything. You can use it as a CGI script on the web, you can build Web applications using Ruby On Rails, you can do shell scripting to automate tasks, and obviously you can build desktop applications.
So what is MacRuby ?
MacRuby is Ruby 1.9 built on top of the Objective-C runtime, which allows you to build Mac applications using Ruby (Its actually an Apple run project). The real sexy bit is you can call any Objective-C method directly using Ruby, meaning that you have access to all of OS X functionality. What is even more surprising, is that you can use Interface builder to put together your UI (well it was a surprise to me anyway).
Unfortunately MacRuby doesn’t currently work on the iPhone as it needs the garbage collector, but at some point this may change.
Interface Builder
So if your using interface builder, your need to declare IBOutlets so you can access a UI elements from in your code.
Objective-C
IBOutlet NSTableView *tableView;
In Ruby you don’t actually type cast your variables, so the only way to achieve this is to declare an accessor to that variable.
attr_accessor :tableView
In addition to IBOutlets your also need to declare IBActions for button presses etc.
Objective-C
- (IBAction)pressMe:(id)sender{
}
In Ruby you need to define a method with the sender parameter
def pressedButton(sender)
end
Calling Objective-C methods from Ruby
As you are building Mac application with Ruby, you will want to access the vast array of APIs available in Mac OS X. These are (mostly) written in Objective-C. One common task is creating a string:
Objective-C
NSString *string = [NSString stringWithString:@"Test string"];
In Ruby you do the following. Notice that there is no pointers and you do not need to declare a type.
string = NSString.alloc.initWithString("Test String")
*As Ted Wise correctly points out in the comments, you can create a NSMutableString by do the following piece of Ruby code, but I thought the string example was a nice and concise one to use.
string = "Test String"
From the above code snippets you will also notice that like most languages, Ruby doesn’t “stagger” its variables like Objective-C.
So how would you call the following Objective-C code snippet in Ruby ?
NSAlert *alert = [NSAlert alertWithMessageText:@"title"
defaultButton:@"ok"
alternateButton:nil
otherButton:nil
informativeTextWithFormat:@"This is an alertview"];
[alert runModal];
Well quite easily actually, as MacRuby actually adds this syntax to Ruby, so it would look like the following:
alert = NSAlert.alertWithMessageText("Title", defaultButton:"OK", alternateButton:nil, otherButton:nil, informativeTextWithFormat:"This is an alertview")
alert.runModal()
Easy enough ?
Conclusion (of my first impressions)
This post quite literally touches the surface of MacRuby, but I think it is an exciting technology. Ruby is really good for getting stuff done quickly, as the language does a lot of heavy lifting for you. By doing the Model part of the MVC in Ruby, you could in theory share the code across applications on the desktop and the web, which can’t be bad.
If your new to the Mac and don’t know ether Objective-C or Ruby, I would still learn Objective-C first if I am being honest. Learning Cocoa is hard enough without all the examples being in another language. But if your new to the Mac and already know Ruby, it might be a good way to start mac development.
Show hidden files in the Finder
4Sometimes when you are digging around in the under pinnings of Mac OS X, you need to access folders and files that are normally hidden by the OS. Thankfully there is preference in the Finder for this, which you can turn on and off in the Terminal.
The command is:
defaults write com.apple.Finder AppleShowAllFiles YES
The Finder needs to be restarted for this change to take effect. Luckily there is a Terminal command for this too:
killall Finder
Once you are done playing around with hidden files, you can stop showing them by replacing YES with NO in the original terminal command.
defaults write com.apple.Finder AppleShowAllFiles NO
It is as simple as that, but make sure your don’t break anything.
URL Encoding
5If you have tried to send any information using a GET web request, you would have come across an annoying problem. That annoying problem is making sure that the URL is correctly encoded.
At first glance it would seem that the Cocoa Frameworks do this for you, and you would be right …. well kind of.
The issue is that by default most of these methods leave characters such as & = ? within a URL, as they are strictly speaking valid. The problem is that these characters have special meanings in a GET request, and will more than likely make your request in valid.
Luckily there is a function in Core Foundation that helps:
1 2 3 4 5 6 7 | CFStringRef CFURLCreateStringByAddingPercentEscapes ( CFAllocatorRef allocator, CFStringRef originalString, CFStringRef charactersToLeaveUnescaped, CFStringRef legalURLCharactersToBeEscaped, CFStringEncoding encoding ); |
What makes this function useful, is the legalURLCharactersToBeEscaped parameter. This will escape legal characters such as & ? = if they are supplied. This allows you to escape parameters using the following code.
1 2 | CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)parameter, NULL, CFSTR(":/?#[]@!$&’()*+,;="), kCFStringEncodingUTF8) |
An example of when to use this, is Twitters Update status API. You can find that here http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-statuses%C2%A0update
To update your status to the following:
This is my status
You would need to post up the following URL:
http://twitter.com/statuses/update.xml?status=This%20is%20my%20status
As this is such a common problem of mine, I have created a category on NSURL. This allows you to pass in a base URL and a parameters dictionary.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | + (NSURL *)URLWithBaseString:(NSString *)baseString parameters:(NSDictionary *)parameters{ NSMutableString *urlString = [NSMutableString string]; //The URL starts with the base string [urlString appendString:baseString]; NSString *escapedString; NSInteger keyIndex = 0; for (id key in parameters) { //First Parameter needs to be prefixed with a ? and any other parameter needs to be prefixed with an & if(keyIndex ==0) { escapedString = (NSString*)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)[parameters valueForKey:key], NULL, CFSTR(":/?#[]@!$&’()*+,;="), kCFStringEncodingUTF8); [urlString appendFormat:@"?%@=%@",key,escapedString]; [escapedString release]; }else{ escapedString = (NSString*)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)[parameters valueForKey:key], NULL, CFSTR(":/?#[]@!$&’()*+,;="), kCFStringEncodingUTF8); [urlString appendFormat:@"&%@=%@",key,escapedString]; [escapedString release]; } keyIndex++; } return [NSURL URLWithString:urlString]; } |
Using a parameters dictionary keeps the code nice and clean, but beware, to use the category method above you still have to make sure that your keys, and the base URL are correctly encoded (no spaces or invalid characters !!!!!).
As we now have a category method to do all the hard work for us, to create the Twitter URL you just need to do the following:
1 2 3 4 5 | NSString *baseString=@"http://twitter.com/statuses/update.xml"; NSDictionary *dictionary=[NSDictionary dictionaryWithObjectsAndKeys:@"This is my status",@"status",nil]; NSURL *url=[NSURL URLWithBaseString:baseString parameters:dictionary]; |
And thats it. Obviously this category can be used for things other than twitter ….. if you really want to.
Reopening an application’s main window by clicking on the Dock Icon
1When building Mac applications, Apple usually takes care of most of the default behaviours for you. One thing that Mac applications don’t do by default is, reopening the applications main window (if it has been closed), when the dock icon is pressed.
Although this information is very hard to find in the documentation, but is actually very easy to. The method you need to find is:
1 | - (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag; |
This is an optional delegate method that your AppDelegate can choose to implement, and is called when the user presses your application’s dock icon. The bool flags indicates whether the application has any visible windows. To reopen your application’s main window, you need to have a pointer to it (In the example below assume that it is defined as NSWindow *window; in the header file). If you do have a pointer to then you simple need to implement the code below.
1 2 3 4 5 6 7 8 | - (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag{ if(flag==NO){ [window makeKeyAndOrderFront:self]; } return YES; } |
It is as simple as that.