You found out that React is more than a Framework and you now can use your React skills to do stuff like VR and mobile development. So did your first mobile project, or even your first few projects with React-Native and got around rather well with your JavaScript knowledge. Most of the time you install JS modules via npm and sometimes native ones too, which link easily with react-native link
.
But now somebody wants you to integrate, for example, the Facebook SDK and suddenly you find yourself reading installation guides, that force you to look into this ios
directory, full of foreign mysteries.
You have to change some code in the Info.plist
and AppDelegate.m
, damn.
Well one of these files doesn't look too intimidating. The Info.plist
seems to be the regular XML disaster you'd expect from corporate devs, you can work with that.
But the AppDelegate.m
is another story. You've seen some C in your time, so the #includes
and comments make kinda sense, but the rest? I don't even!
But fear not, for I shall tell you about this ancient tongue!
What
Objective-C is the love child of C and SmallTalk. Like C++ it tries to enhance C with object oriented programming features. So, as you may already thought, the Objective doesn't mean it has less undefined behaviour, but OOP tricks in its sleeve.
It is more like SmallTalk than C++, it incorporates the concept of messages instead of method calls. One of their interesting properties seems to be, that they're dynamically typed, which should give the developer more flexibility.
Also it has strange syntax, which is basically a mix of C and OOP add ons.
So going through the AppDelegate.m
things are starting simple.
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
Well, that's a comment, izi pizi.
#import "AppDelegate.h"
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
And here are some includes, a bit harder.
These are called directives, which are passed to the C pre-processor. As far as I know they aren't really part of the C language, but of the pre-processor language. Well, what you need to know is, that they're used to include native code into your project before compilation. So when you create a native component, it will call native code sometime and this code has to live in some file your app need to know about.
@implementation AppDelegate
...
@end
What? Now we going to the interesting part!
Here is one of these OOP additions that Objective-C brings to C.
In some OOP languages definition and implementation is split up between files and Objective-C is such a language.
You may have noticed the #import "AppDelegate.h"
before, which stitches together this split up.
In the .h
files you define your interfaces, in the .m
file you implement these interfaces by importing the .h
file and using @implementation
with the name of the interface, in our case AppDelegate
, to implement and finish the implementation with @end
.
I got little C/C++ skills, but as far as I know this split is just a convention so you could write it all in one file, but I won't go any deeper into the .h
here, because I didn't have to look into it on React-Native adventures.
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
}
So what is going on here now?
As you may guessed, it's a method.
Like I said, Objective-C is quite different from C++ especially when it comes to syntax.
The -
in the beginning tells that the method is an instance method, a +
would make it to a static (or class) method.
Maybe a JS example helps here.
class MyClass {
instanceMethod() {};
}
MyClass.staticMethod = function() {};
const instance = new MyClass();
instance.instanceMethod();
MyClass.staticMethod();
Then there is the whole (BOOL)
(UIApplication *)
stuff. I first thought this was the way of Objective-C to set types, but I was wrong, these are simply oldschool C type casts.
Objective-C's OOP is dynamically typed, but since it's still C at the core, the compiler needs to know what to do with all the data, so you have to tell it at runtime what's going on.
Without these casts the method would look like that:
- application:application didFinishLaunchingWithOptions:launchOptions
{
...
}
What does it mean?
- methodName:param1 labelForParam2:param2
{
}
The method name is the implicit label for param1 and every other param should have its own label. While these labels are optional, they're recommended, because they're used at call site. SmallTalk did it like that, so why change?
What brings us to calling a method sending a message in Objective-C.
[object methodName:valueForParam1 labelForParam2:valueForParam2];
In JS it would look like that:
object.methodName(valueForParam1, valueForParam2);
The reason for the labels seem to be a better readability on the call site.
[array addObject:myObj at:myIndex];
Instead of
array.addObject(myObject, myIndex);
Anyway, the next line is a variable declaration, basic C with type in front, and the one after, we can read now too (almost):
NSURL *jsCodeLocation;
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
[RCTBundleURLProvider sharedSettings]
is a message without parameters, it's result will be used as the receiving object for the following message.
In Js it would look like that:
let jsCodeLocation;
jsCodeLocation = RCTBundleURLProvider.sharedSettings().jsBundleURLForBundleRoot("index.ios", null)
Yes, there is nil
instead of null
. Seems to stand for Not In List? Also, your string-literals have to be prefixed with @
.
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"myapp"
initialProperties:nil
launchOptions:launchOptions];
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
Also, not much new happening here. The rootView
object gets created with some configuration and then its attribute for background color is set.
What may be interesting here is, that even tho the parameters of messages are labelled, you can't change their positions, as you can see with the initialProperties:nil
, where the parameter stays at its position and gets explicitly set to no value.
Most of the next lines are now self explaining, but talking about self
, these lines probably need some explanation, haha.
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
...
[self.window makeKeyAndVisible];
self
is the this
of Objective-C, so in this case the AppDelegate
object.
Oh, I almost forgot, the new
!
UIViewController *rootViewController = [UIViewController new];
instead of
let rootViewController = new UIViewController();
So it's just like calling a static method on UIViewController
to get a new instance. The literal (but kinda wrong) translation to JS would be
let rootViewController = UIViewController.new();
So to wrap it all up, the whole AppDelegate.m
could look like this in JavaScript:
import "React/RCTBundleURLProvider.h";
import "React/RCTRootView.h";
class AppDelegate extends UIResponder {
application(application, launchOptions) {
let jsCodeLocation;
jsCodeLocation = RCTBundleURLProvider.sharedSettings().jsBundleURLForBundleRoot("index.ios", null);
let rootView = RCTRootView.alloc().(jsCodeLocation, "myblossomapp", null, launchOptions);
rootView.backgroundColor = UIColor.alloc().initWith(1.0, 1.0, 1.0, 1];
this.window = RCTRootView.alloc().initWithFrame(UIScreen.mainScreen().bounds);
let rootViewController = new UIViewController();
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
self.window.makeKeyAndVisible();
return true;
}
}
This is a translation as literal as it gets and semantically totally wrong at a few places, but I think it could help a few people to wrap their mind around it.
Conclusion
Well, seems like Objective-C is a beast of a language, but nothing you couldn't tame!
Here I really just touched the basics of the whole thing. Most of the time you run react-native link
and be done with it and sometimes you have to copy-n-paste code to the AppDelegate.m
. For this you don't need in-depth knowledge of Objective-C, but it helps to know some syntax, Sometimes you miss a character and get crazy errors and don't know whats happening.
Also I think it makes you more confident about your software, if files you look into often aren't a syntactical mystery.