Archive for the ‘Cocoa Coding’ Category

Favorite C and Obj-C Features of the Week

Wednesday, December 15th, 2010

xcode.jpg

I'm not sure if I'll do a lot of this, but today I was working and realized that there's something I've been using in C/C++ that I really love. I also was thinking about something in C/C++ that I don't love, and how Objective-C does is so much better. So I decided to have a Feature of the Week - for at least this week.

C/C++: Assignments Everywhere

I didn't used to do it, but of late, it's made my code so much more readable to me. Maybe it's me, maybe I've gotten to be a better coder, but I used to write a lot of code that looked like this:

  variant   *a = getVariant(3);
  if (a == NULL) {
    cLog.error("unable to get variant #3");
  }
  a = getVariant(2);
  if (a == NULL) {
    cLog.error("unable to get variant #2");
  }

and it's even worse in a re-used iterator:

  std::vector<std::string&gt::iterator   it = mClients.find("Steve");
  if (it != mClient.end()) {
    // do something with the fact we have 'Steve'
  }
  it = mClients.find("Jeff");
  if (it != mClient.end()) {
    // do something with the fact we have 'Jeff'
  }

But it doesn't have to be this way. With the C/C++/ObjC ability to have assignments anywhere, you can compress this all very nicely:

  variant   *a = NULL;
  if ((a = getVariant(3)) == NULL) {
    cLog.error("unable to get variant #3");
  }
  if ((a = getVariant(2)) == NULL) {
    cLog.error("unable to get variant #2");
  }

and the re-used iterator becomes:

  std::vector<std::string>::iterator   it;
  if ((it = mClients.find("Steve")) != mClient.end()) {
    // do something with the fact we have 'Steve'
  }
  if ((it = mClients.find("Jeff")) != mClient.end()) {
    // do something with the fact we have 'Jeff'
  }

Sure, this isn't rocket science, but it's allowed my code a new level of readablility - certainly in the looping where the definition of the variable is outside the loop and the assignment is within it. There's nothing like readable code. It's a real benefit.

ObjC: The Clever Mr. nil

But one thing I love about ObjC is it's use of the nil. It's far more than the C/C++ NULL because you can message nil with anything, and that's where it's so valuable for code readability. Take the following code, for instance. It's going to get a few things in a data structure, and to do it right, and by "right" I mean safely so as not to get null pointer seg faults, we need to do something like this:

  TPClient   *boss = getBoss();
  if (boss != NULL) {
    Channel  *chan = boss->getChannel("red");
    if (chan != NULL) {
      cLog.info("red channel has %d bits", chan->getBits());
    }
  }

Sure... you can be careless, and write this all optimistically as:

  cLog.info("red channel has %d bits", getBoss()->getChannel("red")->getBits());

but if there's any problem in those calls, it's a SegFault to be sure. But ObjC and nil can handle this nicely:

  [NSLog @"red channel has %d bits", [[[self getBoss] getChannel: @"red"] getBits]];

and the latter is so much more readable. It's the fact that you have to code defensively that kills the readability of the code. Not so in ObjC. It handles the possibility of any one of these steps returning a nil, and carries on as if that's expected behavior.

There you have it. My favorite little language do-dads for today.

The Problems of Premature Optimization

Monday, October 18th, 2010

bug.gif

This morning I figured out my problem from late last week - the serialization problem. The logging really was the key, and the trigger was that I was seeing the deserialization of an array of messages starting over. It's like something reset the decoder. Very odd.

Then I looked at the size.

65495.

I about threw myself out the window.

I had assumed that all the messages I was going to receive were single message containers. For this, it makes sense to think of the size as a uint16_t. But what happens when you get a query for 50,000 messages? The response is an array of messages and the size is a lot bigger than 64k. The "starting over" was the key. It was wrapping around the counter and trying to match up the wrapped data to the messages.

Horrible failure.

I went into the code and changed all these uint16_t to uint32_t and I'll be fine. The tests were perfect, and I could get on with the rest of the testing. But this points out the problems with Premature Optimization. I was thinking that there was no need to have a counter/cursor bigger than 64k when all messages were less than 100 bytes. And I was right.

