532OSC to and from the iPhone with VVOSC

Update (October 2011) Opening and compiling the (original 3.1) OSCDemo project in Xcode 4.1 asks to 'modernize' it. Go ahead, modernize it. For sending from the iOS device, also make sure to set the sendiungToIP address, at line 40 of OSCDemoViewController.m. For testing, also don't forget to set the IP address in OSC Senderin the Quartz Composer patch. Here's the updated, Xcode 4.1 version of OSCDemo. Update (April 2011) Some users reported a problem where the transmission/reception speeds on newer hardware (iPhone 4, iPad) became unstable and "flaky". It seems that Bluetooth is causing some interference with OSC. Solution: Make sure Bluetooth is off when you're using this code. Thanks to Hans Tutschku for finding this solution.

Sending data to and from the iPhone via OSC to applications on other machines should not be that difficult. Unfortunatly it's not as simple as it should be, but fortunalty Mr Ray (of VIDVOX fame) is so kind to share his code and his implementation of OSC for Objective-C. There are some ancient libraries around, but let's better keep them buried where they are.

First a bit of an excursion on how to deal with external code on the iPhone.

Frameworks, Static Libraries or Inclusion? Frameworks are the preferred method of distributing shared code on OSX. The idea behind being, that only one copy of the code can be shared amongst any number of applications. But at the iPhone true multi-tasking is not possible, so shared frameworks are not possible. Heck, they are even forbidden by Apple. But of course their own UIKit Frameworks are fine.

You could convert code for reuse to a Static Library, but with iPhone Dev you might deal with the simulator and the device, so you would need to either pre-compile the library for all plattforms or create a specific project, that compile the static library on demand. More on that at 519. Frameworks are also nice, in that you only have to import them to your project and then they just work. Static Libraries need some special care, with header search paths, compiler flags, and of course putting them in a special place in ~/Library. That's fine if you develop on your own, but if you work with other people and share the code via a source code repository (like SVN), it might be difficult (or annoying) to maintain the same machine state across all the development machines.

So I resorted to including the classes directly into my project. That way they get compiled every time and I can poke around the code directly. If you really want a central source of your external classes, just don't add them to your project by copy but just by reference...

Sending OSC From the iPhone Sending OSC data from the iPhone was always quite straightforward:

- (id) init {
    NSLog(@"OSC init");

    manager = [[OSCManager alloc] init];
    [manager setDelegate:self];

    // sending
    NSString *sendingToIP = @"192.168.20.117";
    int sendingToPort = 50000;
    outPort = [manager createNewOutputToAddress:sendingToIP atPort:sendingToPort];

    // receiving
    int receivingOnPort = 51234;
    //inPort = [manager createNewInput]; // default at port 1234
    inPort = [manager createNewInputForPort:receivingOnPort];

    return self;
}

Receiving OSC At the iPhone The receiving part seems to catch many people out. Basically it's nothing more than set the right delegate, as specified in VVOSC:

// called by delegate on message
- (void) receivedOSCMessage:(OSCMessage *)m {
    NSString *address = [m address];
    OSCValue *value = [m value];
    NSString *message;

    if ([address isEqualToString:@"/mouseX"]) {
        message = [NSString stringWithFormat:@"mouseX: %i", [value intValue]];
        NSString *txt = [NSString stringWithFormat:@"%i", [value intValue]];
        [receiveLabel performSelectorOnMainThread:@selector(setText:) withObject:txt waitUntilDone:NO];
    } else if ([address isEqualToString:@"/mouseY"]) {
        message = [NSString stringWithFormat:@"mouseY: %i", [value intValue]];
    } else if ([address isEqualToString:@"/floatArray"]) {
        message = [NSString stringWithFormat:@"floatArray: %f", [value floatValue]];
    }
}

Change Notes As VVOSC is targeted at both Cocoa and Cocoa Touch, there is a compiler directive that takes care of the switching. Or at least it should take care. I was unable to get the original code to run on the iPhone, because the compiler directive IPHONE was not recognized. I am sure I am missing something there... To solve that, I change IPHONE (and !IPHONE) with TARGET_OS_IPHONE (and !TARGET_OS_IPHONE), and that did the trick.. And as this is going to be used for the iPhone only, I allowed myself the luxury of removing any code, that was not meant for execution on the iPhone OS.

Here's the original OSC demo Xcode 3.1-compatible project, hope it helps. Here's the newer, Xcode 3.2-compatible version (working with Xcode 4.1 on OSX 10.7). Drop me a line, if you have questions, suggestions or improvements.

536Adding a custom delegate

MyClassWithDelegate.h

#import 

@protocol MyClassWithDelegaet 
@optional
- (void)myDelegateMethod:(NSString*)tsst;
@end

@interface MyClassWithDelegate : NSView {
    id  delegate;
}

@property (nonatomic, assign) id  delegate;

@end

 

MyClassWithDelegate.m

#import "MyClassWithDelegate.h"

@implementation MainView

@synthesize delegate;

- (void)anyEvent:(NSEvent *)e { // an event or something like that
    // send delegate
    [[self delegate] myDelegateMethod:@"sss"];
}

@end

Thanks to Jon Sterling for his digest of Apple's 'How Delegation Works'

533Getting Mouse Position in NSWindow

- (void)mouseDown:(NSEvent *)theEvent {
 NSPoint mousePoint = [theEvent locationInWindow];
 //NSPoint localPoint = [self convertPoint:mousePoint fromView:nil];
 CALayer *hitLayer = [[self layer]  hitTest:mousePoint];
 NSLog(@"MainView, hitLayer: %@", hitLayer.name);
 NSLog(@"mousePoint %f %f", mousePoint.x, mousePoint.y);
}

519A bit about Frameworks and Static Libraries on the iPhone

