Objective-C is a general-purpose, object-oriented programming language that adds Smalltalk-style messaging to C.
In LiveCodes, Objective-C runs in the browser using Clang compiled to WebAssembly, with GNUstep's libobjc2 as the Objective-C runtime.
Usage
Demo:
show code
- JS
- TS
- React
- Vue
- Svelte
- Solid
- Preact
- Web Components
import { createPlayground } from 'livecodes';
const options = {
"config": {
"activeEditor": "script",
"script": {
"language": "objc-wasm",
"content": "#import <stdio.h>\n#import <objc/runtime.h>\n\n__attribute__((objc_root_class))\n@interface Greeter {\n Class isa;\n}\n- (void)greet:(const char *)name;\n@end\n\n@implementation Greeter\n- (void)greet:(const char *)name {\n printf(\"Hello, %s!\\n\", name);\n}\n@end\n\nint main(void) {\n Greeter *greeter = class_createInstance(objc_getClass(\"Greeter\"), 0);\n [greeter greet:\"World\"];\n return 0;\n}"
},
"mode": "simple",
"editor": "auto",
"tools": {
"status": "full"
}
}
};
createPlayground('#container', options);
import { createPlayground, type EmbedOptions } from 'livecodes';
const options: EmbedOptions = {
"config": {
"activeEditor": "script",
"script": {
"language": "objc-wasm",
"content": "#import <stdio.h>\n#import <objc/runtime.h>\n\n__attribute__((objc_root_class))\n@interface Greeter {\n Class isa;\n}\n- (void)greet:(const char *)name;\n@end\n\n@implementation Greeter\n- (void)greet:(const char *)name {\n printf(\"Hello, %s!\\n\", name);\n}\n@end\n\nint main(void) {\n Greeter *greeter = class_createInstance(objc_getClass(\"Greeter\"), 0);\n [greeter greet:\"World\"];\n return 0;\n}"
},
"mode": "simple",
"editor": "auto",
"tools": {
"status": "full"
}
}
};
createPlayground('#container', options);
import LiveCodes from 'livecodes/react';
export default function App() {
const options = {
"config": {
"activeEditor": "script",
"script": {
"language": "objc-wasm",
"content": "#import <stdio.h>\n#import <objc/runtime.h>\n\n__attribute__((objc_root_class))\n@interface Greeter {\n Class isa;\n}\n- (void)greet:(const char *)name;\n@end\n\n@implementation Greeter\n- (void)greet:(const char *)name {\n printf(\"Hello, %s!\\n\", name);\n}\n@end\n\nint main(void) {\n Greeter *greeter = class_createInstance(objc_getClass(\"Greeter\"), 0);\n [greeter greet:\"World\"];\n return 0;\n}"
},
"mode": "simple",
"editor": "auto",
"tools": {
"status": "full"
}
}
};
return (<LiveCodes {...options} />);
}
<script setup>
import LiveCodes from "livecodes/vue";
const options = {
"config": {
"activeEditor": "script",
"script": {
"language": "objc-wasm",
"content": "#import <stdio.h>\n#import <objc/runtime.h>\n\n__attribute__((objc_root_class))\n@interface Greeter {\n Class isa;\n}\n- (void)greet:(const char *)name;\n@end\n\n@implementation Greeter\n- (void)greet:(const char *)name {\n printf(\"Hello, %s!\\n\", name);\n}\n@end\n\nint main(void) {\n Greeter *greeter = class_createInstance(objc_getClass(\"Greeter\"), 0);\n [greeter greet:\"World\"];\n return 0;\n}"
},
"mode": "simple",
"editor": "auto",
"tools": {
"status": "full"
}
}
};
</script>
<template>
<LiveCodes v-bind="options" />
</template>
<script>
import LiveCodes from 'livecodes/svelte';
const options = {
"config": {
"activeEditor": "script",
"script": {
"language": "objc-wasm",
"content": "#import <stdio.h>\n#import <objc/runtime.h>\n\n__attribute__((objc_root_class))\n@interface Greeter {\n Class isa;\n}\n- (void)greet:(const char *)name;\n@end\n\n@implementation Greeter\n- (void)greet:(const char *)name {\n printf(\"Hello, %s!\\n\", name);\n}\n@end\n\nint main(void) {\n Greeter *greeter = class_createInstance(objc_getClass(\"Greeter\"), 0);\n [greeter greet:\"World\"];\n return 0;\n}"
},
"mode": "simple",
"editor": "auto",
"tools": {
"status": "full"
}
}
};
</script>
<LiveCodes {...options} />
import LiveCodes from 'livecodes/solid';
export default function App() {
const options = {
"config": {
"activeEditor": "script",
"script": {
"language": "objc-wasm",
"content": "#import <stdio.h>\n#import <objc/runtime.h>\n\n__attribute__((objc_root_class))\n@interface Greeter {\n Class isa;\n}\n- (void)greet:(const char *)name;\n@end\n\n@implementation Greeter\n- (void)greet:(const char *)name {\n printf(\"Hello, %s!\\n\", name);\n}\n@end\n\nint main(void) {\n Greeter *greeter = class_createInstance(objc_getClass(\"Greeter\"), 0);\n [greeter greet:\"World\"];\n return 0;\n}"
},
"mode": "simple",
"editor": "auto",
"tools": {
"status": "full"
}
}
};
return (<LiveCodes {...options} />);
}
import LiveCodes from 'livecodes/preact';
export default function App() {
const options = {
"config": {
"activeEditor": "script",
"script": {
"language": "objc-wasm",
"content": "#import <stdio.h>\n#import <objc/runtime.h>\n\n__attribute__((objc_root_class))\n@interface Greeter {\n Class isa;\n}\n- (void)greet:(const char *)name;\n@end\n\n@implementation Greeter\n- (void)greet:(const char *)name {\n printf(\"Hello, %s!\\n\", name);\n}\n@end\n\nint main(void) {\n Greeter *greeter = class_createInstance(objc_getClass(\"Greeter\"), 0);\n [greeter greet:\"World\"];\n return 0;\n}"
},
"mode": "simple",
"editor": "auto",
"tools": {
"status": "full"
}
}
};
return (<LiveCodes {...options} />);
}
<live-codes></live-codes>
<script type="module">
import "livecodes/web-components";
const playground = document.querySelector("live-codes");
playground.config = {
"activeEditor": "script",
"script": {
"language": "objc-wasm",
"content": "#import <stdio.h>\n#import <objc/runtime.h>\n\n__attribute__((objc_root_class))\n@interface Greeter {\n Class isa;\n}\n- (void)greet:(const char *)name;\n@end\n\n@implementation Greeter\n- (void)greet:(const char *)name {\n printf(\"Hello, %s!\\n\", name);\n}\n@end\n\nint main(void) {\n Greeter *greeter = class_createInstance(objc_getClass(\"Greeter\"), 0);\n [greeter greet:\"World\"];\n return 0;\n}"
},
"mode": "simple",
"editor": "auto",
"tools": {
"status": "full"
}
};
</script>
Communication with JavaScript
The Objective-C code runs in the context of the result page. A few helper properties and methods are available in the browser global livecodes.objc object:
livecodes.objc.input: The initial standard input passed to the code.
livecodes.objc.loaded: A promise that resolves when the environment is fully loaded. Other helpers should be used after this promise resolves.
livecodes.objc.output: The standard output from the code execution.
livecodes.objc.error: The compiler diagnostics, if the code failed to compile.
livecodes.objc.exitCode: The exit code of the program.
livecodes.objc.run: A function that compiles and runs the code with new input. This function takes a string as input and returns a promise that resolves with an object containing the output, error and exitCode properties.
Example:
show code
- JS
- TS
- React
- Vue
- Svelte
- Solid
- Preact
- Web Components
import { createPlayground } from 'livecodes';
const options = {
"template": "objc-wasm",
"params": {
"activeEditor": "markup"
}
};
createPlayground('#container', options);
import { createPlayground, type EmbedOptions } from 'livecodes';
const options: EmbedOptions = {
"template": "objc-wasm",
"params": {
"activeEditor": "markup"
}
};
createPlayground('#container', options);
import LiveCodes from 'livecodes/react';
export default function App() {
const options = {
"template": "objc-wasm",
"params": {
"activeEditor": "markup"
}
};
return (<LiveCodes {...options} />);
}
<script setup>
import LiveCodes from "livecodes/vue";
const options = {
"template": "objc-wasm",
"params": {
"activeEditor": "markup"
}
};
</script>
<template>
<LiveCodes v-bind="options" />
</template>
<script>
import LiveCodes from 'livecodes/svelte';
const options = {
"template": "objc-wasm",
"params": {
"activeEditor": "markup"
}
};
</script>
<LiveCodes {...options} />
import LiveCodes from 'livecodes/solid';
export default function App() {
const options = {
"template": "objc-wasm",
"params": {
"activeEditor": "markup"
}
};
return (<LiveCodes {...options} />);
}
import LiveCodes from 'livecodes/preact';
export default function App() {
const options = {
"template": "objc-wasm",
"params": {
"activeEditor": "markup"
}
};
return (<LiveCodes {...options} />);
}
<live-codes
template="objc-wasm"></live-codes>
<script type="module">
import "livecodes/web-components";
const playground = document.querySelector("live-codes");
playground.params = {
"activeEditor": "markup"
};
</script>
The same API is available as livecodes.clangWasm for all Clang-based languages.
Language Info
Name
objc-wasm
Aliases / Extensions
m, objc, objc-wasm, objective-c, wasm.m, clang.m, clang-objc
Editor
script
Compiler
Clang compiled to WebAssembly via @live-codes/clang-wasm, with a complete libc.
Version
Clang v22.1.8. The standards gnu11, gnu17 and gnu23 are supported (default: gnu23).
Limitations
The Objective-C runtime is GNUstep's libobjc2, which is a runtime and not a class library. There is no NSObject and no NSString, and Foundation is not available. Programs declare their own root class (as in the example above) and create instances directly.
Objective-C exceptions (@try/@catch/@throw) are not supported.
Custom Settings
The Clang compiler can be configured using custom settings added to the property objc-wasm:
| Property | Type | Description |
|---|
std | string | The Objective-C standard to compile with: gnu11, gnu17 or gnu23. Defaults to gnu23. |
compileArgs | string[] | Extra clang flags, e.g. ["-Wall", "-O2"]. |
args | string[] | Command-line arguments passed to the program (argv). |
Custom Settings
{
"objc-wasm": {
"std": "gnu17",
"compileArgs": ["-Wall", "-O2"],
"args": ["--name", "LiveCodes"]
}
}
Using @wasm-fmt/clang-format, applying Google's C++ style guide.
Live Reload
By default, new code changes are sent to the result page without a full page reload, avoiding the need to re-download the compiler. This behavior can be disabled by adding the code comment // __livecodes_reload__ to the code, which forces a full page reload.
This comment can be added in the hiddenContent property of the editor for embedded playgrounds.
Example Usage
#import <stdio.h>
#import <objc/runtime.h>
__attribute__((objc_root_class))
@interface Greeter {
Class isa;
}
- (void)greet:(const char *)name;
@end
@implementation Greeter
- (void)greet:(const char *)name {
printf("Hello, %s!\n", name);
}
@end
int main(void) {
Greeter *greeter = class_createInstance(objc_getClass("Greeter"), 0);
[greeter greet:"LiveCodes"];
return 0;
}
Starter Template
https://livecodes.io/?template=objc-wasm
Links