But I didn't think about the problem of dealing with messages that I create and can be much larger than a single UDP datagram. Being in this business for decades doesn't make you immune to this problem. It's the thought process that you have to be careful about. I'm as guilty here as anyone.

OK, maybe i found the problem a little quicker, but it still took the better part of a day, and it was annoying to boot.

Lesson learned: Optimize when you have a performance problem. Not before.

Making a Quad-FAT Universal Binary for CKit

Friday, June 25th, 2010

CKit.jpg

I saw something like this on Apple's Developer website while looking for some help in getting the PPC build of CKit working the other day. It was a way to combine two binaries and make a universal (or FAT) binary as the output. So you'd compile a PPC library and an Intel one, and then merge the two together. Pretty slick. It's a simple command:

  $ lipo -create one.dylib two.dylib -output final.dylib

This creates a single final.dylib file from the two inputs. Very nice.

So I decided to try my hand at creating a single quad-FAT CKit library: 32/64-bit, PPC/Intel. All I needed to do was to change the lines in the Makefile from:

  ifeq ($(shell uname),Darwin)
  all: $(LIB_FILE) $(LIB64_FILE)
  else

to:

  ifeq ($(shell uname),Darwin)
  all: $(LIB_FILE) $(LIB64_FILE)
	lipo -create $(LIB_FILE) $(LIB64_FILE) -output $(LIB_FILE)
  else

Where the original 'all' target just required the two library files to be generated, and now it does that but then it uses the lipo command to stitch the two libraries together into one. This has the effect of leaving the 64-bit PPC/Intel library alone, but glues it onto the 32-bit version. What an amazingly simple thing to do!

I do love these tools!

To Move On, or Not…

Tuesday, June 22nd, 2010

xcode.jpg

I've been updating some C++ code this afternoon to use Xcode 3.2.2 and the new LLVM compiler that comes with it and I ran into some interesting new warnings and one real issue. The biggest source of the new warnings were the use of char * as a constant. The warning was saying that it wasn't going to cast the string into a char *. For example, the following generates a warning in Xcode 3.2.2:

  char *name = "Bob";

but the fix is pretty easy:

  const char *name = "Bob";

There was another problem with calling methods with optional parameters and needing the interface to declare the argument const. It was easy enough to fix as well.

The biggie was that when I installed Xcode 3.2.2 I didn't include the complete 10.5 compatibility package - including the PowerPC code. And that was a real issue. I spent a ton of time trying to understand what the error message was saying. It was saying __Unwind_Resume was undefined in all the modules, and that had nothing to do with the PPC libraries not being installed.

Yet, it did.

I read in a few places that the link problem was from a bad compiler, or something, and so I got to thinking - What if Xcode 3.2.2 wasn't PPC-aware? And so I checked. And its libraries are all a single CPU type. It's gotta be the case that in one of the installs of Xcode, I didn't ask it to install everything for 10.5, and that dropped the PPC libraries. The compiler generated the code OK, but the link failed.

OK... now I just need to download Xcode 3.2.2 again and re-install it to get the 10.5 libraries for PPC back. I hope it's easier than it sounds.

The alternative is to drop PPC support for the code and just "Move on". I'm not really ready to do that if I don't have to. But there's nothing holding me to PPC and 10.5, but at the same time, there's nothing that says I need Intel-only or 10.6. SO for now, I think I'll try to get it back.

[6/23] UPDATE: It's not nearly as easy to build for PPC and Intel in Snow Leopard. I can still do it, but it's getting to be more and more of a pain. I can see that the legacy systems are just dropping off. While I'll bet I can still build apps with Xcode for PPC, the command-line args are getting tougher to master.

For now, when I used to make my shared library, I had the following arguments in the Makefile:

LDD_32 = -Wl,-syslibroot,/Developer/SDKs/MacOSX10.5.sdk -arch ppc -arch i386 \
         -install_name libCKit.$(SO_EXT) -current_version 1.0.0 \
         -compatibility_version 1.0.0
LDD_64 = -Wl,-syslibroot,/Developer/SDKs/MacOSX10.5.sdk -arch ppc -arch x86_64 \
         -install_name libCKit.$(SO_EXT) -current_version 1.0.0 \
         -compatibility_version 1.0.0