Frameworks are a way to share code and other resources between application. As sharing code between applications is not really possible on the iPhone (as is dynamic loading of libraries) it does not really make much sense to use Frameworks on the iPhone - except maybe for the nice handling of reusable code.

Where with Frameworks the specific files are accessable after the Framework is added to a project, working with Static Libraries is a bit more of an hussle. You not only need to add the library, but also need to make sure to set the right Header Search Paths, which can become troublesome when working with SVN'ed projects.

And because the architecture differs on the iPhone (ARM) and the Simulator (i386), having precompiled libraries is not the best solution. But adding a depended library project to your projects kind of negates the advantages of having reusable code by adding unnecessary complications.

Recommendation? Just add the desired files to your project. And if you really mind, don't copy, but only include by reference.

503UILabel and performSelectorOnMainThread

I've been struggling with that for a while... Why wouldn't my UILabel display it's updated text? The weird thing was, that I could update the text, as long as I called it from the same class.

But as I passed a reference to the UILabel to another class, and tried to set the text from there, it wouldn't show. Stranger still, I could see in the logs, that the value itself was updated, it only did not show on the screen.

I also tried to send a notification back to the class where I made the label, but again, no luck. Very strange, a directly called method would updated the label without problems, one called by the notification would not show the update.

What was I missing?

My first instinct was to check out [myLabel setNeedsDisplay];

I kind of worked. But only if I called from - for example a Button. It then updated the values of the UILabel. That's was a step forward, but not really satisfying; after all I'd like have updates on the UILabel whenever they arrived. And again, calling if from the notification also did not do the trick.

Then I found out, that it order for UILabels to visually update, the update command has to be called on the main loop! Yeah! And how to perfom and action on the main loop?

Yes, with performSelectorOnMainThread:

So, the solution it an anti-climax and here it is:


[myLabel performSelectorOnMainThread:@selector(setText:)withObject:myText waitUntilDone:NO];
//

492Target Conditionals

TargetConditionals.h

#include ;

// Gives you TARGET_IPHONE_SIMULATOR and TARGET_OS_IPHONE target conditionals.
// Set hello to "Hello, "!
#if TARGET_IPHONE_SIMULATOR
   NSString *hello = @"Hello, iPhone Simulator!";
#else
   NSString *hello = @"Hello, iPhone device!";
#endif

//Determining whether you’re compiling for the iPhone OS
#if TARGET_OS_IPHONE
   #import 
#else
   #import 
#endif

Conditionalizing Compilation and Linking from the Apple Dev Library.

I came across a simple and short IPHONE target conditional at some framework, but that did not seemed to do the trick. I am probably missing something there.

-

Update 1. tconf might be a step into the right directions.

Just out of curiosity, here a incomplete list of available target conditionals:

TARGET_IPHONE_SIMULATOR
TARGET_CARBON
TARGET_OS_IPHONE
TARGET_CPU_PPC 
TARGET_CPU_PPC64
TARGET_CPU_68K
TARGET_API_MAC_OSX
PRAGMA_ALIGN_SUPPORTED
TARGET_OS_UNIX
TARGET_OS_EMBEDDED
TARGET_OS_MAC
TARGET_OS_WIN32
TARGET_OS_UNIX
TARGET_OS_EMBEDDED
TARGET_RT_MAC_CFM
TARGET_RT_MAC_MACHO
...

Update 2. And that's the motherload. Nice of Apple to open-source that.

490‘Initial interface orientation’ setting in Info.plisy

The Informatin Property List of iPhone Applications has the optional setting of Initial interface orientation. Is a NSString type, I was wondering, which values were supported, bzw required. Luckily, auto-complete is your friend.

For completeness' sake, here are the accepted values:

Portrait (top home button) Portrait (bottom home button) Landscape (left home button) Landscape (right home button)

484Printing Selectors in NSLog

Using NSStringFromSelector to convert the selectos into a NSString, and the print the object:

NSLog(@"%@", NSStringFromSelector(selector) );

Or print it directly with good, old-fashioned C:

NSLog(@"%s", selector,);

457Singleton Classes and Shared Resources in Objective-C

Resource.h

#import 

@interface Resource : NSObject {
    float myValue;
}

@property float scale;

+ (id)shared;

@end

 

Resource.m

#import "Resource.h"

@implementation Resource

@synthesize scale;

- (id)init {
    scale = 1.0f    // my default value
}

+ (id)shared {
    static Resource *sharedResource = nil;
    if (!sharedResource) {
        sharedResource = [[self alloc] init];
    }
    return sharedResource;
}
@end

An now it can be used like the following:

Resource *r = [Resource shared];
NSLog(@"Resource Test: %f", [r myValue]);
// Resource Test: 1.000000

[r setMyValue:2.0];
NSLog(@"Resource Test: %f", [r myValue]);
//# Resource Test: 2.000000

Resource *s = [Resource shared];
[s setMyValue:2.111];
NSLog(@"Resource Test: %f", [s myValue]);
// Resource Test: 2.111000

NSLog(@"Resource Test: %f", [r myValue]);
//Resource Test: 2.111000

Note that the values stays constant, even if another instantionation occurs. I guess that's what Singleton classes are all about.

Adapted from Scott Stevenson's fantastic introduction at Cocoa Dev Central.

And more tutorials from Scott Stevenson... Cocoa Dev Central: Learn C for Cocoa Cocoa Dev Central: Learn Objective C

452Padding with Zeros (or other characters)

int x = 11;

[NSString stringWithFormat:@"%03i", x];
// @"011"

[NSString stringWithFormat:@"%+5i", x];
// @"+++11"

[NSString stringWithFormat:@"%+05i", x];
// @"+0011"

And not really like that. 381. I'll still have to learn a lot of C.