Thursday, September 7, 2017

[iOS] - Method Swizzling

Method swizzling is the process of changing the implementation of an existing selector. It’s a technique made possible by the fact that method invocations in Objective-C can be changed at runtime, by changing how selectors are mapped to underlying functions in a class’s dispatch table.
For example, let’s say we wanted to track how many times each view controller is presented to a user in an iOS app:
Each view controller could add tracking code to its own implementation of viewDidAppear:, but that would make for a ton of duplicated boilerplate code. Subclassing would be another possibility, but it would require subclassing UIViewControllerUITableViewControllerUINavigationController, and every other view controller class—an approach that would also suffer from code duplication.
Fortunately, there is another way: method swizzling from a category. Here’s how to do it:
#import <objc/runtime.h>

@implementation UIViewController (Tracking)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class class = [self class];

        SEL originalSelector = @selector(viewWillAppear:);
        SEL swizzledSelector = @selector(xxx_viewWillAppear:);

        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

        // When swizzling a class method, use the following:
        // Class class = object_getClass((id)self);
        // ...
        // Method originalMethod = class_getClassMethod(class, originalSelector);
        // Method swizzledMethod = class_getClassMethod(class, swizzledSelector);

        BOOL didAddMethod =
            class_addMethod(class,
                originalSelector,
                method_getImplementation(swizzledMethod),
                method_getTypeEncoding(swizzledMethod));

        if (didAddMethod) {
            class_replaceMethod(class,
                swizzledSelector,
                method_getImplementation(originalMethod),
                method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    });
}

#pragma mark - Method Swizzling

- (void)xxx_viewWillAppear:(BOOL)animated {
    [self xxx_viewWillAppear:animated];
    NSLog(@"viewWillAppear: %@", self);
}

@end
In computer science, pointer swizzling is the conversion of references based on name or position to direct pointer references. While the origins of Objective-C’s usage of the term are not entirely known, it’s understandable why it was co-opted, since method swizzling involves changing the reference of a function pointer by its selector.
Now, when any instance of UIViewController, or one of its subclasses invokes viewWillAppear:, a log statement will print out.
Injecting behavior into the view controller lifecycle, responder events, view drawing, or the Foundation networking stack are all good examples of how method swizzling can be used to great effect. There are a number of other occasions when swizzling would be an appropriate technique, and they become increasingly apparent the more seasoned an Objective-C developer becomes.
Regardless of why or where one chooses to use swizzling, the how remains absolute:

+load vs. +initialize

Swizzling should always be done in +load.
There are two methods that are automatically invoked by the Objective-C runtime for each class. +load is sent when the class is initially loaded, while +initialize is called just before the application calls its first method on that class or an instance of that class. Both are optional, and are executed only if the method is implemented.
Because method swizzling affects global state, it is important to minimize the possibility of race conditions. +load is guaranteed to be loaded during class initialization, which provides a modicum of consistency for changing system-wide behavior. By contrast, +initialize provides no such guarantee of when it will be executed—in fact, it may never be called, if that class is never messaged directly by the app.

dispatch_once

Swizzling should always be done in a dispatch_once.
Again, because swizzling changes global state, we need to take every precaution available to us in the runtime. Atomicity is one such precaution, as is a guarantee that code will be executed exactly once, even across different threads. Grand Central Dispatch’s dispatch_once provides both of these desirable behaviors, and should be considered as much a standard practice for swizzling as they are for initializing singletons.

Selectors, Methods, & Implementations

In Objective-C, selectorsmethods, and implementations refer to particular aspects of the runtime, although in normal conversation, these terms are often used interchangeably to generally refer to the process of message sending.
Here is how each is described in Apple’s Objective-C Runtime Reference:
  • Selector (typedef struct objc_selector *SEL): Selectors are used to represent the name of a method at runtime. A method selector is a C string that has been registered (or “mapped”) with the Objective-C runtime. Selectors generated by the compiler are automatically mapped by the runtime when the class is loaded .
  • Method (typedef struct objc_method *Method): An opaque type that represents a method in a class definition.
  • Implementation (typedef id (*IMP)(id, SEL, ...)): This data type is a pointer to the start of the function that implements the method. This function uses standard C calling conventions as implemented for the current CPU architecture. The first argument is a pointer to self (that is, the memory for the particular instance of this class, or, for a class method, a pointer to the metaclass). The second argument is the method selector. The method arguments follow.
