If you’re just getting into Mac development now, you should start by learning Swift. Learning only Objective-C right now would be a short-sighted idea, because all new code that comes out of Apple is in Swift, as is all sample code at Apple’s conferences etc., and it will only become more.

While knowing either Objective-C or Swift is strictly said enough, Apple are focusing all their efforts on Swift, and you will have an easier time learning going forward if you learn Swift.

That said, I recommend at least learning to read Objective-C code, and learning how to translate it to the equivalent Swift code. Objective-C was there first, and a lot of Swift on the Mac still uses Objective-C code under the hood (they didn’t just rewrite the operating system in Swift, after all), and you may encounter weird error messages that mention Objective-C class names or method names that are more easily understood if you have a basic familiarity how Swift and Objective-C interact. Also, a lot of useful older sample code is in Objective-C.

But I need to interface with C++!

While in the past I have recommended using the Objective-C/C++ hybrid language Objective-C++ to integrate C++ with Mac API, more recent experiences and changes in Swift 5 and 5.1 lead me to rescind that recommendation. Wrap your C++ code in C functions, then call those from Swift. I was surprised that a lot of the compatibility mechanisms for calling Objective-C from Swift can lead to quite significant performance reductions.

So if you need performance, take advantage of the fact that Swift can call C functions directly, without use of a slow foreign-function-call interface like many other languages.

But when you do that, the first thing I would recommend is to wrap your C API in a thin Swift struct or class. While Swift knows to import typedefs to pointers whose content Swift does not understand (like C++ instances) as an opaque type in Swift, it is easy to forget to do proper manual memory management on them. So wrapping them in Swift and having init() and deinit take care of memory management will be a lot safer.

Also, if your types are imported just as a generic, untyped OpaquePointer, make sure your typedef is to the pointer type, not just the type itself.