Sunday, December 5, 2010

About WikiLeaks

This post is not about Objective-C, Cocoa nor anything technological. It is about something more important: WikiLeaks.

I am sure you have already heard that WikiLeaks recently published "United States diplomatic cables". Five major newspapers "helped" to spread the word about the published diplomatic cables. Around the globe people discussed the contents and thought about the impact such a publication might have on various things like international relations and mutual trust. Quickly the government of the United States recognized what has happened and took devastating actions:

  • Denial-of-service-attacks on WikiLeaks's servers
  • Content removal
  • Killing WikiLeak's domains

If this weren't enough companies all over the world are starting to "attack" WikiLeaks. Let me give you an example:

The Wau Holland Foundation is located in Germany. In the past the Wau Holland Foundation collected donations for WikiLeaks.  A few days ago PayPal closed the account of the Wau Holland Foundation. This means that nobody can donate via the Wau Holland Foundation anymore and that the already collected money seems to be lost. I donated hours before PayPal closed the account of the Wau Holland Foundation. I already asked PayPal for a refund so that I can donate the money via other channels. But hey - what PayPal did is not fair:

I am very angry about that what happened. Angry because I think that everybody is overreacting. We all know how much governments all over the world know about us. With us I mean the citizens of the world. The German government is passing law after law after law that allows them to know everything about us. The same is true for most governments these days which means that this is an international problem. All that a "normal" citizen can do is to demonstrate against those laws. Now look at our governments. Look at how they behave. Listen to what they are saying. Are they standing together as one demonstrating for their own rights on privacy? No! They behave like a child whose lolly pop fell on the dirty ground. No. Worse. They behave like a criminal.

There is so much going on at Twitter at the moment. Allow me to quote a few interesting Tweets:

@DanOnymity wrote: We elect Governments not to dictate our freedoms, but to support our liberty. They serve us, we do not serve them. #imwikileaks

@HansRottier wrote: Courage is what it takes to stand up and speak; courage is also what it takes to sit down and listen. #imwikileaks

@jdispinziere wrote: why are none of these trending? looks like twitter is censoring. #imwikileaks #wikileaks #cablegate

@voxhumanum wrote: The Big Brother is watching you. But, WikiLeaks is watching the Big Brother, for you. #imwikileaks

What do you think?

Sunday, October 17, 2010

Handling Initialization Failure

A few months ago a friend of mine asked me the following question: "What should I do if I want to return nil in one of my initializers?" Returning nil in an initializer is nothing fancy. I do it all the time. However, there are a few rules you should be aware of.
  • Only return nil (in an initializer) if you can't perform the initialization. If a caller passes your initializer a path to a file that does not exist and the object can't work without a file it would make sense to return nil.
  • Don't return nil if you can find a nice "workaround" for a problem during initialization such as replacing a missing argument with a sensible default value.
  • If you want to return nil and you haven't sent a initialization message to super yet perform the following steps:
    • cleanup any resources you may have created,
    • call [self release]; and then
    • return nil
  • If you want to return nil and already have sent a initialization message to super (which returned nil) perform the following steps:
    • cleanup any resources you may have created,
    • return nil
If you return nil you must have a good reason. It is a good idea to let the caller know what went wrong during the initialization process. In Objective-C/Foundation we can simply use NSError to pass the cause of a problem back to the caller. Imagine a class called Person. A Person has a first and a last name. One can create a Person by using -initWithFirstName:lastName:error:. If the passed first and/or last name is nil -initWithFirstName:lastName:error: creates an error object, sends release to self and returns nil.

#import "Person.h"

enum {
   PersonErrorCodeFirstLastNameNotValid = 0
};
typedef NSInteger PersonErrorCodes;

@implementation Person

@synthesize firstName, lastName;

- (id)initWithFirstName:(NSString *)initFirstName 
               lastName:(NSString *)initLastName 
                  error:(NSError **)error {
   if(initFirstName == nil || initLastName == nil) {
      if(error != NULL) {
         NSMutableDictionary *u = [NSMutableDictionary dictionary];
         [u setValue:@"first/last name not valid." 
              forKey:NSLocalizedDescriptionKey];
         PersonErrorCodes c = PersonErrorCodeFirstLastNameNotValid;
         *error = [NSErrorerrorWithDomain:@"com.example.unique" 
                                     code:c 
                                 userInfo:u];
      }
      [self release];
      return nil;
   }
   self = [super init];
   if(self != nil) {
      self.firstName = initFirstName;
      self.lastName = initLastName;
   }
   returnself;   
}

