Nov 14

I’m writing this quick little tutorial because I could not find a single source for what I wanted to do, but found myself reading multiple docs and putting it together. So, here we go:

Having Return Execute an Action for an NSTextField

Part 1: Quick Setup

  1. Create a new Cocoa Application named TextFieldTutorial. (I am not going to go into much detail about this, as there are better beginning tutorials out there if you need it).
  2. Open your MainMenu.xib and create your UI. Create two NSTextFields one for input and the other for output. Set these up visually however you’d like.
  3. Add a new File that extends NSObject and name it TextFieldTutorialController (be sure to generate the .h file as well).

Part Two: Writing the Code

There are a couple set-up things we need to add to the code. We’ll need to add the references to the two NSTextFields in our controller’s header file. Make sure these are tagged by IBOutlet to allow Interface Builder to know that it can hook into it.

Additionally, create the method definition for hitting enter. You code should look something like:

#import <Cocoa/Cocoa.h>

@interface TextFieldTutorialController : NSObject {

IBOutlet NSTextField* inputField;

IBOutlet NSTextField* outputField;

}

-(IBAction)userHitEnter:(id)sender;

@end


Next, all we have to do is fill in the body for userHitEnter. It will be a rather simplistic method:

@implementation TextFieldTutorialController

-(IBAction)userHitEnter:(id)sender {

[outputField setStringValue:[inputField stringValue]];

}

@end

Yep, that’s it. This is easy.

Part Three: Hooking Everything Together

Now, that our code is ready, we need to hook the UI to the controller. Go back to Interface Builder and add a new Object to your NIB file.

Interface BuilderScreenSnapz001

Change the type of NSObject to TextViewTutorialController:

Interface BuilderScreenSnapz002

Now, hook up the outlets of TextViewTutorialController to the two NSTextViews. Do this for both inputText and outputText.

Interface BuilderScreenSnapz003

Next, we need to set up our inputText object. First, we will set it to only call an action on Enter. Otherwise, we would be making a message call on every press of the keyboard (feel free to leave it like this if you want to experiment).

Interface BuilderScreenSnapz004

Then the last thing we need to do it set the Sent Actions selector of the Input NSTextField to our controller and select the userHitEnter method.

Interface BuilderScreenSnapz005

Interface BuilderScreenSnapz006

That’s it! Build and Run, and you should be able to type anything in the inputText area and hit enter, this will update the outputText.

TextFieldTutorialScreenSnapz001

Tagged with:
Nov 08

There are a number of things that Cocoa provides by default that is really great.

If I wanted to call a method after X seconds in Java, I would have to create some sort of Timer class, create an Interface that defines a callback method, execute the timer with some class that implements the interface, have the Timer execute a timer loop handling all the necessary threading code (Thread Pool, etc).

With Cocoa you call performSelector:withObject:afterDelay:

performSelector:withObject:afterDelay:

Invokes a method of the receiver on the current thread using the default mode after a delay.

- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay

Parameters
aSelector

A selector that identifies the method to invoke. The method should not have a significant return value and should take a single argument of type id, or no arguments.

See “Selectors” for a description of the SEL type.

anArgument

The argument to pass to the method when it is invoked. Pass nil if the method does not take an argument.

delay

The minimum time before which the message is sent. Specifying a delay of 0 does not necessarily cause the selector to be performed immediately. The selector is still queued on the thread’s run loop and performed as soon as possible.

Discussion

This method sets up a timer to perform the aSelector message on the current thread’s run loop. The timer is configured to run in the default mode (NSDefaultRunLoopMode). When the timer fires, the thread attempts to dequeue the message from the run loop and perform the selector. It succeeds if the run loop is running and in the default mode; otherwise, the timer waits until the run loop is in the default mode.

If you want the message to be dequeued when the run loop is in a mode other than the default mode, use theperformSelector:withObject:afterDelay:inModes: method instead. To ensure that the selector is performed on the main thread, use the performSelectorOnMainThread:withObject:waitUntilDone: orperformSelectorOnMainThread:withObject:waitUntilDone:modes: method instead. To cancel a queued message, use thecancelPreviousPerformRequestsWithTarget: or cancelPreviousPerformRequestsWithTarget:selector:object: method.

This method retains the receiver and the anArgument parameter until after the selector is performed.

Availability
  • Available in Mac OS X v10.0 and later.
See Also
Related Sample Code
Declared In

NSRunLoop.h

So, significant functionality is built into the main system allowing you to call an arbitrary Selector without any extra work.

Tagged with:
Nov 01

The first task I gave myself when writing the Celery Application is to obtain nutritional information for various foods. I’ll need to provide a means to request a list of food that matches a search query and a way of getting more information about a particular food from that list. As I mentioned before, I found the FatSecret REST API, and decided to use this for these two requests. FatSecret supports “foods.search” and “food.get” methods that meet my needs. FatSecret also uses oauth for authentication.

My list of tasks were as follows:

  1. Obtain the necessary keys to communicate with FatSecret.
  2. Find a Cocoa Library to use oauth.
  3. Establish a connection and call methods as needed.

1. Obtain the necessary keys to communicate with FatSecret. This was easy enough, simply went to this site and registered the application I was making. This provided me with a Public Consumer Key and the applications Private Key. These keys were emailed to me, and they were ready to be used.

2. Find a Cocoa Library to use oauth. As I mentioned in a previous post, I found MPOauthConnection for establishing an oauth connection and calling methods on a REST Library. I downloaded the source using Subversion and opened the library. After running the Build, Xcode proceeded to lock up completely. All I got was the Beachball of Death. I stared at it, tried a couple more times, but could not successfully build the project. After awhile, I noticed that it was failing to proceed past the Unit Tests. I figured, I’m not modifying the Library, and therefore, don’t really need to run the Unit Tests. So, I opened up the Unit Test target and deleted it. Kicked off the Build and it succeeded.

I was going to start up the Celery project, but decided to go ahead and modify the existing test application to communicate with FatSecret.

3. Establish a connection and call methods as needed. The first thing that I had to do was match up what MPOAuthConnection expects to what FatSecret API expects, including slightly different nomenclature. I started by plugging in the values for the Base Host URL, Shared Secret and Consumer Key and the method to call. The method to call stumped me a bit, as the FatSecret sets the actual method to a parameter (method=VALUE). Where the method for the API is server.api. That really took me awhile to figure out. Secondly, the provided example had no usage of method parameters (making it a very flawed example, in my opinion). I struggled then to figure out the API to pass parameters, finding a Unit Test in code, I was able to figure this out and successfully make calls to the API, searching for a food, and getting information for that food.

The next step will be to build my own Celery project and duplicate this functionality in what will become my own Application.


Tagged with:
preload preload preload