but to get it working with Xcode 3.2.3 and Snow Leopard - even with all the old development tools, I had to change this to:

LDD_32 = -lgcc_s.1 -Wl,-syslibroot,/Developer/SDKs/MacOSX10.5.sdk -arch ppc \
         -arch i386
LDD_64 = -lgcc_s.1 -Wl,-syslibroot,/Developer/SDKs/MacOSX10.5.sdk -arch ppc64 \
         -arch x86_64

Interestingly, I didn't need the current_version or compatibility_version, but it's nice to have them if you want that information in the code. In my code, I leave in the two values just to be complete:

LDD_32 = -lgcc_s.1 -Wl,-syslibroot,/Developer/SDKs/MacOSX10.5.sdk -arch ppc \
         -arch i386 -install_name libCKit.$(SO_EXT) -current_version 1.0.0 \
         -compatibility_version 1.0.0
LDD_64 = -lgcc_s.1 -Wl,-syslibroot,/Developer/SDKs/MacOSX10.5.sdk -arch ppc \
         -arch x86_64 -install_name libCKit.$(SO_EXT) -current_version 1.0.0 \
         -compatibility_version 1.0.0

I also changed the defines for the 64-bit build from:

CXX_64 = -isysroot /Developer/SDKs/MacOSX10.5.sdk -arch ppc -arch x86_64

to:

CXX_64 = -isysroot /Developer/SDKs/MacOSX10.5.sdk -arch ppc64 -arch x86_64

And then for the tests that only need to work on the one architecture:

CXX_DEFS = -D_REENTRANT -O2 -isysroot /Developer/SDKs/MacOSX10.5.sdk \
           -arch ppc -arch i386
OS_LIBS = -Wl,-syslibroot,/Developer/SDKs/MacOSX10.5.sdk

to:

CXX_DEFS = -D_REENTRANT -O2 -arch ppc -arch i386
OS_LIBS = 

as I was getting problems with linking libcrt.1.10.6 and the only way to get it was to let the system default to it's libraries. It's not ideal, but it's working.

The next step is just to remove PPC support and be Intel-only.

[6/24] UPDATE: To get better universal binaries out of Xcode, I'm going to have to switch to Xcode as the build system. Why? The LLVM compiler. Using GCC, I'm not going to be able to make 10.4u binaries as that was GCC 3.3, and Xcode 3.2.3 is on GCC 4.2. Pretty soon, the GCC will move away from that, and I'll be left with nothing to easily compile with. Except the LLVM compiler. Unfortunately, the documentation on this is still a little sketchy, and the best way to really use it is Xcode.

Probably just switch off PPC generation as it's unlikely to come back anytime soon.

Icon Color Mapping in Snow Leopard – Interesting Issue

Tuesday, June 22nd, 2010

Seems with Snow Leopard (Mac OS X 10.6) there's an issue with the color mapping of icons. Specifically, icons made on 10.6 with Photoshop, saved to a file and then loaded into Icon Composer. The Panic Guys have figured this out.

Seems when exporting (using 'Save for Web') in Photoshop, you need to set the 'Destination Space' in the color profile to "Generic RGB Profile", and then export the artwork as a Generic RGB .png file, which can then be loaded up in Icon Composer and everything will be OK.

I say 'everything', but in fact, the icon will now look dark on 10.5 because of the exact same reason. Can't please everyone.

Interesting Look for the NSTextField

Thursday, June 17th, 2010

xcode.jpg

I saw this post on a new Cocoa development weblog, and it looks very interesting: a new rounded-corner NSTextField: SSTextField. The problem with much of Cocoa programming is the GUI components that Apple uses in it's high-end apps (in this case, Safari) are custom to Apple and don't make their way into Interface Builder for quite some time. Sure, eventually, they'll get there, but if you want to have that cutting edge design, you're on your own.

Anyway... someone decided to share what they had done with their app, and the result is a new look to NSTextFields:

SSTextField

Interesting view, though... I might use it in my CryptoQuip solver for an interesting look. Then again, I really need to fix up the initial legend drop-downs... so much to do...

Good News for Threaded ObjC Code

Tuesday, June 8th, 2010

