Experimental scala-native bridge to Objective-C / Cocoa.

Introduction

SNCocoa is a bridge for writing Cocoa (and possibly Cocoa Touch) applications with Scala Native. To this end it provides:

  • a set of macros that transform the message-passing style of Objective-C in idiomatic Scala (method calls on objects) and support defining Objective-C classes in Scala,
  • bindings to Cocoa (Foundation, AppKit) and other core frameworks,
  • wrappers and decorators for fundamental Cocoa classes (strings, collections, …) for seamless integration between Scala and Cocoa.

Here’s a comparison of Objective-C syntax with the corresponding SNCocoa idiom:

Objective-C

Scala

Method Calls
    [[NSNumber alloc] initWithInt:42]; 
    NSNumber.alloc().initWithInt(42)
Numbers and Strings
    NSNumber *theNumber = @123;
    
    NSString *greeting = @"Hello Cocoa!"; 
    val theNumber = @@(123)
    
    val greeting = ns"Hello Cocoa!" 
Arrays
    NSArray *theArray = @[@"one", @"two"];
    
    NSString *oneString = theArray[0]; 
    val theArray = NSArray(ns"one", ns"two")
    
    val oneString = theArray(0) 
Dictionaries
    NSDictionary *theDict = @{
      @"greeting": @"Hello",
      @"farewell": @"Goodbye"
    };
    
    NSString *greeting = theDict[@"greeting"]; 
    val theDict = NSDictionary(
      ns"greeting" -> ns"Hello",
      ns"farewell" -> ns"Goodbye"
    )
    
    val greeting = theDict(ns"greeting") 
Defining an Objective-C Class in Scala
    // The constructor argument is the Objective-C proxy for the created Scala instance
    @ScalaObjC
    class AppDelegate(self: NSObject) extends NSApplicationDelegate {
      //protected and private fields are not accessible from Objective-C
      private var _clickCount = 0
      
      // all public vars, vals, and Scala getter/setter are exposed as Objective-C properties
      var window: NSObject = _             // IBOutlet connected in the xib to the application window
      var clickCountView: NSTextField = _  // another IBOutlet
        
      // all public methods are exposed to Objective-C using the normal selector semantics
      def takeClick(id: NSObject): Unit = {  // IBAction connected in xib to a button
        _clickCount += 1
        updateView()
      }
      
      override def applicationDidFinishLaunching(notification: NSNotification): Unit = {
         updateView()
      }
        
      // protected and private methods are not accessible from Objective-C
      private def updateView(): Unit = {
        clickCountView.setIntegerValue(_clickCount)
      } 
    }