- (id)initWithFirstName:(NSString *)initFirstName 
               lastName:(NSString *)initLastName {
   return [self initWithFirstName:initFirstName 
                         lastName:lastName 
                            error:NULL];
}

- (id)init {
   return [self initWithFirstName:[NSString string
                         lastName:[NSString string]];
}

- (void)dealloc {
   self.firstName = nil;
   self.lastName = nil;
   [super dealloc];
}

@end

As you can see, this class has three initializers: -init, -initWithFirstName:lastName: and -initWithFirstName:lastName:error:. The designated initializer is -initWithFirstName:lastName:error:, which is used by a caller which is interested in the cause of a failed initialization. -initWithFirstName:lastName: can be used by a caller which only wants to create a Person and see if it worked or not.

Wednesday, October 13, 2010

Singletons to hell

In my talk about "Complex Projects with Cocoa" at a German iOS and OS X developer conference I warned the audience about the singleton design pattern. This warning resulted in something that I would call a small flame war about singletons. Although I have nothing against controversial discussions I was a bit surprised that many people tried to defend the singleton design pattern. For the rest of the conference I asked myself two simple questions:

  1. Why are so many people defending the singleton design pattern?
  2. How can these people be convinced that they are defending bullshit?

I will try to answer them both.

Why are so many people defending the singleton design pattern?

I think this is because the singleton design pattern is easy to understand. Most books and tutorials about design patterns first demonstrate the singleton pattern before anything else. So, every developer knows and understands the singleton design pattern. If this wouldn't be enough a singleton is often used by beginners to solve basic problems.

"I don't know how to pass an array from instance to instance. What do I do?"

Five minuted pass.

"Ah! LETS MAKE A SINGLETON!"

Another five minutes later and the poor developer has a singleton that holds the array of objects that can and will be access from everywhere. This makes the developer happy. He used a singleton to (superficially) solve a problem. One does not like to abandon something familiar. We all know that.

How can these people be convinced that they are defending bullshit?

Yes, there are singletons that make sense. No, I don't repeat what makes singletons so bad. So how do I convince you? Simply by quoting Erich Gamma. In an interview Erich Gamma, one of the authors of the famous book "Design Patterns: Elements of Reusable Object-Oriented Software", was asked the question "How would you refactor "Design Patterns?".

His answer:

"[...] When discussing which patterns to drop, we found that we still love them all. (Not really—I'm in favor of dropping Singleton. Its use is almost always a design smell.) [...]"

This should convince everybody.

 

 

Wednesday, August 18, 2010

Google please don't stand in the way of innovation.

Google Reader is a really cool web application. I use it myself and I like it very much. Over the last couple of month I have been working on a Cocoa based news reader for Mac OS X. I have not yet released it because we are still working on the design. But this it how it looks:

Screenshot Headline.png

Yes, the application is living in the menu bar. But it can also be used as a window based application:

Screen shot 2010-08-18 at 10.46.41 .png

But the most important part about this news reader is that it is integrated into Mac OS X very well. In fact the application is just a PubSub front end. PubSub is a framework provided by Apple that is managing a system wide database that knows which applications have subscribed to which feeds. This has some nice side effects. If you read something in our application it is also marked as read in another application (Mail, Safari) that is subscribed to the same feed (and vice versa). When we started developing the application one of our goals was to support Google Reader. The basic idea was to sync your whole PubSub database with Google Reader. This would automatically sync all PubSub-enabled applications with Google Reader. Even if one or more of these apps do not even know what Google Reader is.

Arch.png

To say it again: This would enable every app that uses PubSub to automatically sync with Google Reader. There are already a lot of apps that make use of PubSub: Mail, Safari, Xcode, Times, our app, .... It is very easy to adopt PubSub. The problem is that Google has not yet released an official API for Google Reader. There exists an unofficial documentation and there are many apps that are using Google Reader today. They all rely on a private API that is not documented very well. We have decided not to support Google Reader in any form because of that. I would love to see a public API. Then we would have a Google Reader Sync Agent in weeks. This sync agent would be so cool in my opinion.

 

Tuesday, August 17, 2010

Core Data Editor 3.0 released

Yesterday I finally released Core Data Editor 3.0. It took me about ten months to get from a beta version of Core Data Editor 3.0 to the final version. What is new:

  • Core Data Editor automatically observes the file system and tries to figure out when a persistent store file is changed by another application. If Core Data Editor detects a change it automatically reloads the file and refreshes its UI. Many thanks to Stuart Connolly, the developer of SCEvent, which makes observing the file system very easy.
  • Better support for iOS applications: In Core Data Editor 2 you could only specify the location of the iPhone Simulator directory, globally. This makes no sense anymore. Apple changed the locations where the Simulator places application data which broke Core Data Editor. Now you have to specify the location of the applications folder in each configuration. This allows you to use Core Data Editor for different versions of the SDK.
  • Updates are now delivered via Sparkle.
  • Help is now available and integrated in the app and will be constantly improved.

Core Data Editor Website

The following screen cast shows Core Data Editor and a third party app. As I add objects in the third party app Core Data Editor refreshes it's UI to reflect the changes. Neat - isn't it?

SyncThumbnail.png

(Click on the image above to watch the screen cast.)

Starting with version 3.0 Core Data Editor costs $20. Everyone who already donated $20 will receive a free license for Core Data Editor 3.0. Just drop me an e-mail if I forgot you. I hope you like the latest version of Core Data Editor.

Core Data Editor Website

Sunday, July 18, 2010

Drawing Patterns

Imagine you have a nice wooden texture that you want to use in some kind of navigation bar. You want the wooden texture to be repeatedly drawn along the x-axis. Your first approach might look something like this.

#import "PatternView.h"

@implementation PatternView

- (void)drawRect:(NSRect)dirtyRect {
   [superdrawRect:dirtyRect];

   NSImage *bg = [NSImageimageNamed:@"bg"];
   NSColor *backgroundColor = [NSColorcolorWithPatternImage:bg];
[backgroundColor set];
   NSRectFill([selfbounds]);
}

@end

This might not be what you have expected. Let me show you how the above code behaves in action.

Pattern1-Web.jpg

(Click on the image above to see the video)

As you can see when resizing the window the displayed texture is changing as well. This is because of the fact that patterns are always drawn relative to the containing window. Of course this works fine for patterns that should repeat along both axes. In this case however, we don't want that. Let me show you how to fix that.

#import "PatternView.h"

@implementation PatternView

- (void)drawRect:(NSRect)dirtyRect {
   [superdrawRect:dirtyRect];
   NSSize size = [selfbounds].size;

   // Create a new image and make it as big as the view
   NSImage *bigImage = [[[NSImagealloc] initWithSize:size] autorelease];

   // Prepare for drawing onto the new image
   [bigImage lockFocus];

   NSImage *bg = [NSImageimageNamed:@"bg"];
   NSColor *backgroundColor = [NSColorcolorWithPatternImage:bg];
   [backgroundColor set];
   NSRectFill([selfbounds]);

   [bigImage unlockFocus];

   // Now draw the image to the view
   [bigImage drawInRect:[selfbounds
               fromRect:NSZeroRect 
              operation:NSCompositeSourceOver 
               fraction:1.0f];
}

@end


The trick is to create a new empty image and size it correctly. Then you simply have to draw as shown in the first example. This results in exactly what we want.

Pattern2-Web.jpg
(Click on the above image to see the video)

Feel free to download the examples.

 

Sunday, May 16, 2010

Cocoa Tip: Detecting Arrow Down Key Events

We all know the Spotlight Search item in the top right corner of the screen. You can enter something and Spotlight instantly finds all matching files. The results view below the search field can be accessed by pressing the down arrow key. Usually pressing the down arrow key has the effect that the cursor jumps to the end of the text field's content. How can we override the default behavior? One solution would be to subclass NSTextView and provide an instance of this text view as the field editor of the cell. Luckily we have an alternative solution for this:

   [NSEvent addLocalMonitorForEventsMatchingMask:NSKeyDownMask handler:^(NSEvent *event) {
      NSString *characters = [event characters];
      unichar character = [characters characterAtIndex:0];
      if(character == NSDownArrowFunctionKey) {
         NSLog(@"key down");
      } 
      return event;
   }];

This solution looks pretty straight forward. We could also return an alternative event. I don't want to say that this is my final solution but I am happy to see that common things are easy with Cocoa.

Edit: You can remove a monitor by calling +removeMonitor: (NSEvent).