Siesta

Using Siesta from Objective-C

Siesta follows a Swift-first design approach. It uses the full expressiveness of the language to make everything feel “Swift native,” both in interface and implementation.

However, a design constraint of Siesta is that you can use it in your Objective-C app. To that end, the features you’ll need to use in your app code are exposed in an Objective-C compatibility layer. Some features related to configuring and customizing Siesta’s behavior for a particular API are only available in Swift.

What’s In, What’s Out

Features exposed to Objective-C:

Some things are not exposed in the compatibility layer, and must be done in Swift:

Naming Conventions

In Swift, everything is namespaced to the framework (Service is shorthand for Siesta.Service). In Objective-C, however, classes and protocol use the BOS prefix to avoid namespace collisions:

Siesta structs are exposed as Objective-C classes, and some Swift classes get wrapped in Obj-C friendly compatibility objects. This may incur a slight performance overhead, which will not be a problem 99.9% of the time — but if for some reason you need to iterate over a massive number of resources and examine their latestData, it might be better to write that bit of code in Swift. Benchmark it and find out.

Setting Up Services

You can use Service subclass from both Objective-C and Swift, but you must write it in Swift.

Objective-C can’t see Swift globals, so you’ll instead need to make your singleton a static constant:

class MyAPI: Service {
    public static let instance = MyAPI(baseURL: "https://api.example.com")
}

You can then do:

[[MyAPI.instance resource:@"/profile"] child:@"123"];

Observers

Objective-C cannot see Swift enums, and ResourceEvent and RequestMethod are both enums. Objective-C methods that deal with events take strings instead, with the enum cases capitalized. In the case of ResourceEvent.newData, the string you receive also contains the nested source of the data in parentheses, e.g. NewData(Network). If you just want to check whether new data arrived and don’t care where it came from, look for the NewData prefix:

- (void) resourceChanged: (BOSResource*) resource event: (NSString*) event {
  if([event hasPrefix:@"NewData"]) {
    ...
  }
}

Runtime vs. Compile-Time Checks

Some things that would be compile errors in Swift’s more robust static type system surface as runtime errors in Objective-C.

Of particular note are the various flavors of [Resource requestWithMethod:...], which take a string instead of an enum for the HTTP method. That means that what is a compile error in Swift:

resource.request(.flargle)

…comes back as a failed request in Objective-C:

[resource requestWithMethod:@"FLARGLE"]

A similar principle applies for attempting to pass something other than a dictionary or an array for a JSON request body.

Request Callbacks

Most of the request callbacks translate naturally into Objective-C blocks, but the completion callback, which can receive either data on success or an error on failure:

resource.request(.post, json: ["color": "green"])
  .onCompletion { info in
    switch info.response {
      case .success(let data):
        
      
      case .failure(let error):
        
    }
  }

…has a different, less type-safe flavor in Objective-C:

[[resource.requestWithMethod:@"POST" json:@{@"color": @"mauve"}]
  onCompletion: ^(BOSEntity *data, BOSError *error) {
    
  }];

Exactly one of the completion block’s two arguments will be non-nil.

Next: FAQ