# Objective-C

Interfacing with Objective-C code

[Reference](index.md)

<a id="section-Guides"></a>

## Guides

<a id="Using-Native-APIs"></a>

### Using Native APIs

Use `objc` to call Objective-C classes from Lua. This gives your project
access to system features beyond Codea’s built-in drawing, input, and sound commands.

## Start small

Look up a class, create an object, and call its methods. Check the method’s
parameter types: Lua values, native objects, selectors, and structs are passed
in different ways. See [Objective-C](#objc) for conversions and examples.

Present native controls from the active view controller. Keep callback objects
alive while native code uses them, and release observers or delegates when the
project stops. System permissions and entitlements still apply.

<a id="section-Objective-C"></a>

## Objective-C

<a id="objc"></a>

### objc

Use Objective-C classes and system features from Lua.

**Native Classes**

To access a native Objective-C class, append its name to `objc`.

```lua
-- access the UIScreen class
UIScreen = objc.UIScreen
```

**Constructor**

If the native class has a `new` constructor, you can invoke it directly instead of calling the `new` method.

```lua
-- create an instance of NSDateComponents
dateComponents = objc.NSDateComponents()
```

**Properties**

Properties can be read and modified directly.

```lua
-- read the screen brightness
brightness = objc.UIScreen.mainScreen.brightness

-- change the screen brightness
objc.UIScreen.mainScreen.brightness = 0.5
```

**Methods**

Methods are invoked using the ‘:’ operator and their full selector name, including named arguments separated by underscores ‘_’ instead of colons. Note that the Objective-C method names must always end with an underscore in Codea. The underscores are required for Codea to find the corresponding signatures in Objective-C.

```lua
-- Calling a method with multiple arguments
controller:presentViewController_animated_completion_(newController, true, nil)

-- Calling a method with no argument
webView:goBack_()
```

**Callbacks**

Callbacks such as completion handlers with up to 7 arguments are supported by passing a function where each parameter is prefixed to indicate the corresponding native type.

The following prefixes are supported for callback arguments:

- c: char
- i: int, NSInteger
- uc: unsigned char
- ui: unsigned int, NSUInteger
- f: float
- d: double, CGFloat
- b: bool, BOOL
- s: char*
- o: NSObject, NSString, etc.

Note that only the first one or two characters are important in your argument names. `bGranted` and `boolGranted` will both work for a boolean argument, but for our examples, we decided to go with the second option.

Struct members are passed separately. For example, for an NSRange argument, you could use intLocation and intLength arguments.

Pointers for value types are also supported by prefixing them with `p`, (e.g. `pboolStop`). The actual value can be accessed and modified using `.value`.

Note that when using objc from within a callback, changes are not guaranteed to occur on the main thread. Consider using `objc.async` inside your callback if you need changes to happen on the main thread, such as modifying UIControls.

**Automatic Conversions**

Some Codea types will be converted to corresponding Objective types automatically when passed to native methods or properties.

- **color**: UIColor
- **vec2**: CGPoint

```lua
--- uiView: objc.UIView
uiView.backgroundColor = Color(255, 0, 0)

--- uiTextView: objc.UITextView
uiTextView:setContentOffset_(vec2(0, 100))
```

Conversions also happen in the other direction: a `UIImage` or `UIColor`
returned from a native method arrives in Lua as a Codea `image` or `color`.

**Disabling automatic conversion**

Because the conversion happens on the way into Lua, a returned `UIImage` has
already become a Codea `image` and can no longer be configured. Set
`objc.automaticBridging` to `false` to receive the native object instead.

```lua
objc.automaticBridging = false

local native = objc.UIImage:systemImageNamed_("globe")
native = native:imageWithTintColor_(color(255, 0, 0))

objc.automaticBridging = true

img = objc.bridge(native)   -- convert it now
```

`objc.bridge(value)` performs the conversion explicitly, whatever the current
setting is.

Prefer `objc.withoutBridging(f)`, which restores the previous setting
afterwards — including when `f` raises an error, where a bare flag would stay
switched off for the rest of the session.

```lua
img = objc.withoutBridging(function()
    local native = objc.UIImage:systemImageNamed_("globe")
    native = native:imageWithTintColor_(color(255, 0, 0))
    return objc.bridge(native)
end)
```

**Note**

For SF Symbols specifically, prefer [`image.symbol()`](Graphics.md#image.symbol), which needs no
`objc` at all.

**Examples**

*Change the screen brightness to 50%*

```lua
objc.UIScreen.mainScreen.brightness = 0.5
```

*Request application review*

```lua
scene = objc.app.keyWindow.windowScene
store = objc.SKStoreReviewController
store:requestReviewInScene_(scene)
```

*Request notifications permission*

```lua
center = objc.
    UNUserNotificationCenter.
    currentNotificationCenter
options = objc.enum.UNAuthorizationOptions
center:requestAuthorizationWithOptions_completionHandler_(
    options.badge | options.sound | options.alert,
    function(boolGranted, objError)
    if boolGranted then
        print("granted")
    elseif objError then
        print("error " .. objError.code)
    end
    end)
```

*Enumerate words until the word stop is found*

```lua
txt = "First second stop third fourth"
str = objc.string(txt)
str:enumerateSubstringsInRange_options_usingBlock_(
    objc.range(0, txt:len()),
    objc.enum.NSStringEnumerationOptions.byWords,
    function(objWord,
            isubstringLocation,
            iSubstringLength,
            iEnclosingLocation,
            iEnclosingLength,
            pboolStop)
        if objWord == "stop" then
            pboolStop.value = true
        else
            print(objWord)
        end
    end)
```

<a id="objc.delegate"></a>

### objc.delegate(name)

```lua
objc.delegate("DelegateName")
```

Returns a type which can be instantiated and used as an Objective-C delegate for the specified type.

create an Objective-C delegate type

#### Parameters

- **name** (string): The name of the delegate.

#### Returns

- **table**: A type to be used as an Objective-C delegate.

#### UITextViewDelegate Example

```lua
Delegate = objc.delegate("UITextViewDelegate")

function Delegate:textViewShouldBeginEditing_(objTextView)
    -- replace with false to prevent editing
    return true
end

function Delegate:textViewDidChange_(objTextView)
    print(objTextView.text)
end

-- uiTextView.delegate = Delegate()
```

#### WKScriptMessageHandler Example

```lua
-- Exposes the following method to JavaScript:
-- window.webkit.messageHandlers.log.postMessage
Handler = objc.delegate("WKScriptMessageHandler")

function Handler:
    userContentController_didReceiveScriptMessage_(
    objUserContentController, objMessage)
    print(objMessage.body)
end

function setup()
    local ctrl = objc.WKUserContentController()
    local logHandler = Handler()
    ctrl:addScriptMessageHandler_name_(
    logHandler, "log")
end
```

<a id="objc.class"></a>

### objc.class(name)

```lua
objc.class("ClassName")
```

Returns a type which can be instantiated and used as an Objective-C class, for example combined with a selector when registering for notifications through the NSNotificationCenter.

create an Objective-C class type

#### Parameters

- **name** (string): The name of the class.

#### Returns

- **table**: A type to be used as an Objective-C class.

#### NotificationHandler Example

```lua
NotificationHandler = objc.class("NotificationHandler")

function NotificationHandler:textDidChange(objNotification)
    print(objNotification.object.text)
end

handler = NotificationHandler()

notificationCenter = objc.NSNotificationCenter.defaultCenter
notificationCenter:addObserver_selector_name_object_(
    handler,
    objc.selector("textDidChange"),
    "UITextViewTextDidChangeNotification",
    nil)
```

<a id="objc.selector"></a>

### objc.selector(name)

```lua
objc.selector("SelectorName")
```

Returns an Objective-C selector with the specified name which can be used in combination with an objc.class, for example to register for notifications through the NSNotificationCenter.

create an Objective-C selector

#### Parameters

- **name** (string): The name of the selector.

#### Returns

- **table**: An Objective-C selector (or SEL).

#### NotificationHandler Example

```lua
NotificationHandler = objc.class("NotificationHandler")

function NotificationHandler:textDidChange(objNotification)
    print(objNotification.object.text)
end

handler = NotificationHandler()

notificationCenter = objc.NSNotificationCenter.defaultCenter
notificationCenter:addObserver_selector_name_object_(
    handler,
    objc.selector("textDidChange"),
    "UITextViewTextDidChangeNotification",
    nil)
```

<a id="objc.set"></a>

### objc.set(table)

```lua
objc.set({1, 2, 3})
```

Returns an Objective-C NSSet initialized from a Lua table.

By default, NSSet returned from calls to Objective-C (or reading properties) are automatically converted to Lua tables. If you need to use the NSSet, you can convert the table to NSSet using `objc.set`.

create an NSSet from a Lua table

#### Parameters

- **table** (table): A Lua table.

#### Returns

- **table**: An Objective-C NSSet.

<a id="objc.string"></a>

### objc.string(text)

```lua
objc.string("Text")
```

Returns an Objective-C NSString initialized from a Lua string.

By default, strings returned from calls to Objective-C (or reading properties) are automatically converted to Lua strings and vice versa. If you need to access NSString methods, you can convert the strings to NSString using `objc.string`.

create an NSString from a Lua string

#### Parameters

- **text** (string): The text to convert to an NSString.

#### Returns

- **table**: An Objective-C NSString.

<a id="objc.automaticBridging"></a>

### objc.automaticBridging

```lua
objc.automaticBridging = false
```

Whether values crossing from Objective-C into Lua are converted to their Codea
equivalents. Defaults to `true`.

While `false`, a `UIImage` or `UIColor` returned from a native call
arrives as the wrapped Objective-C object instead of a Codea `image` or
`color`, so it can still be configured. Prefer `objc.withoutBridging()`
over setting this directly — an error raised while it is `false` would leave
it switched off for the rest of the session.

whether ObjC values are converted to Codea types

<a id="objc.withoutBridging"></a>

### objc.withoutBridging(body)

```lua
img = objc.withoutBridging(function()
    local native = objc.UIImage:systemImageNamed_("globe")
    native = native:imageWithTintColor_(color(255, 0, 0))
    return objc.bridge(native)
end)
```

Runs `body` with `objc.automaticBridging` disabled, restoring the
previous setting afterwards — including when `body` raises an error.

Returns whatever `body` returns.

run a function without automatic ObjC conversion

#### Parameters

- **body** (function): The function to run with bridging disabled.

<a id="objc.bridge"></a>

### objc.bridge(value)

```lua
img = objc.bridge(native)
```

Converts an Objective-C value to its Codea equivalent, whatever the current
`objc.automaticBridging` setting is.

Used to convert a native object once it has been configured. Values with no
Codea equivalent are returned unchanged.

convert an ObjC value to a Codea type

#### Parameters

- **value** (any): The Objective-C value to convert.

#### Returns

- **value**: The Codea equivalent, or the value unchanged.

<a id="objc.enum"></a>

### objc.enum

```lua
objc.enum.EnumName.ValueName
```

Exposes native Objective-C enumerations.

When value names are prefixed with their enumeration’s name, the prefix is removed to simplify their usage.

For example, `objc.enum.NLTokenUnit.paragraph` is the integer value for `NLTokenUnitParagraph` (`2`).

Unnamed enum values can be found directly under `objc.enum`, e.g. `objc.enum.NSUTF8StringEncoding`.

access native enumarations

#### Combine UNAuthorizationOptions

```lua
opts =
    objc.enum.UNAuthorizationOptions.badge |
    objc.enum.UNAuthorizationOptions.sound |
    objc.enum.UNAuthorizationOptions.alert
```

<a id="objc.app"></a>

### objc.app

```lua
objc.app
```

The UIApplication’s `sharedApplication`.

access the sharedApplication

<a id="objc.viewer"></a>

### objc.viewer

```lua
objc.viewer
```

The runtime `UIViewController`.

update view settings such as display mode

<a id="objc.info"></a>

### objc.info

```lua
objc.info
```

Exposes the info dictionary keys and values.

For better readability, all keys have their Apple prefix removed.

For example, to get the value of `NSBundleIdentifier`, use `objc.info.bundleIdentifier`.

access the application info dictionary

#### Test if running in an exported project

```lua
isStandalone = objc.info.bundleIdentifier ~= "com.twolivesleft.Codify"
```

<a id="objc.insets"></a>

### objc.insets(top, left, bottom, right)

```lua
objc.insets(top, left, bottom, right)
```

Create a UIEdgeInsets.

create a UIEdgeInsets

#### Parameters

- **top** (number): top value of the UIEdgeInsets
- **left** (number): left value of the UIEdgeInsets
- **bottom** (number): bottom value of the UIEdgeInsets
- **right** (number): right value of the UIEdgeInsets

#### Returns

- **objc.private.insets**: The UIEdgeInsets struct.

<a id="objc.log"></a>

### objc.log(message)

```lua
objc.log(message)
```

Log a message using NSLog instead of the Codea console.

log a message with NSLog

#### Parameters

- **message** (string): Message to display.

<a id="objc.inspect"></a>

### objc.inspect(class)

```lua
objc.inspect(class)
```

Inspect an Objective-C class, listing its variables, properties, methods and protocols.

Returns a table with the following information:

- **super**: the superclass which can be used as if it was accessed through `objc`
- **variables**: array of instance variables
  - **name**: name of the variable
  - **typeEncoding**: see [Type Encoding](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html)
  - **type**: user-friendly name of the variable type
- **properties**: array of instance properties
  - **name**: name of the property
  - **attributes**: see [Property Type String](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html)
  - **type**: user-friendly name of the property type
- **methods**: array of instance methods
  - **name**: name of the methods
  - **returnType**: user-friendly name of the method’s return type
  - **arguments**: array of method arguments
    - **name**: name of the arguments
    - **typeEncoding**: see [Type Encoding](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html)
    - **type**: user-friendly name of the argument’s type
- **protocols**: array of instance protocols
  - **name**: name of the protocol

Class members are accessible by prefixing with `class.`, for example using `objc.inspect(myClass).class.variables` to list the class variables of myClass.

inspect an Objective-C class

#### Parameters

- **class** (table): Objective-C class to inspect.

#### Returns

- **table**: A table with the class information

#### Inspect the SFSpeechRecognizer class

```lua
inspect = objc.inspect(objc.SFSpeechRecognizer)
print("Class has " .. #inspect.methods .. " instance methods.")
```

<a id="objc.async"></a>

### objc.async(function)

```lua
objc.async(function)
```

run a function asynchronously

#### Parameters

- **function** (function): Parameterless function to run on the target thread.

<a id="objc.point"></a>

### objc.point(x, y)

```lua
objc.point(x, y)
```

Create a CGPoint.

create a CGPoint

#### Parameters

- **x** (number): x position of the CGPoint
- **y** (number): y position of the CGPoint

#### Returns

- **table**: The CGPoint struct.

#### Create a CGPoint

```lua
point = objc.point(100, 200)
```

<a id="objc.rect"></a>

### objc.rect(x, y, width, height)

```lua
objc.rect(x, y, width, height)
```

Create a CGRect.

draw a rectangle

#### Parameters

- **x** (number): x position of the CGRect
- **y** (number): y position of the CGRect
- **width** (number): width of the CGRect
- **height** (number): height of the CGRect

#### Returns

- **table**: The CGRect struct.

#### Create a CGRect

```lua
rect = objc.rect(100, 200, 300, 400)
```

<a id="objc.size"></a>

### objc.size(width, height)

```lua
objc.size(width, height)
```

Create a CGSize.

create a CGSize

#### Parameters

- **width** (number): width of the CGSize
- **height** (number): height of the CGSize

#### Returns

- **table**: The CGSize struct.

#### Create a CGSize

```lua
size = objc.size(300, 400)
```

<a id="objc.range"></a>

### objc.range(loc, len)

```lua
objc.range(loc, len)
```

Create a NSRange.

create an NSRange

#### Parameters

- **loc** (number): location of the NSRange
- **len** (number): length of the NSRange

#### Returns

- **table**: The NSRange struct.

#### Create a NSRange

```lua
range = objc.range(10, 20)
```

<a id="objc.color"></a>

### objc.color(r, g, b, a)

```lua
objc.color(r, g, b, a)
```

Create a CGColor. For UIColor, use the Codea Color type instead.

create a new color type

#### Parameters

- **r** (number): red value of the CGColor
- **g** (number): green value of the CGColor
- **b** (number): blue value of the CGColor
- **a** (number): alpha value of the CGColor

#### Returns

- **table**: The CGColor struct.

#### Create a CGColor

```lua
color = objc.color(1, 0, 0, 1)
```

<a id="objc.vector"></a>

### objc.vector(dx, dy)

```lua
objc.vector(dx, dy)
```

Create a CGVector.

create a CGVector

#### Parameters

- **dx** (number): x direction of the CGVector
- **dy** (number): y direction of the CGVector

#### Returns

- **table**: The CGVector struct.

#### Create a CGVector

```lua
vector = objc.vector(1, 0)
```

<a id="objc.affineTransform"></a>

### objc.affineTransform()

```lua
objc.affineTransform(a, b, c, d, tx, ty)
```

Create a [CGAffineTransform](https://developer.apple.com/documentation/coregraphics/cgaffinetransform?language=objc).

create a CGAffineTransform

#### Returns

- **table**: The CGAffineTransform struct.

#### Create a CGAffineTransform

```lua
affineTransform = objc.affineTransform(1, 0, 0, 1, 100, 200)
```

<a id="Loading-Frameworks"></a>

### Loading Frameworks

Here are some of the frameworks included with the Codea runtime.

Refer to Apple’s documentation for how to interact with them.

- [ARKit](https://developer.apple.com/documentation/arkit?language=objc)
- [AssetsLibrary](https://developer.apple.com/documentation/assetslibrary?language=objc)
- [AudioKit](https://audiokit.io)
- [AudioToolbox](https://developer.apple.com/documentation/audiotoolbox?language=objc)
- [AuthenticationServices](https://developer.apple.com/documentation/authenticationservices?language=objc)
- [CFNetwork](https://developer.apple.com/documentation/cfnetwork?language=objc)
- [CoreBluetooth](https://developer.apple.com/documentation/corebluetooth?language=objc)
- [CoreGraphics](https://developer.apple.com/documentation/coregraphics?language=objc)
- [CoreHaptics](https://developer.apple.com/documentation/corehaptics?language=objc)
- [CoreLocation](https://developer.apple.com/documentation/corelocation?language=objc)
- [CoreMedia](https://developer.apple.com/documentation/coremedia?language=objc)
- [CoreMIDI](https://developer.apple.com/documentation/coremidi?language=objc)
- [CoreML](https://developer.apple.com/documentation/coreml?language=objc)
- [CoreMotion](https://developer.apple.com/documentation/coremotion?language=objc)
- [CoreText](https://developer.apple.com/documentation/coretext?language=objc)
- [CoreVideo](https://developer.apple.com/documentation/corevideo?language=objc)
- [FileProvider](https://developer.apple.com/documentation/fileprovider?language=objc)
- [GameController](https://developer.apple.com/documentation/gamecontroller?language=objc)
- [GameplayKit](https://developer.apple.com/documentation/gameplaykit?language=objc)
- [GLKit](https://developer.apple.com/documentation/glkit?language=objc)
- [JavaScriptCore](https://developer.apple.com/documentation/javascriptcore?language=objc)
- [MapKit](https://developer.apple.com/documentation/mapkit?language=objc)
- [MediaPlayer](https://developer.apple.com/documentation/mediaplayer?language=objc)
- [MessageUI](https://developer.apple.com/documentation/messageui?language=objc)
- [MLCompute](https://developer.apple.com/documentation/mlcompute?language=objc)
- [NaturalLanguage](https://developer.apple.com/documentation/naturallanguage?language=objc)
- [OpenGLES](https://developer.apple.com/documentation/opengles?language=objc)
- [PDFKit](https://developer.apple.com/documentation/pdfkit?language=objc)
- [PencilKit](https://developer.apple.com/documentation/pencilkit?language=objc)
- [ReplayKit](https://developer.apple.com/documentation/replaykit?language=objc)
- [Social](https://developer.apple.com/documentation/social?language=objc)
- [Speech](https://developer.apple.com/documentation/speech?language=objc)
- [UIKit](https://developer.apple.com/documentation/uikit?language=objc)
- [UserNotifications](https://developer.apple.com/documentation/usernotifications?language=objc)
- [WebKit](https://developer.apple.com/documentation/webkit?language=objc)

For a more exhaustive list, use the example code below.

*List all included system Frameworks*

```lua
-- list all included system Frameworks
local bundles = objc.NSBundle.allFrameworks
local systemBundles = {}

for i, b in ipairs(bundles) do
    if string.find(
        b.bundlePath,
        "System/Library/Frameworks/") then
        table.insert(systemBundles, b.bundlePath)
    end
end

table.sort(systemBundles)

for i, bundle in ipairs(systemBundles) do
    print(bundle)
end
```
