Objective C (iOS) for Qt C++ Developers
For our first customer iOS application, I had to learn Objective C.
Coming from the Qt world
that was not too hard. To make life even easier for the readers of this blog, I am going
to describe some of the things I have learnt. This is more of a brain dump than a tutorial, but I still hope it is useful for you.
I'll first write about the language differences and then about the class libraries.
Objective C vs C vs C++
Similarly to C++, Objective C is a superset of C (that is not 100% correct but a good enough statement to understand it)
The file extensions you are using for the header is .h and .m for the implementation.
Note that there is also Objective-C++ with the file extension .mm, I will not write about that though.
Similar to Symbian C++, Objective C is using two phase construction: First you alloc the object on the heap, then you call one of the init methods on it. Often you can avoid having to call two methods and just use one of the static convenenience methods that directly give you back a newly allocated object (e.g. stringWithCString).
Quite different (and at first very distracting) is the method calling syntax in Objective C. There are normal C functions that you call in the usual C-ish way, e.g. NSLog(@"My log message");. But there is also the Objective C syntax for methods of objects. As an example, this is for a method on obj with two parameters: [obj methodName:param1value param2:param2Value]. Looks odd, but you'll get used to it. In Objective C, this is usually called sending a message, although I find that more confusing than just calling it methods.
In this method example above, methodName is the so called selector. A selector is the identifier of a method. Sometimes you will have to identify the method (similar to a function pointer), in the example above you could do that with @selector(methodName:param2:).
While in C++ there is no root object and in Qt QObject is only used for some objects, Objective C has the mandatory root object NSObject. Contrary to Qt where you use QObject only for classes where you want signals/slots, here you use NSObject for everything.
ARC is the automatic reference counting implemented since iOS 5. Think of it like having an implicit QSharedPointer around your objects. It makes coding feel like you have a garbage collector. Internally, ARC tells the compiler to insert retain (increment reference count) and release (decrement reference count and eventually dealloc) statements in your code. I think this is awesome, you basically can't leak objects anymore if you stick to the normal way of doing things.
Properties in Objective C are similar to Q_PROPERTY. It means that you can use the nice obj.var = foo syntax in your code while internally a [obj setVar:foo] message is called (well.. message is sent). You can create a property with @property and have the compiler make a getter/setter for you using @synthesize. You can of course also have your custom getter/setter that has more logic inside, for example for implementing lazy initialization.
You can think of Objective C delegates as a set of slots. A delegate method in the delegate object is called by an object to notify that something has happened. This is very similar to Java's interfaces.
Equivalencies to the Qt classes
As important as the syntax is the associated libraries provided by iOS (and OS X). Read on to learn about the objects and functions provided by them.
An NSString object is a constant string. You can also create it by @"having it in 'at' followed by quotation marks". To have a mutable string, you have to use NSMutableString with its appendString, appendFormat etc functions. Especially appendFormat is really useful. If you want to do replacing, stringByReplacingOccurrencesOfString is your friend and gives you back a new NSString object. For constructing a path on the file system, you can use stringByAppendingPathComponent.
Like in C++, basic types like int are not objects. If you need to wrap them inside an object, you can use NSNumber and NSValue (similar to QVariant). Also useful to know here: You can use the intValue methods of NSNumber, NSString etc to convert to an int.
NSArray, NSSet, NSDictionary are what they sound like: A place to store NSObjects. NSArray is equivalent to a QList, NSSet to QSet and NSDictionary is a QHash/QMap. You need to use their mutable variants to change them (e.g. NSMutableArray). If you want to store primitive types, you need to use NSNumber, NSValue etc to wrap them. For NSArray, you can access the objects by using objectAtIndex. For a NSDictionary, you'd use valueForKey or objectForKey.
I haven't done much file IO, so I cannot write much about this here. There is NSFileManager for directory operations. You can very easily read a (smaller) file by using NSString's stringWithContentsOfFile or NSData's dataWithContentsOfFile. Remember that on OS X and iOS, one of your system levels below is POSIX, so you can also use the methods from there to get raw performance.
Speaking of NSData: It's your equivalent to QByteArray :-) For a mutable variant, have a look at NSMutableData. You can access the char* pointer via the data or mutableData methods.
I feel that most mobile applications nowadays are somehow using HTTP. In Qt you would use the QNetworkAccessManager for that. In Objective C, you use a NSMutableURLRequest(or NSURLRequest) inside a NSURLConnection. You need to set a delegate for the NSURLConnection. The delegate handles the asynchonous events that get produced when downloading (readyRead signal is connection:didReceiveData:, finished signal is connectionDidFinishLoading: etc).
If you want to do socket-based IO, I can only recommend to get GCDAsyncSocket . I've tried manual socket programming for iQuassel before and it sucked for several reasons, mainly since you have to use Carbon instead of Cocoa. GCDAsyncSocket also has the nice advantage that you can easily do your network protocol parsing in a thread and you avoid blocking the UI.
Speaking of threading: You can achieve basic concurrency by using NSObject's performSelectorInBackground. It makes a method run in a background thread. It can then communicate back its result to the main thread via performSelectorOnMainThread. If you want to do a Qt-tish 0 timer invocation, check the afterDelay: variant of performSelector, this has the selector run in an event loop invocation. More advanced things can be done with NSOperationQueue or Grand Central Dispatch.
The equivalent to a QEventLoop is a NSRunLoop. You can use that if you are processing something in another thread and need an event loop, for example for network IO.
NSUserDefaults is a nice way to store and load application settings (like you would do with QSettings).
Unfortunately there is no real equivalent to QtXmlPatterns. The libxml2 exists on the iOS devices, so you could use use that. For simple SAX-style parsing, at least there is NSXMLParser.
XCode has a (quite buggy) visual designer (interface builder) included. With the designer you design a storyboard (UIStoryboard) that contains a number of view controllers (UIViewController subclasses). Each view controller manages a view (remember MVC?). The navigation between the views happens via segues (UIStoryboardSegue). You can move data between view controllers inside the prepareForSegue method of the source view controller. Each view controller has methods like viewWillAppear that get called by the OS when a specific event happens.
You use "outlets" to link instances of controls (e.g. a UIButton, UILabel) with their counterpart in the interface builder UI file. Use drag and drop with CTRL.
For Qt's itemviews, I cannot say much about the equivalents in the Apple world. Definitely have a look at UITableView which will use your UITableViewDataSource and UITableViewDelegate for its contents. I'd say almost all iOS applications use a table view.
If you have been using a QWebView, you can substitute it with UIWebView.
The equivalents for QImage and QPixmap are CGDataProviderRef, NSImage and CGImage.
You can do custom drawing using the core graphics methods. UIGraphicsBeginImageContextWithOptions creates a context on which you can use drawing functions. If you want to get a bitmap out of the context, try UIGraphicsGetImageFromCurrentImageContext.
QRect, QPoint etc have their equivalents in CGRect, CGPoint and CGSize. To help you debugging, check NSStringFromCGRect and friends.
For the widgets, note that NS* UI classes are for OS X and UI* classes are for iOS.
When developing Qt, I'm using QtCreator. My Co-Founder Olivier is a KDevelop fan, which is also supposed to be very good. For iOS development, you can use Apple's free XCode.
The Apple engineers also provide you with some possibilities to do unit testing similar to QTest. In XCode, create a new test class and use methods like STAssertEquals, STAssertTrue etc.
Want to know more?
I guess the equivalent of the Qt Developer Network is StackOverflow. Most things that have ever been attempted in iOS programming have something on StackOverflow. There is also an internal Apple developer forum available.
Woboq is a software company that specializes in development and consulting around Qt and C++. Hire us!
Article posted by Markus Goetz on 20 August 2013
Click to subscribe via RSS or e-mail on Google Feedburner. (external service).