# Objective-C from JavaScript

Use **UIHelper** to find buttons, enter text and scroll. Use **ObjC** when you want to call a native Objective-C method directly, such as reading a Foundation object. You write JavaScript; you do not need to write or compile Objective-C.

## Choose where the method runs

| Where | API | Example |
| --- | --- | --- |
| Inside SpringBoard | `ObjC` | `ObjC.class("NSUUID").UUID()` |
| Inside another app | `RemoteObjC.forApp(bundleId)` | `app.class("NSBundle").mainBundle()` |

**Local means SpringBoard.** Opening another app or selecting it in the inspector does not change the target of `ObjC`. You do not need to connect to another app for local calls. Both APIs are available directly in scripts without imports or the `at.` prefix.

To confirm the target:

```js
console.log(ObjC.getInfo().processName); // "SpringBoard"
```

## Call methods directly in SpringBoard

Get a class, call its methods, and convert native strings with `toJS()`:

```js
const NSUUID = ObjC.class("NSUUID");
const uuid = NSUUID.UUID();
const text = uuid.UUIDString();
try {
  console.log(text.toJS()); // A UUID string
} finally {
  text.release();
  uuid.release();
}
```

You can also obtain SpringBoard's application object:

```js
const SpringBoard = ObjC.class("SpringBoard");
const application = SpringBoard.sharedApplication();
try {
  console.log(application.respondsTo("canOpenURL:"));
} finally {
  application.release();
}
```

The same style works with other classes already loaded in SpringBoard. Use `ObjC.hasClass("ClassName")` to check availability. Installing an app or library does not mean its classes exist in SpringBoard. Private classes and methods can differ between iOS versions.

## Four words you need

| Word | Meaning | Example |
| --- | --- | --- |
| Client | Chooses which process receives your calls | `ObjC` or `RemoteObjC.forApp(bundleId)` |
| Class | A native type that can create objects or provide class methods | `NSString`, the native string type |
| Object / proxy | A JavaScript handle to a native object | The string returned by `stringWithString:` |
| Selector | The exact name of a native method, including its colons | `stringWithString:` |

`ObjCObject` on reference pages is a label for returned objects. It is not a global to import or construct. Likewise, `client` and `object` in a signature are example variable names.

## 1. Make a native string and read its value

```js
const text = ObjC.call("NSString", "stringWithString:", "Hello");
try {
  console.log(text.toJS());          // "Hello": a normal JS string
  console.log(text.call("length"));  // 5: a normal JS number
} finally {
  text.release();
}
```

Read the first line as: **ask the NSString class to run stringWithString: with "Hello" as its argument**. The result is a native object handle. `toJS()` copies its string value into JavaScript. `length` already returns a number, so it needs no `toJS()`.

`release()` releases your handle when finished. It does not close an app. Do not use that handle afterward. Script cleanup also releases references, but explicit cleanup avoids accumulation in long loops.

## 2. Call a method with more than one argument

```js
const dictionary = ObjC.create("NSMutableDictionary");
try {
  dictionary.call("setObject:forKey:", "Hello", "message");
  console.log(dictionary.toJS()); // {message: "Hello"}
} finally {
  dictionary.release();
}
```

`ObjC.create()` allocates and initializes an object. `setObject:forKey:` takes two arguments in that order: the value, then its key. Each colon belongs to one argument. You must know which class or object provides the method; the bridge does not invent app methods.

## 3. Optional shorthand

These two calls are equivalent:

```js
const dictionary = ObjC.create("NSMutableDictionary");
try {
  dictionary.call("setObject:forKey:", "Hello", "message");
  dictionary.setObject_forKey_("Hello", "message");
} finally {
  dictionary.release();
}
```

Replace selector colons with underscores. `length()` has no arguments and needs no underscore. The final underscore is optional: `setObject_forKey("Hello", "message")` also works. Use `call("exact:selector:", ...)` when you prefer exact native spelling or when a native method name collides with a helper such as `get`, `set` or `release`. A double underscore represents a literal underscore.

## 4. Read information inside another app

`ObjC` always addresses SpringBoard. To call inside Settings, open it and choose a remote client:

```js
if (!openApp("com.apple.Preferences")) throw new Error("Could not open Settings");
const app = RemoteObjC.forApp("com.apple.Preferences");
console.log(app.getInfo().bundleId); // "com.apple.Preferences"
const bundle = app.class("NSBundle").mainBundle();
let identifier;
try {
  identifier = bundle.bundleIdentifier();
  console.log(identifier ? identifier.toJS() : null);
} finally {
  if (identifier) identifier.release();
  bundle.release();
}
```

The remote client has the same `class`, `call`, `create`, `out` and other methods as `ObjC`. Creating it does not launch the app. The app must be running with its ApplesauceOS helper enabled; a suspended or blacklisted app may not answer.

Keep one client per app and reuse it. Objects belong to the client/session that created them: copy ordinary data with `toJS()` before passing it to another client. After an app restart, call `app.reconnect()` and obtain new object handles.

## What comes back?

| Native result | JavaScript result | What to do |
| --- | --- | --- |
| BOOL, integer, floating point | Boolean or number | Use directly |
| Integer outside the safe Number range | BigInt, or decimal string if BigInt is unavailable | Preserve precision; convert to a string before JSON serialization |
| NSString, NSArray, NSDictionary, NSNumber | Native object proxy | Use `toJS()` when you need ordinary JS data |
| Other native object | Native object proxy | Call its known methods; `toJS()` is not a universal object serializer |
| nil or void | `null` | Check before calling methods |
| Supported structure, such as CGRect | Plain object with named fields | Read `x`, `y`, `width`, `height` for CGRect |

Pass JavaScript `null` for native nil; the string `"nil"` is just text. `get(key)` and `set(key, value)` use native key-value coding. Assigning `object.someProperty = value` is unsupported; use `set()` or an exact native setter.

## Errors and limits

If a class or selector is unavailable, calls throw. `hasClass()` and `respondsTo()` let you check support. `signature()` reports native type encodings; it is an advanced diagnostic, not a human description of what a method does.

Calls are synchronous and execute on the target's main thread. Keep them short. Remote timeouts stop waiting; they do not undo a method already executing. Do not automatically repeat an uncertain mutation.

Callbacks, non-null Objective-C blocks, variadic methods, unions and arbitrary pointer arguments are unsupported. Known C functions use [C and RemoteC](/doc/native). Wrong native calls can crash the target process.

## Find the method you need

| Task | Reference |
| --- | --- |
| Choose another app | [RemoteObjC.forApp](/doc/api/remoteobjc-forapp) |
| Find a class / check availability | [class](/doc/api/objc-class), [hasClass](/doc/api/objc-hasclass) |
| Call a class or object method | [ObjC.call](/doc/api/objc-call), [object.call](/doc/api/objcobject-call) |
| Create an object | [create](/doc/api/objc-create) |
| Copy a native value into JS | [toJS](/doc/api/objcobject-tojs) |
| Read or write a native property | [get](/doc/api/objcobject-get), [set](/doc/api/objcobject-set) |
| Receive an NSError output parameter | [out](/doc/api/objc-out) |
| Inspect method support | [respondsTo](/doc/api/objcobject-respondsto), [signature](/doc/api/objcobject-signature) |
| Release a handle / session | [release](/doc/api/objcobject-release), [close](/doc/api/objc-close) |
| Recover after an app restart | [reconnect](/doc/api/objc-reconnect) |

Each reference page has its own arguments, result and small example. Read the target native API's documentation too: an ApplesauceOS method explains how to call it, not the meaning of every method supplied by every app.
