Develop with Cocoa for Apple devices without using Objective-C
felixk15.github.io
felixk15.github.io
The article makes no mention of memory management. ARC is a compiler feature, so I guess this C code makes a ton of calls to an nsobject_release() function for everything allocated in Obj-C world. The code example shown seems to be just leaking the NSString instance.
Which platform doesn't have Clang? Why not allow the Obj-C compiler to take away all that C boilerplate and fragile retain counting gruntwork, and then wrap those calls in a concise C API that provides the exact interface your application needs? I don't really get it.
100%. If you’re tying your codebase to Cocoa (or other objc framework), it makes zero sense to avoid Objective-C while also requiring intimate knowledge of Objective-C conventions.
Plus, you’re potentially breaking all sorts of related tooling. Documentation lookup becomes harder. Will Instruments work right? Can you get clang Static Analyzer tips? What about objc-specific compiler warnings? Any time you want to search for code / examples / whatever, you have to translate the symbols. What does it do to a stack trace? Do you get the same deprecation warnings? Does it work correctly if a team member uses a different SDK version, either intentionally or accidentally?
There are obviously things that could be refined, but for a first release it has proven to be very effective in production.
It seems that if you unleash this wrapper onto a C programmer who has never used Cocoa, you'll just be in a world of hurt with unexplained memory leaks and segfaults due to misunderstood object lifetimes.
For example, class factory methods like +[NSString stringWithFormat:] will return an autoreleased instance. How will the C programmer know this convention if they've never used Objective-C?
Practically nobody starts a new project on macOS / iOS that uses manual memory management instead of ARC, so you won't have a lot of documentation when you go down this path. The Apple documentation for the aforementioned stringWithFormat: method doesn't mention (anymore!) that the return value is autoreleased because that doesn't matter with ARC, but makes all the difference for someone using the C wrapper.
There's no magic in ARC, it's all just calls to retain and release that the compiler synthesizes for you automatically. If you have the headers, you can do what it does and figure out which methods return objects that need to be manually released. If you were generating bindings for a language with RAII, like Rust or C++, you could create a bunch of wrapper types and give them destructors, the best you can do for C is adding an extra paragraph in your docs.
This is true for every API under the sun. If you just use it without reading the documentation or understanding the design philosophy, you're alyways in a world of hurt.
The same things that are true for Obj-C are true for the wrapper, it just lets you use the API in C. No more, no less.
In fact you need to know quite a bit more about Obj-C details than the average iOS programmer because you’re doing manual memory management rather than compiler-assisted ARC (automatic reference counting).
So I don’t really see who this is for. The person who has to learn Obj-C but must pretend not to know it to please the boss who insisted on plain C?
They literally covered this point for you:
> The Apple documentation for the aforementioned stringWithFormat: method doesn't mention (anymore!) that the return value is autoreleased because that doesn't matter with ARC
It is no secret that documentation surrounding the "old ways" of Apple dev is a pain in the ass to find.
And it doesn't help people who aren't used to Objective-C, because they'll be utterly, hopelessly lost trying to deal with platform-specific features like autorelease pools and Foundation-specific calling conventions. And they won't be able to find docs for your weird syntax.
You cannot remove the platform from the platform specific bits! It will come back to bite you.
Also, you really need to check the memory management situation -- the code samples are leaking memory out the wazoo and it doesn't give confidence that any code using your wrapper isn't doing the same.
It’s a bit like using unsafe in rust - you’re the one responsible.
I don’t see much of a point of doing it that way. I do prefer working with ObjC with some C in it if need be ;)
If Java had become the primary language for Cocoa, the path to Cocoa Touch and an iPhone App Store could have been much more complicated.
When most of them rushed to adopt Objective-C, there was no reason to keep two stacks around, specially when they were still in the red, bleeding money.
I tried to and have _very much_ the opposite opinion about the ease of use.
Darwin/PowerPC :(
> if all you did was manage pools you'd leak memory
I‘m not sure what you mean there.
"... you could even use the generated API with Lua, Python, Ruby or JavaScript"
Guess what, all these have Objective-C bridges, usually multiple ones, because the combination of being just a thin shim on top of C as well as that thin shim being essentially a Smalltalk with full dynamic messaging and runtime introspection + intercession means interop is Objective-C's bread and butter.
No C code generation required.
This should be no surprise because that was exactly the stated goal of Objective-C, and they achieved it admirably. If you think Objective-C is a closed, vendor-specific language like Swift, you truly don't understand it. At all.
Someone once described Objective-C as "COM with language support" and that's pretty accurate.
Exactly.
In fact sometimes in lieu of shell scripts I write simple utility JavaScript files using Objective-C APIs and run them under osascript.
For Python, the easiest way to copy a file while not using twice the disk space (using reflinks) is still using the Objective-C API: https://github.com/RhetTbull/osxphotos/blob/20ef78bbd45a6787...
Edit: oh I see what you are talking about. The osascript aspect was what I wasn’t getting.
I couldn't write it as a shell script because I wanted to get the "date added" rather than the "date modified" or "date created" but this is available in Cocoa APIs.
That is what VB6, Delphi, C++ Builder and .NET Native do (yes not that much relevant nowadays).
If anything I would describe that Objective-C is a better COM, which isn't quite the same.
Bit of a shame that this idea isn't extended to all system frameworks and not just C++ but also C bindings (official C bindings would make life a lot easier for all other programming languages).
I also dabbled a bit with this idea by parsing clang AST-dumps of macOS system headers and generate C binding functions:
https://github.com/floooh/objc-ast-experiments
Unfortunately this is very brittle, and then also broke on ARM CPUs, I guess the shim code needs some ABI adjustments (famously, objc_msgSend has multiple "ABI shapes": https://www.mikeash.com/pyblog/objc_msgsends-new-prototype.h...).
"CppNow 2023:Introducing a Memory-Safe Successor Language in Large C++ Code Bases"
Or maybe not exactly a "bug" but at least an unfortunate tradeoff because your org lacks in-house expertise on one or more of the target platforms.
The case of a single person using many apps on a single mobile platform is just so much more common than the case of a single person using your app on multiple mobile platforms that it makes far more sense to hew to the platform idioms at the cost of cross-platform consistency.
An obvious exception might be something like Slack, where it's common to use both the mobile app and the web app (either directly or via an Electron-like wrapper), but calling Slack "mobile first" is also a stretch.
A quick couple of examples: multi-selection and drag-n-drop, both all but broken on desktop.
That would solve many of their issues, including missing argument names, type information for arguments and return values and access to iOS frameworks on Mac.
I'm not sure how difficult that would be to accomplish, though, considering how macro-heavy C often is.
> https://gamepipeline.org/betray.html
Interesting, I've been using a similar project for Nim lately: https://github.com/treeform/windy
It's surprising how simple Obj-C interaction is compared to Java JNI or something. Here's the Obj-C interop for Windy:
- macdefs: https://github.com/treeform/windy/blob/master/src/windy/plat... - macro shims for Obj-C messages: https://github.com/treeform/windy/blob/master/src/windy/plat...
How would this binding work in such cases, if at all?
(It's not a big blocker to still be tied to Objective-C IMO; I'm mostly just responding to the "might be the only swift-only API apple is actively working on" line.)
> Swift code that can be called from objc, right? Could you write a wrapper/shim in Swift for "object c"
you could, but there are some things that are harder to represent such as structs and complex enums (since everything "objective" in obj-c is a reference), or even async/await based api's (perhaps with lots of black-based wrappers?)The maintainers will still need to know ObjC to understand the Cocoa calls, and this presumably removes a lot of the ObjC niceties in the process.
And now you have an extra layer to maintain, as well as resource allocations to maintain, that ARC would take care for you. Is all the overhead worth it, over just learning to put a few square brackets around the place?
The blog does mention stuff like bindings to other languages, but since ObjC is just C, that's no easier or harder really than before.
On the contrary!
.NET has been cross-platform for years now and runs fine in Linux, Windows and macOS.
Visual Studio for Mac was a legacy piece of software and was promptly replaced by either Jetbrains Rider or VSCode + Microsoft's C# Dev Kit.
If anything, this transition will foster C# in macOS since newbie devs wont stumble upon by accident on the horrible experience that the legacy IDE had to offer.
But if all you want to do is not use Obj-C then Swift us the 100% supported official path.
No need to hack your own wrapper.
It's not exactly what I would call "hostile", language-wise. Swift, on the other hand, might be a bigger barrier...
Android Framework on the other hand is not great in this department. Practically speaking it’s just Java and Kotlin. I wish I could write Swift there because even if Kotlin is similar syntactically the JVM baggage can be irritating.
There's about a billion things about developing on Android that are absolutely miserable. HLL-induced perf bottlenecks aren't usually one of them.
I don’t really understand why the Android team haven’t made it easy to call any Java API from C, with auto-generated bindings or some such.
I think they just don’t believe in apps using native code, beyond the special case of games (note that pretty much all the native APIs are to do with low-level graphics and sound).
"The Android NDK is a toolset that lets you implement parts of your app in native code, using languages such as C and C++. For certain types of apps, this can help you reuse code libraries written in those languages."
-- https://developer.android.com/ndk
"The NDK may not be appropriate for most novice Android programmers who need to use only Java code and framework APIs to develop their apps. However, the NDK can be useful for cases in which you need to do one or more of the following:
- Squeeze extra performance out of a device to achieve low latency or run computationally intensive applications, such as games or physics simulations.
- Reuse your own or other developers' C or C++ libraries.
"-- https://developer.android.com/ndk/guides
There is also the security aspect, why they discourage the use of those languages for full blown applications.
There is also the security aspect, why they discourage the use of those languages for full blown applications.
Native code in apps doesn’t seem like a security problem on iOS, though?
Spend some time reading iOS security updates from Apple, lots of nice CVEs fixes reported there.
Try to write an iOS application using only C and C++, instead of either Objective-C or Swift.
"Swift was designed from the outset to be safer than C-based languages, and eliminates entire classes of unsafe code"
-- https://www.swift.org/about/#features
"Swift is a successor to the C, C++, and Objective-C languages. It includes low-level primitives such as types, flow control, and operators. It also provides object-oriented features such as classes, protocols, and generics, giving Cocoa and Cocoa Touch developers the performance and power they demand."
-- https://developer.apple.com/swift/#fast
Some of the information related their Safe C dialect,
https://discourse.llvm.org/t/rfc-enforcing-bounds-safety-in-...
"2023 EuroLLVM - Keynote: “-fbounds-safety”: Enforcing bounds safety for production C code"
https://www.youtube.com/watch?v=RK9bfrsMdAM
Finaly a recent gem from CppNow 2023,
"Introducing a Memory-Safe Successor Language in Large C++ Code Bases"
Also considering the number of iOS devices, those two languages are probably more usable in practice than for example C#, even if the latter is cross-platform.
Platform vendors seek to lock in developers and discourage development on competing platforms, while developers wish to leverage their skills portably across multiple platforms.
They could capture alot more developers this way, as learning 1 language for both mobile platforms would facilitate more iOS only apps (there are many still even today) to get ported to Android.
This may finally make Android tablets viable, as the app ecosystem for tablets isn't as good as iPadOS
Also Kotlin and Android Studio are mostly developed by JetBrains that is in bed with Google for Android tooling, if anything I expect more Google acquiring JetBrains than supporting Swift on Android.
Since Android 5, with ART introduction, that Android uses a mix of AOT/JIT code.
Java was invented for low end IoT, there isn't anything more low powered than anything in the last 20 years of mobile computing.
Apple and Google should be cherished by not keeping the old C and C++ song of POSIX tunes going.
As Rob Pike puts it, it is like only listening to David Cassidy records.
Just some examples of bindings:
Python https://pypi.org/project/pyobjc/ Rust https://docs.rs/objc/latest/objc/ C# https://learn.microsoft.com/en-us/xamarin/ios/get-started/ob... Javascript https://www.npmjs.com/package/objc
As long as they tie into bringing Apple money- it’s fair game