xcode.jpg

Today I was telling a friend on chat that I like the idea of mutable objects. It's how I think about programming. I realize that immutability is all the rage with Clojure and Erlang, but it's not how my mind thinks - at least not yet. So I was saying that what I wanted was someone to implement the atomic compare/replace needed for lockless data structures in ObjC. Well... I had a few minutes while digesting the ordering of set elements in Clojure, and decided to google lockless data structures for ObjC - lo and behold, there's a podcast with Mike Ash on exactly this topic.

I haven't listened to it (yet), it's still downloading, but I'm going to listen and see if in the latest developer tools there is support for the lockless data structures. If so, what a lucky break! It would certainly make things a lot easier for me when I get to that level of coding.

[6/9] UPDATE: I found TransactionKit on the web, and it's got a partially done implementation of NSDictionary and NSMutableDictionary. His warnings are nice, but it leaves me with the impression that I shouldn't really trust this. It looks nice, but I need to do a lot more reading on it, and looking at the code before I'm convinced. The problem is that I also need an NSArray equivalent. We'll have to see when I get around to it.

As a note, the description of TransactionKit by it's author is here, and it's a pretty significant piece of code. Not at all what I had anticipated in my initial thoughts. In fact, it sounds pretty amazing, but he warns us all:

There's also almost certainly bugs here and there, so the idea of unwinding stack frames by hand and being able to almost reflexively spot pointers to stack variables, and which threads stack it refers to should be second nature to you. When things go wrong, they will go wrong in a stunningly complex way.

Also, Apple has done a reasonably good job of implementing a LIFO queue with OSAtomicEnqueue() and OSAtomicDequeue(), which are in the man pages. The man page even gives a nice example of putting it to use - the only problem is that you need to drop into C structs to hold the data so it's not likely to be used in a simple Cocoa implementation.

Additionally, Mike Ash (in the podcast) talks about how the atomic increment is about 10x slower than the simple ++i implementation, but it's far, far faster than the lock, increment and unlock. Makes sense, but again, it goes to Apple's comments on threading - make code that doesn't need to use lockless data structures and you're even better off. Good to know.

Latest Changes to CryptoQuip in Cocoa

Monday, June 7th, 2010

GeneralDev.jpg

I added a little twist to my Cocoa CryptoQuip solver - I made sure that the PuzzlePieces were unique, and then I sorted them in the Quip by the number of possible plaintext words that each had. Why? Well, the duplicates are just unnecessary work, and in my test quip, I had one. Just no need to do that. The sorting by the number of possible plaintext words is meant to reduce the number of iterations by "pinning" the most complete Legend as early as possible. If I have to cycle through 30 words first, and then 1 word, it's faster to pin the one word, and then search the 30. Not a lot faster, but as the searching grows, it makes a difference.

The way to guarantee uniqueness amongst the PuzzlePieces is to change the code for initialization of the Quip to look for duplicates first, and then only add the unique ones:

- (id) initWithCypherText:(NSString*)text where:(unichar)cypher
  equals:(unichar)plain usingDict:(NSArray*)dict
{
  if (self = [self init]) {
    // save the important arguments as ivars
    [self setCypherText:text];
    [self setStartingLegend:[Legend createLegendWhere:cypher equals:plain]];
    // now let's parse the cyphertext into puzzle pieces
    PuzzlePiece*   pp = nil;
    for (NSString* cw in [text componentsSeparatedByString:@" "]) {
      if ([cw length] > 0) {
        if ((pp = [PuzzlePiece createPuzzlePiece:cw]) != nil) {
          [self addToPuzzlePieces:pp];
        }
      }
    }
    // if we have a dictionary of words, use them
    if (dict != nil) {
      for (NSString* pw in dict) {
        for (PuzzlePiece* pp in [self getPuzzlePieces]) {
          [pp checkPlaintextForPossibleMatch:pw];
        }
      }
    }
  }
  return self;	
}

to:

- (id) initWithCypherText:(NSString*)text where:(unichar)cypher
  equals:(unichar)plain usingDict:(NSArray*)dict
{
  if (self = [self init]) {
    // save the important arguments as ivars
    [self setCypherText:text];
    [self setStartingLegend:[Legend createLegendWhere:cypher equals:plain]];
    // now let's parse the cyphertext into puzzle pieces
    PuzzlePiece*   pp = nil;
    for (NSString* cw in [text componentsSeparatedByString:@" "]) {
      if ([cw length] > 0) {
        if ((pp = [PuzzlePiece createPuzzlePiece:cw]) != nil) {
          if (![[self getPuzzlePieces] containsObject:pp]) {
            [self addToPuzzlePieces:pp];
          }
        }
      }
    }
    // if we have a dictionary of words, use them
    if (dict != nil) {
      for (NSString* pw in dict) {
        for (PuzzlePiece* pp in [self getPuzzlePieces]) {
          [pp checkPlaintextForPossibleMatch:pw];
        }
      }
    }
  }
  return self;	
}

which works wonderfully because we have already built the -isEqual: method for the PuzzlePiece:

/*!
 This method returns YES if the argument represents the same puzzle piece
 as this instance. That is not to say that they are identical, but that
 they have the same cyphertext, and same list of possible plain text words.
 */
- (BOOL) isEqual:(id)obj
{
  BOOL   equal = NO;
  if ([obj isKindOfClass:[self class]] &&
    [[self getCypherWord] isEqual:[obj getCypherWord]] &&
    [[self getPossibles] isEqualToArray:[obj getPossibles]]) {
    equal = YES;
  }
  return equal;
}

Now to do the sorting we needed to add a little more code. The trick is to use the NSMutableArray's ability to sort it's content with the -sortUsingSelector: and then the key is to have the right selectors for the objects. I decided to make it pretty simple, and I implemented two versions of the -compare: method:

/*!
 This comparison method will compare the lengths of the cypherwords so that
 you can use this method to sort the puzzle pieces on the lengths of the words
 for some attack.
 */
- (NSComparisonResult) compareLength:(PuzzlePiece*)anOther
{
  NSUInteger	me = [[self getCypherWord] length];
  NSUInteger	him = [[anOther getCypherWord] length];
  if (me < him) {
    return NSOrderedAscending;
  } else if (me > him) {
    return NSOrderedDescending;
  } else {
    return NSOrderedSame;
  }
}
 
 
/*!
 This comparison method will compare the number of possible plaintext matches
 for the argument and this instance to see who has more. This is useful in
 sorting the puzzle pieces on the number of possible matches in the attack.
 */
- (NSComparisonResult) comparePossibles:(PuzzlePiece*)anOther
{
  NSUInteger	me = [self countOfPossibles];
  NSUInteger	him = [anOther countOfPossibles];
  if (me < him) {
    return NSOrderedAscending;
  } else if (me > him) {
    return NSOrderedDescending;
  } else {
    return NSOrderedSame;
  }
}

With these, I'm able to easily sort the puzzle pieces by the number of their possible plaintext matches with:

  // sort the puzzle pieces by the number of possible words they match
  [[self getPuzzlePieces] sortUsingSelector:@selector(comparePossibles:)];

With these changes, the time to solve my test case went from 0.21 sec to 0.18 sec. Not quite what I'd hoped, but I'm not done, either. I believe I'm on the right track, but I need to further limit the search space, and when that is done, I hope to be well under the 0.10 sec mark. Now that would be cool!

First Working Version of CryptoQuip in Cocoa

Wednesday, June 2nd, 2010

xcode.jpg

I just got my Cocoa version of my CryptoQuip code working, and I have to say, I'm impressed - but then I knew I'd be. I can solve the standard puzzle in about 0.21 sec on my MacBook Pro - which is pretty darn speedy. I'm not completely happy with the results, as I think there are a ton of improvements I can make in the attack, and now that I have a really nice domain model, I can make these changes very easily. It's sweet.

I also decided to use git as the source control - and it was a little bit of a debate within myself on this issue. I'm normally a CVS guy, and I've gotten very good at making CVS do all that I've ever needed. But I don't have tethering on my iPhone, and at the prices AT&T are talking about, I'm not sure I will for a while. Still, I wanted to have it in source control, so git was it. Plus, it's clean, fast, local, and with Time Machine, it's as safe locally as it can possibly be.