The best way to understand the relationship between these concepts is as follows: a class (Class) maintains a dispatch table to resolve messages sent at runtime; each entry in the table is a method (Method), which keys a particular name, the selector (SEL), to an implementation (IMP), which is a pointer to an underlying C function.
To swizzle a method is to change a class’s dispatch table in order to resolve messages from an existing selector to a different implementation, while aliasing the original method implementation to a new selector.

Invoking _cmd

It may appear that the following code will result in an infinite loop:
- (void)xxx_viewWillAppear:(BOOL)animated {
    [self xxx_viewWillAppear:animated];
    NSLog(@"viewWillAppear: %@", NSStringFromClass([self class]));
}
Surprisingly, it won’t. In the process of swizzling, xxx_viewWillAppear: has been reassigned to the original implementation of UIViewController -viewWillAppear:. It’s good programmer instinct for calling a method on self in its own implementation to raise a red flag, but in this case, it makes sense if we remember what’s really going on. However, if we were to call viewWillAppear: in this method, it would cause an infinite loop, since the implementation of this method will be swizzled to the viewWillAppear: selector at runtime.

Thursday, July 27, 2017

[iOS] - Static Libraries, Frameworks, and Bitcode

A couple weeks ago, I had to add Bitcode support for an Objective-C library I was working on. My first thought was something along the lines of:
I just have to change `Enable Bitcode` to YES on my Project Settings, awesome!
Wrong.

Ways to use libraries

Libraries on Objective-C/Swift can generally be used in 3 different ways:
  1. Binary
  2. CocoaPods
  3. Frameworks / Carthage
In my case, the library could be used via CocoaPods or a Universal Binary. The universal binary was being built by an Aggregate target, which had a custom Run Script to build a "fat" (simulator+device) version of it. To my surprise, Bitcode was already enabled in the project "Build Settings", but a user was getting errors when using the binary. So, what was going on?

Extra Bitcode settings

Well, turns out one setting wasn't enough. Xcode will only build a project with Bitcode support if you Archive it, which is not usually the case when you're working with libraries. To get around that, you can use either one of two settings on your project (whichever one you prefer):
  • On Build Settings -> Other C flags, set Debug to -fembed-bitcode-marker, and Release to -fembed-bitcode. Make sure that is set for your project, and not the targets. (thanks @naishta for pointing that out!)
  • On Build Settings, click on the + sign at the top to add a user-defined build setting with the name BITCODE_GENERATION_MODE, and set Debug to marker, Release to bitcode
If you're using xcodebuild or xctool to build your project, you can use it like this:
# Debug
xcodebuild … OTHER_CFLAGS=”-fembed-bitcode-marker” …
# Release
xcodebuild … OTHER_CFLAGS=”-fembed-bitcode” …
The marker or -fembed-bitcode-marker option for Bitcode is only useful for testing. You can have an app with Bitcode Enabled, using a binary from a library that was built with the -fembed-bitcode-marker setting, for example, and it'll work fine while you're testing. But if you try to Archive your app, you'll get an error such as this:
ld: bitcode bundle could not be generated because ‘{project dir}/path/to/SomeLib.a’ was built without full bitcode. All object files and libraries for bitcode must be generated from Xcode Archive or Install build for architecture arm64
To fix that, make sure that you're building your library's binary with the option -fembed-bitcode before importing it into an app.
P.S: To test if you're correctly building with full bitcode support, or to check other libraries you might be using, use the `otool` command in your terminal.
Okay, that takes care of the Universal Binary. 🎉

What about CocoaPods and Carthage/Frameworks?

Well, if you're using CocoaPods you might have been lucky and not have
seen any errors regarding Bitcode. Pods will be added to your workspace with Bitcode Enabled set to YES, and hopefully, you'll be good to go without lifting a finger.
Now, our last option, Carthage/Frameworks. The same settings I mentioned above will allow you to build a framework with full Bitcode support (staticor dynamic). But, if you have a setup that creates a "fat" (simulator+device) framework, which is the more common case, there's a bug with the App Store submission process that will throw an error if your app includes a framework with extra architectures. Carthage has instructions for getting around the bug that can be found here, that basically involves adding a few extra steps to your Build Phases, and adding a script that will strip a framework of those extra architectures.
Hopefully, the information here will help you get a little bit less frustrated and save some time searching on Google/StackOverflow when dealing with Bitcode. :)

Thursday, May 18, 2017

[iOS] Static libraries vs Dynamic Libraries

Linking Libraries

The act of linking libraries is a form of code dependency management. When any app is run, its executable code is loaded into memory. Additionally, any code libraries that it depends on are also loaded into memory. There are two type of linking: static, and dynamic. Both offer different benefits to the developer and should be used according to these benefits. This blog post will cover the benefits offered by each and then explain the basics of how to create and link your own libraries on OS X and iOS.

Dynamic Linking

Dynamic linking is most commonly used on OS X and iOS. When dynamic libraries are linked, none of the library's code is included directly into the linked target. Instead, the libraries are loaded into memory at runtime prior to having symbols getting resolved. Because the code isn't statically linked into the executable binary, there are some benefits from loading at runtime. Mainly, the libraries can be updated with new features or bug-fixes without having to recompile and relink executable. In addition, being loaded at runtime means that individual code libraries can have their own initializers and clean up after their own tasks before being unloaded from memory. For more information on overview and design, see Apple's Dynamic Library Programming Topics.

• Libraries

Dynamic libraries are a type of Mach-O binary1 that is loaded at launch or runtime of an application. Since the executable code in a dynamic library isn't statically linked into target executable, this affords some benefits when needing to reuse the same code. For example, if you have an application and a daemon or extension that needs to make use of the same code, that code only has to exist in a single location -- the dynamic library, rather than in both the executable's binary and the daemon's binary. Since dynamic libraries are loaded at runtime, the library is responsible for telling the linker what additional code is needed. This removes the burden of managing what all of the code that you use needs to operate.

• How to verify it's static or dynamic

To use the following command line:
$ otool -L xx.a
Dynamic result:
@rpath/PWCore.framework/PWCore (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 307.4.0)
/usr/lib/libicucore.A.dylib (compatibility version 1.0.0, current version 57.1.0)
/usr/lib/libsqlite3.dylib (compatibility version 9.0.0, current version 253.0.0)
/usr/lib/libxml2.2.dylib (compatibility version 10.0.0, current version 10.9.0)
/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.8)
/System/Library/Frameworks/CFNetwork.framework/CFNetwork (compatibility version 1.0.0, current version 808.2.16)
Static result: 
Archive : XXCore
XXCore(XXAFURLRequestSerialization.o):
XXCore(XXAFHTTPSessionManager.o):
XXCore(XXCore.o):
XXCore(XXBundleManager.o):
XXCore(XXBluetoothHelper.o):
XXCore(XXErrors.o):

• Useful commands

Identify library files:
$ lipo -info libfat.a 
Build a new dynamic library:
$ libtool -dynamic *.o -o libfoo_dynamic-x86_64.dylib -framework CoreFoundation -lSystem

Wednesday, January 4, 2017

[iOS] Per-Domain Exceptions

To configure a per-domain exception so that your app can connect to a non-secure (or non TLSv1.2-enabled secure host), add these keys to your Info.plist (and note that Xcode doesn’t currently auto-complete these keys as of the first Xcode 7 beta seed):
<key>NSAppTransportSecurity</key>
<dict>
  <key>NSExceptionDomains</key>
  <dict>
    <key>yourserver.com</key>
    <dict>
      <!--Include to allow subdomains-->
      <key>NSIncludesSubdomains</key>
      <true/>
      <!--Include to allow HTTP requests-->
      <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
      <true/>
      <!--Include to specify minimum TLS version-->
      <key>NSTemporaryExceptionMinimumTLSVersion</key>
      <string>TLSv1.1</string>
    </dict>
  </dict>
</dict>
There are other keys that you can use to configure App Transport Security as well, such as:
NSRequiresCertificateTransparency
NSTemporaryExceptionRequiresForwardSecrecy
NSTemporaryThirdPartyExceptionAllowsInsecureHTTPLoads
NSTemporaryThirdPartyExceptionMinimumTLSVersion
NSTemporaryThirdPartyExceptionRequiresForwardSecrecy