Still, I'll probably put it up on my home git server, just so I can have a remote pull if I need it.

gitLogo.gif

To get it all going, I needed to do just a few things for decent Xcode integration. I say decent because there's really no Xcode integration at this time for git - it's all on the command line. However, because I always have a terminal session open to the project directory, the really important issue is how the files are treated in git. Thankfully, git is wonderful at this.

I first went into the project directory Xcode made, and created the git repository:

  $ cd ~/Developer/CryptoQuip
  $ git init

then I needed to set up my project-based .gitignore and .gitattributes based on this posting that is a great place to start if you don't already have some decent defaults for git. I created two files in the root project directory. First, .gitignore:

  build/*
  *.pbxuser
  *.mode1v3
  profile

and then .gitattributes:

  *.pbxproj -crlf -diff -merge

When I started looking at the new layout of the project directory that Xcode uses, it's far cleaner than the older project layout of NeXTSTEP-era projects (yes, I still have a few of them). The lines in the .gitignore make a lot of sense, and it's very nice how they have moved the old bundles into files that can be put into generic source control very easily.

Then I needed to put it on my home gitosis server so I could have a backup and remote pull. First, I needed to check out the gitosis-admin project:

  $ git clone git@git.themanfromspud.com:gitosis-admin.git

then in the newly created gitosis-admin directory, edit the gitosis.conf file to add the new repository to the group I've created for everything:

  [group everything]
  members = drbob@sherman
  writeable = JiGV CryptoQuip

then I need to check it back in and push it back to the server:

  $ git commit -a -m "Added CryptoQuip project to the main group"
  $ git push

and it was all ready for the project.

To add the project, I simply went into the project directory and add it's new origin and then push it to the server:

  $ cd ~/Developer/CryptoQuip
  $ git remote add origin git@git.themanfromspud.com:CryptoQuip.git
  $ git push origin master:refs/heads/master

and it's all up on the server and ready to go!

At this point, when I want to sync my local git repository to the main server-side one, I'll just have to do a push:

  $ git push

and git will remember where I pushed it last and sync it up with the server repository. Very nice.

One final style point: on the server, a new repository is created but from the web server, the description is lacking any color. What I did was to login to the server, go to the newly created repository directory, and then edit the file called description. I changed it to a decent little one-liner and that was it. Done.

The Incredible Expressiveness of Objective-C

Friday, May 28th, 2010

I've been messing with getting my latest ObjC code going again today and I have to say that once again, ObjC simply brings a smile to my face. It's so incredibly expressive that I just can't get over it. Sure, I can do a lot of the same things in C, C++ and Java, but there's a lot I can't do simply because they don't have the ObjC runtime. I appreciate that I can send nil any message I want, and it's not going to error. That means I don't have to check every single step in the processing or worry that some bad data will blow me up.

In C, C++ and Java, I have to do this checking. It's not horrible but it does make the implementation (not the language itself) much uglier than the equivalent implementation in ObjC.

Sure, I have looked at things like Python and Clojure, and there are languages that allow the more flexible method invocation, but it's not the same as really understanding that there's a nil object, and it's OK to deal with it as a valid instance of anything. It's really pretty sweet.

I'm porting code from C to ObjC for this project, and while the C code was about as clean and nice as I could have ever written, the ObjC code is just fifty times cleaner and easier to understand. Sure, a lot of this is the objects and message passing, and another big chunk is the Cocoa objects, but even in Java, it would not have been as clean.

I love that I can drop into C code when I need to, and that I've got retain/release memory management as opposed to the reference counting and garbage collecting. I just really hate that about Java. It's always something that comes back to bite me in terms of efficiency of storage.

I had an interview once with a company that I've since realized I'm glad I didn't get the position, but at the time, I was really ready to leave where I was. The guy I was talking to realized that I had been somewhat of a mistake in that my interests were not at all in line with the position - typical recruiter move, but we had a nice talk anyway. In the end, when talking about the language, he said "Any reasonably expressive language is pretty much the same." and at the time I was thinking of Java vs. C#, and tended to agree with him.

Horrible statement by him, and horrible memory fault by me.

There's nothing like ObjC. Nothing.