The blog of Sash Zats2022-12-20T21:09:05+00:00http://blog.zats.ioSash Zatshey@zats.ioLet's build Amphetamine2018-06-10T00:00:00+00:00http://blog.zats.io/2018/06/10/lets-build-amphetamine<h1 id="intro">Intro</h1>
<p>This is a first of what I hope will become a series of blog posts inspired by Mike Ash’s <a href="https://www.mikeash.com/pyblog/?tag=letsbuild">let’s build series</a>. I vividly remember that at first, not having a computer science degree, I strongly believed that NSArray is magical and folks over at Apple figured a way to bend <em>O(n)</em> when it comes to iterating over the elements and such. And while Foundation definitely packs more smarts when it comes to dealing with comon cases, it’s series like Mike Ash’s (and learning basics of computer science) helped me to see how anyone can build those.</p>
<p>In my series, instead of analyzing data structures and lower level functions I wanted to take a look at the apps that I find useful in my daily workflow. I want to learn how f.lux changes the screen colour, what keeps my computer awake with Caffeine or Amphetamine, how does AppZapper or AppCleaner knows which files to remove when I delete the app etc.</p>
<p>This series intended both as a reverse-engineering look at the internals and imagining how to architect given app. Hope you will enjoy it!</p>
<h1 id="lets-build-amphetamine">Let’s build Amphetamine</h1>
<p>Sometimes you just want your computer not to sleep its screen to finish a long-running task, making sure it’s not interrupted. There’re several apps that do that: <a href="http://lightheadsw.com/caffeine/">Caffeine</a> and <a href="https://itunes.apple.com/us/app/amphetamine/id937984704?mt=12">Amphetamine</a>. Both are free, Caffeine is very simple and straight forward, while Amphetamine provides greater level of sophistication: do you want to prevent the entire computer from sleeping, or just keep the hard drives running? Do you want to prevent sleep when you get on a certain WiFi network or when certain app is launched, or maybe you want to allow computer to sleep if the battery level is low.</p>
<p>Let’s take both apart. Just like with any app, there are several ways to go about figuring out how it’s built: we can either google “disable sleep macOS” and make our way through the irrelevant resources or fire Hopper Disassembler and peak into the internals of the apps.</p>
<h1 id="caffeine">Caffeine</h1>
<p><img src="/assets/2018-06-10/caffeine.png" alt="Caffeine preferences window" /></p>
<p>Let’s start with simpler (and a bit older) Caffeine. Few bels and whistles that it offers aside, the essence of the app is very simple.</p>
<ol>
<li>Schedule a timer that fires ridiculously often</li>
<li>Every timer tick check if computer is trying to sleep
<ol>
<li>To do that, get a bag of key values by calling <code class="language-plaintext highlighter-rouge">NSWorkspace.shared.activeApplication()</code></li>
<li>Check that value for key <code class="language-plaintext highlighter-rouge">NSApplicationBundleIdentifier</code> is either <code class="language-plaintext highlighter-rouge">com.apple.loginwindow</code> or <code class="language-plaintext highlighter-rouge">com.apple.ScreenSaver.Engine</code></li>
</ol>
</li>
<li>If it is running, use Carbon-time API <code class="language-plaintext highlighter-rouge">UpdateSystemActivity(OverallAct)</code>. That will prevent computer from sleeping. It’s unclear for how long though.</li>
</ol>
<p>If you feel like Nicolas Cage from National Treasure, here is a <a href="https://developer.apple.com/library/archive/qa/qa1160/">retired documentation</a>. Note that the documentation mentions you can only call this method once every 30 seconds. So either I don’t understand the assembly, or author chose to ignore the warning.</p>
<h1 id="amphetamine">Amphetamine</h1>
<p><img src="/assets/2018-06-10/amphetamine.png" alt="Amphetamine app preferences window" /></p>
<p>Just like the edgier name suggest, this is a more modern piece of software, and, as I mentioned previously, it has more to offer.
</p>
<h2 id="keeping-awake">Keeping awake</h2>
<p>Let’s start with the essence: disabling sleep. Amphetamine uses IOKit which offers variety of tools to interface with hardware and derivers from the comfort of the user-space. The function that we want to call is</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep, kIOPMAssertionLevelOn, "MyApp is running an important task", &assertionID)
</code></pre></div></div>
<p>Several things to note here:</p>
<ul>
<li>String that we passed to the function is used as an explanation to why system is not allowed to sleep. I’m not sure where can I see the current reason as a user</li>
<li>It’s important to hold on to the assertionID that will be populated with an identifier so that you can dispose it later when you want computer to be allowed to sleep again. To do that, call <code class="language-plaintext highlighter-rouge">IOPMAssertionRelease(assertionID)</code></li>
</ul>
<p>Here is the Apple documentation on how to <a href="https://developer.apple.com/library/archive/qa/qa1340/_index.html#//apple_ref/doc/uid/DTS10003321-CH1-SOURCECODE2">prevent display sleep</a></p>
<h2 id="keeping-the-drives-alive">Keeping the drives alive</h2>
<p><img src="/assets/2018-06-10/amphetamine_drive.png" alt="Hard drive settings window" /></p>
<p>This part is actually fairly straight forward, there’s no API macOS offers to keep the hard drives awake, but it’s fairly trivial to do it yourself. As a matter of fact every time you perform any disk IO, the disk must be awake to allow you to read a file. In case of Amphetamine, it holds on to the list of the drives you want to keep awake. Once the timer fires, we perform following</p>
<ul>
<li>Create a <code class="language-plaintext highlighter-rouge">URL</code> for each drive using <code class="language-plaintext highlighter-rouge">URL(resolvingBookmarkData:options:relativeTo:bookmarkDataIsStale:)</code></li>
<li>Using <code class="language-plaintext highlighter-rouge">checkResourceIsReachableAndReturnError</code> to verify if the bookmark became inaccessible since last time we ran the method (this is done so that app can be sandboxed)</li>
<li>Announce that we are starting accessing the scoped bookmark by calling <code class="language-plaintext highlighter-rouge">startAccessingSecurityScopedResource</code></li>
<li>If the bookmark is available, Amphetamine writes an invisible file called <code class="language-plaintext highlighter-rouge">.Amphetamine.DriveAlive</code> with a random number inside of it (just so the file won’t be empty I guess)</li>
<li>Finally let the system know that you won’t longer need the resource by calling <code class="language-plaintext highlighter-rouge">stopAccessingSecurityScopedResource</code></li>
</ul>
<h2 id="battery-level">Battery level</h2>
<p><img src="/assets/2018-06-10/amphetamine_battery.png" alt="Battery level preferences window" /></p>
<p>Amphetamine allows to prevent session if your battery level is getting low. This uses pretty much the same trick of sampling the battery level over certain time interval. Here is a sample of how to get it:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import Foundation
import IOKit.ps
let info = IOPSCopyPowerSourcesInfo().takeRetainedValue()
let sourcesList = IOPSCopyPowerSourcesList(info).takeRetainedValue() as [CFTypeRef]
let power = IOPSGetPowerSourceDescription(info, sourcesList[0])!.takeRetainedValue() as! Dictionary<String, Any>
power[kIOPSCurrentCapacityKey]
</code></pre></div></div>
<p>this will return an integer representing the battery level such as 88 or 12. Once we see that percentage went below certain number, we can pause the session.
Option of ignoring battery level and restarting the session if you are plugged in is equality easy to implement by checking for <code class="language-plaintext highlighter-rouge">power[kIOPSPowerSourceStateKey] == kIOPSACPowerValue</code></p>
<h2 id="triggers">Triggers</h2>
<p><img src="/assets/2018-06-10/amphetamine_triggers.png" alt="Triggers preferences window" />

Amphetamine allows to automate session behavior using WiFi name or certain app being launched.
Current Wifi name (also known as SSID) can be queried via <code class="language-plaintext highlighter-rouge">CWWiFiClient.shared().interface()?.ssid()</code>. To be notified about SSID being changed, you can use following code</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import CoreWLAN
let client = CWWiFiClient.shared()
try! client.startMonitoringEvent(with: .ssidDidChange)
client.delegate = delegate
// in delegate
public func ssidDidChangeForWiFiInterface(withName interfaceName: String) {
if let ssid = CWWiFiClient.shared().interface()?.ssid() {
// check if ssid matches any of the ones user specified
}
}
</code></pre></div></div>
<p>Lastly to detect the apps being launched, there’s a notification we can listen to. The only tricky detail to note is that we don’t use shared notification center, instead we use the one that <code class="language-plaintext highlighter-rouge">NSWorkspace</code> points to:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import AppKit
let center = NSWorkspace.shared.notificationCenter
center.addObserver(forName: NSWorkspace.didLaunchApplicationNotification, object: nil, queue: nil) { notification in
if let app = notification.userInfo?[NSWorkspace.applicationUserInfoKey] as? NSRunningApplication {
print(app.bundleIdentifier)
}
}
</code></pre></div></div>
<p>We already looked at the power as a trigger in the previous section. As far as scheduling events, local notifications might be a good way to go allowing to schedule an invisible to the user notification that will ping your app but more importantly handle all the date math for you. You can refer to the documentation over at <a href="https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/">Local and Remote Notifications</a> or <a href="https://developer.apple.com/documentation/usernotifications">User Notifications</a> (depending which OS versions are you targeting)</p>
<h1 id="architecture">Architecture</h1>
<p>When thinking about architecting this kind of software, I’d take in account that number of triggers might grow in the future (or you might want to provide some of them as payed upgrade). That makes me want to architect it as a system of plugins of 2 types:</p>
<ul>
<li>Where system API allows I would go with pub-sub type of plugins, reporting when certain even occured</li>
<li>Where it’s not possible, due to lack of API, I’d create a scheduler iterating over the enabled plugins, asking each plugin to evaluate itself</li>
</ul>
<p>Once both systems reconcile results, plugin manager passes the judgment whether to enable or disable no sleep mode. Plugin manager here acts as a plugin suite. I would create 1 manager per set of triggers:</p>
<ul>
<li>Keep computer awake if <code class="language-plaintext highlighter-rouge">$ brew update</code> is running, but allow to fall asleep if the battery level is bellow 5%</li>
<li>Keep computer awake if connected to “At work” wifi, allow to sleep if battery is under 10%, but keep awake if the computer plugged to the power, etc..</li>
</ul>
<p>Also having independant plugins will allow to test each one of them. Since we are dealing with a lot of hardware-related and time-dependant data, ideally every plugin should take a data provider that</p>
<ul>
<li>shields the plugin from talking direcly to the hardware or date API</li>
<li>allows to pass a mock data provide instead to allow predictable testing</li>
</ul>
<p>Following is a rough implementation of various parts of the architecture outlined above. Keep in mind that I skipped certain sharp corners around Swift <code class="language-plaintext highlighter-rouge">associatedtype</code> since I didn’t want to pollute example with type erasures. I also use marker protocols extensively, this will allow to pull out common functionality later. Treat following code as more of a UML diagram.</p>
<h2 id="plugins">Plugins</h2>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>protocol PluginProtocol {
}
protocol NotifyingPluginProtocol: PluginProtocol {
var lastResult: PluginEvaluationResult { get }
init(provider: PluginDataProviderProtocol, manager: PluginManagerProtocol)
}
protocol EvaluatedPluginProtocol: PluginProtocol {
func evaluate() -> PluginEvaluationResult
}
</code></pre></div></div>
<p>Here we define 2 types of plugins I mentioned previously, when plugin manager is trying to figure out should we allow system to sleep or not, we don’t want any asynchronyous operations here, that’s why pubsub based plugins should cache their <code class="language-plaintext highlighter-rouge">PluginEvaluationResult</code>.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>enum PluginEvaluationResult {
case allowSleep
case preventSleep
case noOp
}
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">PluginEvaluationResult</code> allows to express 3 situation:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">allowSleep</code> - plugin wants to guarantee system is allowed to sleep</li>
<li><code class="language-plaintext highlighter-rouge">noOp</code> - plugin has no opinion on whether system sleeps or stays awake</li>
<li><code class="language-plaintext highlighter-rouge">preventSleep</code> - plugin wants to keep system awake unless any other plugin wants to allow system to sleep</li>
</ul>
<p>We will take a look at the concrete examples below</p>
<h3 id="plugin-data-providers">Plugin data providers</h3>
<p>As mentioned before, we want to abstract plugins data access to reduce coupling and allow stubbing for tests. Implementation of those is not too important, but here are the examples of pubsub plugin data provider and eagirly evaluated one</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>protocol PluginDataProviderProtocol {
}
protocol BatteryProivderProtocol: PluginDataProviderProtocol {
var batteryLevel: Int { get }
}
protocol AppLaunchProviderProtocol: PluginDataProviderProtocol {
typealias SubscriptionToken = Int
init(appBundleId: String)
func subscribe(_ handler: (AppLaunchEvent) -> Void) -> SubscriptionToken
func unsubscribe(_ token: SubscriptionToken)
}
</code></pre></div></div>
<p>Each concrete plugin should be instantiated with one, they can be shared if needed.</p>
<p>Battery plugin can be implemented like so:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class BatteryPlugin: EvaluatedPluginProtocol {
let dataProvider: BatteryProivderProtocol
init(dataProvider: BatteryProivderProtocol) {
self.dataProvider = dataProvider
}
func evaluate() -> PluginEvaluationResult {
if dataProvider.batteryLevel < 10 {
return .allowSleep
} else {
// when battery level is above 10%, this plugin doesn't care if system sleeps or not
return .noOp
}
}
}
</code></pre></div></div>
<p>Plugin reacting to the app launch:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class AppLaunchPlugin: NotifyingPluginProtocol {
let provider: AppLaunchProviderProtocol
let manager: PluginManagerProtocol
// another workaround to allow to capture weak self in the subscription block down bellow
private var token: AppLaunchProviderProtocol.SubscriptionToken!
private (set) var lastResult: PluginEvaluationResult = .noOp
required init(provider: PluginDataProviderProtocol, manager: PluginManagerProtocol) {
self.provider = provider as! AppLaunchProviderProtocol
self.manager = manager
self.token = self.provider.subscribe { [weak self] event in
guard let `self` = self else {
return
}
switch event {
case .launched:
self.lastResult = .preventSleep
case .terminated:
self.lastResult = .noOp
}
self.manager.requestEvaluation(for: self)
}
}
deinit {
provider.unsubscribe(token)
}
}
</code></pre></div></div>
<p>Fundamental differences between two plugins are:</p>
<ul>
<li>battery is eagierly evaluated upon scheduler firing externally, while app launch plugin reacts to notifications that might fire any moment</li>
<li>battery plugin will either allow system to sleep (preventing evaluation of subsequent plugins) or result in no-op result in allowing system to sleep or no-op, app launch plugin</li>
</ul>
<h2 id="plugin-manager">Plugin manager</h2>
<p>This is the core of the plugin system. It should encapsulate a set of conditions. In restrospect I should’ve named it something like <code class="language-plaintext highlighter-rouge">PluginsSuite</code> since it encapsulates several plugins, meaning there should be another entity keeping track of all the <code class="language-plaintext highlighter-rouge">PluginsSuite</code>s, but hopefully you get the gist.</p>
<ul>
<li>It only focuses on handling plugins
<ul>
<li>It doesn’t handle scheduling logic</li>
<li>It doesn’t handle logic of keeping the system awake</li>
</ul>
</li>
<li><code class="language-plaintext highlighter-rouge">evaluatePlugins</code> is the core function that will make sure to query latest values from all the plugins
<ul>
<li>any plugin allowing system to sleep short-circuits to allow system to sleep immediately</li>
<li>if plugin wants to prevent system from sleeping we continue evaluation to the end and only if no other plugin wants to allow to sleep we will call <code class="language-plaintext highlighter-rouge">preventSleep</code> at the end</li>
</ul>
</li>
</ul>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class PluginManager: PluginManagerProtocol {
var plugins: [PluginProtocol] = []
typealias AllowSleepCallback = () -> Void
let allowSleep: AllowSleepCallback
typealias PreventSleepCallback = () -> Void
let preventSleep: PreventSleepCallback
let scheduler: PluginEvaluationScheduler
// We don't want to encapsulate logic of sleep management itself here,
// so we will take callbacks that will take care of actual logic
// this will also make the code more testable
init(allowSleep: @escaping AllowSleepCallback, preventSleep: @escaping PreventSleepCallback, scheduler: PluginEvaluationScheduler) {
self.allowSleep = allowSleep
self.preventSleep = preventSleep
self.scheduler = scheduler
scheduler.setup(with: self.onSchedulerFire)
}
func requestEvaluation(for plugin: NotifyingPluginProtocol) {
evaluatePlugins()
}
func onSchedulerFire() {
evaluatePlugins()
}
private func evaluatePlugins() {
var result: PluginEvaluationResult = .noOp
for plugin in plugins {
let currentResult: PluginEvaluationResult
if let evaluatingPlugin = plugin as? EvaluatedPluginProtocol {
currentResult = evaluatingPlugin.evaluate()
} else if let notifyingPlugin = plugin as? NotifyingPluginProtocol {
currentResult = notifyingPlugin.lastResult
} else {
assertionFailure("Unknown plugin type: \(plugin)")
continue
}
switch currentResult {
case .allowSleep:
// as soon as one plugin allows to sleep, stop evaluating plugins
allowSleep()
return
case .preventSleep:
result = .preventSleep
// if we will find plugin that allows to sleep later, we should ignore this value
case .noOp:
// this means plugin has no opinion whether system should
continue
}
}
switch result{
case .allowSleep:
assertionFailure("This is impossible")
case .noOp:
break
case .preventSleep
preventSleep()
}
}
}
</code></pre></div></div>
<h1 id="outro">Outro</h1>
<p>This should give you a good sense of what are the building blocks API for the app that keeps your laptop awake and uses certain event types (quite common in the automation software) to trigger this behavior. As a rule I would try to stay away from polling with timers and always look for a framework providing relevant notification - this way you are opting into Apple’s ecosystem (along with bugs of course) and will get future improvements for free.</p>
<p>While Amphetamine’s architecture is quite different, we took a look at <em>one of the possible</em> architectures that would allow adding more plugins as you think of the new cases and keep code testable.</p>
<p>As always, feedback is very welcome! You can find me on twitter <a href="https://twitter.com/zats">@zats</a></p>
iPhone X home button2017-12-27T00:00:00+00:00http://blog.zats.io/2017/12/27/iPhone-X-home-button<p>As soon as I saw iPhone X home indicator replacing the physical button, I got interested in its behavior: it has to be visible both on the lock screen with an arbitrary wallpaper as a background and in any 3rd-party app showing arbitrary content, which in case of videos or games can also change quite quickly.</p>
<p><img src="/assets/2017-12-27/home-indicators.png" alt="" /></p>
<p>Obviously, UIKit doesn’t expose anything remotely similar, so let’s figure out how it is built!</p>
<h1 id="finding-the-home-indicator-class">Finding the home indicator class</h1>
<p>To figure out where to look for the relevant code, I tried to think of the similar UI elements. Initially I thought system status bar would be the closest relative. Just like home indicator it lives on the lock screen, just like home indicator it’s being added to every app window. My first naive attempt was to look in UIKit that contains some of the status bar-relevant code. Looking into UIKit header dumps you can find on GitHub, I didn’t find anything that seemed to correspond to the new home indicator.
Next, I’d like to explore SpringBoard - it is an “app” that lives in the CoreServices folder and contains various system functionality corresponding with lock and home screen. Dumping classes containing in SpringBoard with <code class="language-plaintext highlighter-rouge">class-dump</code> (<code class="language-plaintext highlighter-rouge">$ brew install class-dump</code>) shows an interesting <code class="language-plaintext highlighter-rouge">SBHomeGrabberView</code>. That’s a good start:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ class-dump /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/CoreServices/SpringBoard.app/SpringBoard
...
@interface SBHomeGrabberView : UIView <_UISettingsKeyPathObserver, SBAttentionAwarenessClientDelegate, MTLumaDodgePillBackgroundLuminanceObserver>
{
SBHomeGrabberSettings *_settings;
MTLumaDodgePillView *_pillView;
SBAttentionAwarenessClient *_idleTouchAwarenessClient;
_Bool _touchesAreIdle;
_Bool _autoHides;
long long _luma;
unsigned long long _suppressLumaUpdates;
}
@property(nonatomic) _Bool autoHides; // @synthesize autoHides=_autoHides;
- (void).cxx_destruct;
- (void)lumaDodgePillDidDetectBackgroundLuminanceChange:(id)arg1;
</code></pre></div></div>
<p>Next up, let’s load entire code from SpringBoard into our dummy app so that we can add the view to the window and check if it’s actually the one we are interested in. While the code can be cleaner, essential idea is this:</p>
<div class="language-objc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#import <dlfcn.h>
</span>
<span class="c1">// somewhere in viewDidLoad</span>
<span class="n">dlopen</span><span class="p">([</span><span class="n">binaryPath</span> <span class="nf">cStringUsingEncoding</span><span class="p">:</span><span class="n">NSUTF8StringEncoding</span><span class="p">],</span> <span class="n">RTLD_NOW</span><span class="p">);</span>
<span class="n">UIView</span> <span class="o">*</span><span class="k">const</span> <span class="n">view</span> <span class="o">=</span> <span class="p">[[</span><span class="n">NSClassFromString</span><span class="p">(</span><span class="s">@"SBHomeGrabberView"</span><span class="p">)</span> <span class="nf">alloc</span><span class="p">]</span> <span class="nf">init</span><span class="p">];</span>
<span class="p">[</span><span class="n">view</span> <span class="nf">sizeToFit</span><span class="p">];</span>
<span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">view</span> <span class="nf">addSubview</span><span class="p">:</span><span class="n">view</span><span class="p">];</span>
</code></pre></div></div>
<p>With few modifications, this is what we get:</p>
<p><img src="/assets/2017-12-27/few-home-indicators.png" alt="" /></p>
<p>Now when we know it’s what we are looking for, let’s figure out how it’s built. To learn the implementation details I use Hopper Disassembler, even a free version will do fine for our purposes. This app helps to reduce the friction of reading disassembly (which I still know very basics of). All you need to do is to open a binary and find the method that interests you. After jumping to it, toggle the pseudo code at the top. It will generate a very readable mix of Objective-C, C++ and assembly.</p>
<p><img src="/assets/2017-12-27/hopper.png" alt="" /></p>
<ol>
<li>We typed the the name of the class to see all the methods that were implemented</li>
<li>Over time you will build an intuition and will learn to spot “interesting” methods. It never hurts to start with public UIKit methods since Apple engineers use those, too. That’s why I started with <code class="language-plaintext highlighter-rouge">-[SBHomeGrabberView initWithFrame:]</code></li>
<li>Unless you are comfortable with reading assembly, switch to pseudo-code mode</li>
<li>Try to make as much sense as possible. Sometimes code is quite self-explanatory, sometimes you will find yourself in the dead end.</li>
</ol>
<p>On a personal note, I find reading implementation details very interesting. I do it for “fun” sometimes, or when I want to understand certain behaviour better.</p>
<p>Back to our <code class="language-plaintext highlighter-rouge">SBHomeGrabberView</code>, we see that it’s a rather thin wrapper (aside from various bookkeeping… oh hey <code class="language-plaintext highlighter-rouge">AWAttentionAwarenessConfiguration</code>, I’ll need to revisit you later!), adds a <code class="language-plaintext highlighter-rouge">MTLumaDodgePillView</code> subview. Initially I thought it’s defined in the Metal framework (mostly due to MTL prefix), but it seems a bit too specific to be defined in such a “low-level” framework as Metal. Also as Matthias pointed out on <a href="https://twitter.com/myell0w/status/946304768783388673">twitter</a>, the prefix of our class is actually <code class="language-plaintext highlighter-rouge">MT</code> and not <code class="language-plaintext highlighter-rouge">MTL</code> 🤦♂️.
Luckily, if you load a binary (such as SpringBoard) into your app, you also get access to all the libraries it loads subsequently. It makes finding the library defining the class as easy as using <code class="language-plaintext highlighter-rouge">dladdr</code>:</p>
<div class="language-objc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">const</span> <span class="n">Class</span> <span class="n">MTLumaDodgePillViewClass</span> <span class="o">=</span> <span class="n">NSClassFromString</span><span class="p">(</span><span class="s">@"MTLumaDodgePillView"</span><span class="p">);</span>
<span class="n">Dl_info</span> <span class="n">dlInfo</span><span class="p">;</span>
<span class="n">dladdr</span><span class="p">((</span><span class="n">__bridge</span> <span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="n">MTLumaDodgePillViewClass</span><span class="p">,</span> <span class="o">&</span><span class="n">dlInfo</span><span class="p">);</span>
<span class="n">dlInfo</span><span class="p">.</span><span class="n">dli_fname</span><span class="p">;</span> <span class="c1">// path to the binary defining the symbol (class in this case)</span>
</code></pre></div></div>
<p>This code can be run as a part of the app I set up to investigate. You can also use <code class="language-plaintext highlighter-rouge">lldb</code>. Lesser known lldb-feature is being able to set up variables. The advantage of using lldb is that you don’t have to recompile the app, the disadvantage is that lldb requires a bit more help with types since it doesn’t have access to the header files, hence casting additional variable and function return types:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(lldb) e Dl_info $dlInfo
(lldb) e (void)dladdr((__bridge void *)NSClassFromString(@"MTLumaDodgePillView"), & $dlInfo);
(lldb) p $dlInfo.dli_fname
(const char *) $1 = 0x00006000001fd900 "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/PrivateFrameworks/MaterialKit.framework/MaterialKit"
</code></pre></div></div>
<p>As we can see, it’s defined in <code class="language-plaintext highlighter-rouge">/System/Library/PrivateFrameworks/MaterialKit.framework/MaterialKit</code></p>
<div class="language-objc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">@class</span> <span class="nc">MTLumaDodgePillView</span><span class="p">;</span>
<span class="k">@protocol</span> <span class="nc">MTLumaDodgePillBackgroundLuminanceObserver</span> <span class="o"><</span><span class="n">NSObject</span><span class="o">></span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">lumaDodgePillDidDetectBackgroundLuminanceChange</span><span class="p">:(</span><span class="n">MTLumaDodgePillView</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg1</span><span class="p">;</span>
<span class="k">@end</span>
<span class="k">@interface</span> <span class="nc">MTLumaDodgePillView</span> <span class="p">:</span> <span class="nc">UIView</span>
<span class="k">@property</span><span class="p">(</span><span class="n">nonatomic</span><span class="p">,</span> <span class="n">weak</span><span class="p">)</span> <span class="n">id</span> <span class="o"><</span><span class="n">MTLumaDodgePillBackgroundLuminanceObserver</span><span class="o">></span> <span class="n">backgroundLumninanceObserver</span><span class="p">;</span>
<span class="k">@property</span><span class="p">(</span><span class="n">nonatomic</span><span class="p">)</span> <span class="n">MTLumaDodgePillViewStyle</span> <span class="n">style</span><span class="p">;</span>
<span class="k">@property</span><span class="p">(</span><span class="n">nonatomic</span><span class="p">,</span> <span class="n">readonly</span><span class="p">)</span> <span class="n">MTLumaDodgePillViewBackgroundLuminance</span> <span class="n">backgroundLuminance</span><span class="p">;</span>
<span class="k">@end</span>
</code></pre></div></div>
<p>Few things to point out. To figure out possible values for <code class="language-plaintext highlighter-rouge">MTLumaDodgePillViewStyle</code> and <code class="language-plaintext highlighter-rouge">MTLumaDodgePillViewBackgroundLuminance</code>, it’s enough to look into the description method. It converts integer values into strings, which we are going to use for the constants:</p>
<div class="language-objc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="nf">NS_ENUM</span><span class="p">(</span><span class="n">NSInteger</span><span class="p">,</span> <span class="n">MTLumaDodgePillViewStyle</span><span class="p">)</span> <span class="p">{</span>
<span class="n">MTLumaDodgePillViewStyleNone</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span>
<span class="n">MTLumaDodgePillViewStyleThin</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
<span class="n">MTLumaDodgePillViewStyleGray</span> <span class="o">=</span> <span class="mi">2</span><span class="p">,</span>
<span class="n">MTLumaDodgePillViewStyleBlack</span> <span class="o">=</span> <span class="mi">3</span><span class="p">,</span>
<span class="n">MTLumaDodgePillViewStyleWhite</span> <span class="o">=</span> <span class="mi">4</span><span class="p">,</span>
<span class="p">};</span>
<span class="k">typedef</span> <span class="nf">NS_ENUM</span><span class="p">(</span><span class="n">NSInteger</span><span class="p">,</span> <span class="n">MTLumaDodgePillViewBackgroundLuminance</span><span class="p">)</span> <span class="p">{</span>
<span class="n">MTLumaDodgePillViewBackgroundLuminanceUnknown</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span>
<span class="n">MTLumaDodgePillViewBackgroundLuminanceDark</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
<span class="n">MTLumaDodgePillViewBackgroundLuminanceLight</span> <span class="o">=</span> <span class="mi">2</span><span class="p">,</span>
<span class="p">};</span>
</code></pre></div></div>
<p>Last interesting API is the <code class="language-plaintext highlighter-rouge">backgroundLumninanceObserver</code>, it will invoke the callback every time our view changed its appearance.</p>
<h1 id="building-our-own-mtlumadodgepillview">Building our own <code class="language-plaintext highlighter-rouge">MTLumaDodgePillView</code></h1>
<p>While we are getting closer, <code class="language-plaintext highlighter-rouge">MTLumaDodgePillViewStyle</code> is just a wrapper of sort itself. Internally it is a private-class galore: It proxies calls to <code class="language-plaintext highlighter-rouge">CABackdropLayer</code> (private, iOS 7+), using a whole slew of <code class="language-plaintext highlighter-rouge">CAFilter</code>s (private, iOS 2+), including the one called <code class="language-plaintext highlighter-rouge">kCAFilterHomeAffordanceBase</code>.
<code class="language-plaintext highlighter-rouge">CABackdropLayer</code> is what’s powering various blur effects since iOS 7 introduced them. In a nutshell it clones the view hierarchy behind the layer, and gathers statistics about the contents. Also any CALayer allows to apply QuartzCore filters to any layer. Cloning view hierarchy along with filters applied to it, allows to produce all variations effects provided by <code class="language-plaintext highlighter-rouge">UIVisualEffectView</code>. Let’s take basic blur example:</p>
<div class="language-objc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">UIBlurEffect</span> <span class="o">*</span><span class="n">blur</span> <span class="o">=</span> <span class="p">[</span><span class="n">UIBlurEffect</span> <span class="nf">effectWithStyle</span><span class="p">:</span><span class="n">UIBlurEffectStyleLight</span><span class="p">];</span>
<span class="n">UIVisualEffectView</span> <span class="o">*</span><span class="n">blurView</span> <span class="o">=</span> <span class="p">[[</span><span class="n">UIVisualEffectView</span> <span class="nf">alloc</span><span class="p">]</span> <span class="nf">initWithEffect</span><span class="p">:</span><span class="n">blur</span><span class="p">];</span>
</code></pre></div></div>
<p>To build it all we need is: Gaussian blur, saturation filter and a solid white color composed using source over blend mode. Here’s a rough code for the filtering part:</p>
<div class="language-objc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">CAFilter</span> <span class="o">*</span><span class="k">const</span> <span class="n">blur</span> <span class="o">=</span> <span class="p">[(</span><span class="n">id</span><span class="p">)</span><span class="n">NSClassFromString</span><span class="p">(</span><span class="s">@"CAFilter"</span><span class="p">)</span> <span class="nf">filterWithType</span><span class="p">:</span><span class="n">kCAFilterGaussianBlur</span><span class="p">];</span>
<span class="p">[</span><span class="n">blur</span> <span class="nf">setValue</span><span class="p">:</span><span class="mi">@30</span> <span class="nf">forKey</span><span class="p">:</span><span class="s">@"inputRadius"</span><span class="p">];</span>
<span class="n">CAFilter</span> <span class="o">*</span><span class="k">const</span> <span class="n">saturate</span> <span class="o">=</span> <span class="p">[(</span><span class="n">id</span><span class="p">)</span><span class="n">NSClassFromString</span><span class="p">(</span><span class="s">@"CAFilter"</span><span class="p">)</span> <span class="nf">filterWithType</span><span class="p">:</span><span class="n">kCAFilterColorSaturate</span><span class="p">];</span>
<span class="p">[</span><span class="n">saturate</span> <span class="nf">setValue</span><span class="p">:</span><span class="mf">@1.8</span> <span class="nf">forKey</span><span class="p">:</span><span class="s">@"inputAmount"</span><span class="p">];</span>
<span class="n">CABackdropLayer</span> <span class="o">*</span><span class="n">backdrop</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSClassFromString</span><span class="p">(</span><span class="s">@"CABackdropLayer"</span><span class="p">)</span> <span class="nf">new</span><span class="p">];</span>
<span class="n">backdrop</span><span class="p">.</span><span class="n">filters</span> <span class="o">=</span> <span class="p">@[</span> <span class="n">blur</span><span class="p">,</span> <span class="n">saturate</span> <span class="p">];</span>
<span class="n">CALayer</span> <span class="o">*</span><span class="n">overlay</span> <span class="o">=</span> <span class="p">[</span><span class="n">CALayer</span> <span class="nf">new</span><span class="p">];</span>
<span class="n">overlay</span><span class="p">.</span><span class="n">backgroundColor</span> <span class="o">=</span> <span class="p">[</span><span class="n">UIColor</span> <span class="nf">colorWithWhite</span><span class="p">:</span><span class="mi">1</span> <span class="nf">alpha</span><span class="p">:</span><span class="mi">0</span><span class="p">.</span><span class="mi">3</span><span class="p">].</span><span class="n">CGColor</span><span class="p">;</span>
<span class="n">overlay</span><span class="p">.</span><span class="n">compositeFilter</span> <span class="o">=</span> <span class="p">[(</span><span class="n">id</span><span class="p">)</span><span class="n">NSClassFromString</span><span class="p">(</span><span class="s">@"CAFilter"</span><span class="p">)</span> <span class="nf">filterWithType</span><span class="p">:</span><span class="n">kCAFilterSourceOver</span><span class="p">];</span>
<span class="p">[</span><span class="n">layer</span> <span class="nf">addSublayer</span><span class="p">:</span><span class="n">backdrop</span><span class="p">];</span>
<span class="p">[</span><span class="n">layer</span> <span class="nf">addSublayer</span><span class="p">:</span><span class="n">overlay</span><span class="p">];</span>
</code></pre></div></div>
<h1 id="putting-it-all-together">Putting it all together</h1>
<p>Final touch is to open <code class="language-plaintext highlighter-rouge">-[MTLumaDodgePillView initWithFrame:]</code>. It shows the list of the filters MaterialKit creates in order to replicate the effect:</p>
<div class="language-objc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">CAFilter</span> <span class="o">*</span><span class="k">const</span> <span class="n">blur</span> <span class="o">=</span> <span class="p">[(</span><span class="n">id</span><span class="p">)</span><span class="n">NSClassFromString</span><span class="p">(</span><span class="s">@"CAFilter"</span><span class="p">)</span> <span class="nf">filterWithType</span><span class="p">:</span><span class="n">kCAFilterGaussianBlur</span><span class="p">];</span>
<span class="n">CAFilter</span> <span class="o">*</span><span class="k">const</span> <span class="n">colorBrightness</span> <span class="o">=</span> <span class="p">[(</span><span class="n">id</span><span class="p">)</span><span class="n">NSClassFromString</span><span class="p">(</span><span class="s">@"CAFilter"</span><span class="p">)</span> <span class="nf">filterWithType</span><span class="p">:</span><span class="n">kCAFilterColorBrightness</span><span class="p">];</span>
<span class="n">CAFilter</span> <span class="o">*</span><span class="k">const</span> <span class="n">colorSaturate</span> <span class="o">=</span> <span class="p">[(</span><span class="n">id</span><span class="p">)</span><span class="n">NSClassFromString</span><span class="p">(</span><span class="s">@"CAFilter"</span><span class="p">)</span> <span class="nf">filterWithType</span><span class="p">:</span><span class="n">kCAFilterColorSaturate</span><span class="p">];</span>
</code></pre></div></div>
<p>To get the actual values for each filter we will pause using the view debugger, select one of our added views, copy the address from the view or layer section on the right</p>
<p><img src="/assets/2017-12-27/view-debugger.png" alt="" /></p>
<p>now in the console we can use the selected addresses as if they are the references to the views and layers themselves</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(lldb) po 0x7fc81331a8a0
<MTLumaDodgePillView:0x7fc81331a8a0 frame={\{120.5, 107.5}, {134, 5}\} style=white backgroundLuminance=unknown>
(lldb) po ((CALayer *)0x600000226d60).filters
<__NSArrayI 0x60000005e450>(
homeAffordanceBase,
gaussianBlur,
colorBrightness,
colorSaturate
)
(lldb) po [((CALayer *)0x600000226d60).filters[0] valueForKey:@"inputAmount"]
1
(lldb) po [((CALayer *)0x600000226d60).filters[0] valueForKey:@"inputAddWhite"]
0.71
</code></pre></div></div>
<p>As you noticed we are casting types on the integers when we are calling properties on them, this is to help lldb to figure out the type of the object behind the pointer.</p>
<p>Repeating <code class="language-plaintext highlighter-rouge">valueForKey:</code> dance for every property we found mentioned in <code class="language-plaintext highlighter-rouge">-[MTLumaDodgePillView initWithFrame:]</code>. It is a bit tedious but I didn’t want to look for the original styles definition file (assuming it comes from a plist somewhere). Once finished we can reconstruct the view using only QuartzCore:</p>
<div class="language-objc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">CAFilter</span> <span class="o">*</span><span class="k">const</span> <span class="n">homeAffordanceBase</span> <span class="o">=</span> <span class="p">[(</span><span class="n">id</span><span class="p">)</span><span class="n">NSClassFromString</span><span class="p">(</span><span class="s">@"CAFilter"</span><span class="p">)</span> <span class="nf">filterWithType</span><span class="p">:</span><span class="n">kCAFilterHomeAffordanceBase</span><span class="p">];</span>
<span class="n">UIImage</span> <span class="o">*</span><span class="k">const</span> <span class="n">lumaDodgeMap</span> <span class="o">=</span> <span class="p">[</span><span class="n">UIImage</span> <span class="nf">imageNamed</span><span class="p">:</span><span class="s">@"lumaDodgePillMap"</span> <span class="nf">inBundle</span><span class="p">:[</span><span class="n">NSBundle</span> <span class="nf">bundleForClass</span><span class="p">:</span><span class="n">viewClass</span><span class="p">]</span> <span class="n">compatibleWithTraitCollection</span><span class="o">:</span><span class="nb">nil</span><span class="p">];</span>
<span class="p">[</span><span class="n">homeAffordanceBase</span> <span class="nf">setValue</span><span class="p">:(</span><span class="n">__bridge</span> <span class="n">id</span><span class="p">)</span><span class="n">lumaDodgeMap</span><span class="p">.</span><span class="n">CGImage</span> <span class="nf">forKey</span><span class="p">:</span><span class="s">@"inputColorMap"</span><span class="p">];</span>
<span class="n">CAFilter</span> <span class="o">*</span><span class="k">const</span> <span class="n">blurFilter</span> <span class="o">=</span> <span class="p">[(</span><span class="n">id</span><span class="p">)</span><span class="n">NSClassFromString</span><span class="p">(</span><span class="s">@"CAFilter"</span><span class="p">)</span> <span class="nf">filterWithType</span><span class="p">:</span><span class="n">kCAFilterGaussianBlur</span><span class="p">];</span>
<span class="n">CAFilter</span> <span class="o">*</span><span class="k">const</span> <span class="n">colorBrightness</span> <span class="o">=</span> <span class="p">[(</span><span class="n">id</span><span class="p">)</span><span class="n">NSClassFromString</span><span class="p">(</span><span class="s">@"CAFilter"</span><span class="p">)</span> <span class="nf">filterWithType</span><span class="p">:</span><span class="n">kCAFilterColorBrightness</span><span class="p">];</span>
<span class="n">CAFilter</span> <span class="o">*</span><span class="k">const</span> <span class="n">colorSaturate</span> <span class="o">=</span> <span class="p">[(</span><span class="n">id</span><span class="p">)</span><span class="n">NSClassFromString</span><span class="p">(</span><span class="s">@"CAFilter"</span><span class="p">)</span> <span class="nf">filterWithType</span><span class="p">:</span><span class="n">kCAFilterColorSaturate</span><span class="p">];</span>
<span class="c1">// MTLumaDodgePillViewStyleThin values</span>
<span class="p">[</span><span class="n">homeAffordanceBase</span> <span class="nf">setValue</span><span class="p">:</span><span class="mf">@0.31</span> <span class="nf">forKey</span><span class="p">:</span><span class="s">@"inputAmount"</span><span class="p">];</span>
<span class="p">[</span><span class="n">homeAffordanceBase</span> <span class="nf">setValue</span><span class="p">:</span><span class="mf">@0.37275</span> <span class="nf">forKey</span><span class="p">:</span><span class="s">@"inputAddWhite"</span><span class="p">];</span>
<span class="p">[</span><span class="n">homeAffordanceBase</span> <span class="nf">setValue</span><span class="p">:</span><span class="mf">@0.4</span> <span class="nf">forKey</span><span class="p">:</span><span class="s">@"inputOverlayOpacity"</span><span class="p">];</span>
<span class="p">[</span><span class="n">blurFilter</span> <span class="nf">setValue</span><span class="p">:</span><span class="mi">@10</span> <span class="nf">forKey</span><span class="p">:</span><span class="s">@"inputRadius"</span><span class="p">];</span>
<span class="p">[</span><span class="n">blurFilter</span> <span class="nf">setValue</span><span class="p">:</span><span class="nb">@YES</span> <span class="nf">forKey</span><span class="p">:</span><span class="s">@"inputHardEdges"</span><span class="p">];</span>
<span class="p">[</span><span class="n">colorBrightness</span> <span class="nf">setValue</span><span class="p">:</span><span class="mf">@0.06</span> <span class="nf">forKey</span><span class="p">:</span><span class="s">@"inputAmount"</span><span class="p">];</span>
<span class="p">[</span><span class="n">colorSaturate</span> <span class="nf">setValue</span><span class="p">:</span><span class="mf">@1.15</span> <span class="nf">forKey</span><span class="p">:</span><span class="s">@"inputAmount"</span><span class="p">];</span>
<span class="n">CALayer</span> <span class="o">*</span><span class="n">layer</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSClassFromString</span><span class="p">(</span><span class="s">@"CABackdropLayer"</span><span class="p">)</span> <span class="nf">new</span><span class="p">];</span>
<span class="n">layer</span><span class="p">.</span><span class="n">frame</span> <span class="o">=</span> <span class="n">CGRectInset</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">view</span><span class="p">.</span><span class="n">bounds</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="mi">100</span><span class="p">);</span>
<span class="n">layer</span><span class="p">.</span><span class="n">filters</span> <span class="o">=</span> <span class="p">@[</span> <span class="n">homeAffordanceBase</span><span class="p">,</span> <span class="n">blurFilter</span><span class="p">,</span> <span class="n">colorSaturate</span><span class="p">,</span> <span class="n">colorSaturate</span> <span class="p">];</span>
<span class="n">layer</span><span class="p">.</span><span class="n">cornerRadius</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
<span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">view</span><span class="p">.</span><span class="n">layer</span> <span class="nf">addSublayer</span><span class="p">:</span><span class="n">layer</span><span class="p">];</span>
</code></pre></div></div>
<p>The mysterious home affordance base filter seems to use the passed <code class="language-plaintext highlighter-rouge">lumaDodgePullMap</code> image as to map the input image. Everything else seems to be fairly straight forward use of filters we saw in the implementation of <code class="language-plaintext highlighter-rouge">UIVisualEffectView</code>. That’s all, we get our final result:</p>
<video src="/assets/2017-12-27/final.mov" width="50%" autoplay="" controls="" loop=""></video>
<h1 id="afterword">Afterword</h1>
<p>Hope this article showed you reverse engineering as a far less magical endeavor than it appeared before; Objective-C with helps with abundance of the information retained in the binaries. It makes reverse engineering into a fun adventure!
Feel free to share your thoughts or ask questions on twitter <a href="http://twitter.com/zats">@zats</a></p>
<p>My thanks go to <a href="https://twitter.com/warpling">@warpling</a>, <a href="https://twitter.com/myell0w">@myell0w</a>, <a href="https://twitter.com/shaps">@shaps</a> and others for suggestions on how to improve this post.</p>
Markov Chains with GameplayKit2015-08-29T00:00:00+00:00http://blog.zats.io/2015/08/29/markov-chains-with-gameplaykit<p>GameplayKit hides many amazing features: a random number generators, components architecture, path finding, state machines and more. <a href="http://setosa.io/blog/2014/07/26/markov-chains/">Markov chains</a> is another ingenious gem that can be utilised by games or apps to simulate natural patterns. It has plenty of <a href="https://en.wikipedia.org/wiki/Markov_chain#Applications">useful applications</a>.
Since Markov chains <a href="http://stackoverflow.com/questions/4880286/is-a-markov-chain-the-same-as-a-finite-state-machine">can be represented</a> by a finite state machine, it seems logical to implement it using <code class="language-plaintext highlighter-rouge">GKStateMachine</code> from GampelayKit.</p>
<p>Basically, it is an autopilot combined with <code class="language-plaintext highlighter-rouge">GKStateMachine</code>. As a result, API for <code class="language-plaintext highlighter-rouge">MarkovChainMachine</code> is less hands on. All you need is to set its initial state and it will tell you which state should be next. Here is an example:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">m</span> <span class="o">=</span> <span class="kt">MarkovChainMachine</span><span class="p">(</span><span class="nv">initialStates</span><span class="p">:</span> <span class="p">[</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">],</span> <span class="nv">mapping</span><span class="p">:</span> <span class="p">[</span>
<span class="p">[</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">]:</span> <span class="p">[</span>
<span class="p">[</span><span class="mf">0.3</span><span class="p">:</span> <span class="n">a</span><span class="p">],</span>
<span class="p">[</span><span class="mf">0.7</span><span class="p">:</span> <span class="n">b</span><span class="p">]</span>
<span class="p">],</span>
<span class="p">[</span><span class="n">b</span><span class="p">,</span> <span class="n">a</span><span class="p">]:</span> <span class="p">[</span>
<span class="p">[</span><span class="mf">0.7</span><span class="p">:</span> <span class="n">a</span><span class="p">],</span>
<span class="p">[</span><span class="mf">0.3</span><span class="p">:</span> <span class="n">b</span><span class="p">]</span>
<span class="p">],</span>
<span class="p">[</span><span class="n">a</span><span class="p">,</span> <span class="n">a</span><span class="p">]:</span> <span class="p">[</span>
<span class="p">[</span><span class="mf">0.1</span><span class="p">:</span> <span class="n">a</span><span class="p">],</span>
<span class="p">[</span><span class="mf">0.9</span><span class="p">:</span> <span class="n">b</span><span class="p">]</span>
<span class="p">],</span>
<span class="p">[</span><span class="n">b</span><span class="p">,</span> <span class="n">b</span><span class="p">]:</span> <span class="p">[</span>
<span class="p">[</span><span class="mf">0.9</span><span class="p">:</span> <span class="n">a</span><span class="p">],</span>
<span class="p">[</span><span class="mf">0.1</span><span class="p">:</span> <span class="n">b</span><span class="p">]</span>
<span class="p">]</span>
<span class="p">])</span>
<span class="k">for</span> <span class="n">_</span> <span class="k">in</span> <span class="mi">0</span><span class="o">...</span><span class="mi">15</span> <span class="p">{</span>
<span class="k">if</span> <span class="n">m</span><span class="o">.</span><span class="nf">enterNextState</span><span class="p">()</span> <span class="p">{</span>
<span class="nf">print</span><span class="p">(</span><span class="n">m</span><span class="o">.</span><span class="n">currentState</span><span class="o">!</span><span class="p">,</span> <span class="nv">separator</span><span class="p">:</span> <span class="s">""</span><span class="p">,</span> <span class="nv">terminator</span><span class="p">:</span> <span class="s">" "</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Given, we have 2 states <code class="language-plaintext highlighter-rouge">a</code> and <code class="language-plaintext highlighter-rouge">b</code>, and following rules:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">a b</code> is likely to be followed by <code class="language-plaintext highlighter-rouge">b</code></li>
<li><code class="language-plaintext highlighter-rouge">b a</code> is likely to be followed by <code class="language-plaintext highlighter-rouge">a</code></li>
<li><code class="language-plaintext highlighter-rouge">a a</code> is almost definitely to be followed by <code class="language-plaintext highlighter-rouge">b</code></li>
<li><code class="language-plaintext highlighter-rouge">b b</code> is almost definitely to be followed by <code class="language-plaintext highlighter-rouge">a</code></li>
</ul>
<p>Running the code will yield results similar to <code class="language-plaintext highlighter-rouge">A B B A B B A A B A A B A A B B A A </code></p>
<p>Several architectural notes:</p>
<ul>
<li>I decided to opt out from custom structure representing a probable outcome to make it easier to compose mapping of current state to to possible outcomes.</li>
<li><code class="language-plaintext highlighter-rouge">MarkovChainMachine</code> expects mapping keys to be of the same length as <code class="language-plaintext highlighter-rouge">initialState</code> array. It uses the <code class="language-plaintext highlighter-rouge">initialState</code> length to deduce the lookbehind size.</li>
<li>When working with free text, it is possible to come to the terminal state. Although it is not taken care of here, it is quite easy to workaround be adding a missing state transition to one of the registered states.</li>
<li>The downside of piggybacking on GameplayKit is that each state must be a separate class. This architectural decision felt strange when I was researching GameplayKit here it might pose certain challenges.</li>
</ul>
<p>Last limitation is quite annoying when dealing with unknown data set. I worked around using dynamic class generation, a neat feature of Objective-C runtime. When processing free text, I create a dynamic subclass of <code class="language-plaintext highlighter-rouge">GKState</code>, e.g. <code class="language-plaintext highlighter-rouge">State_J</code> or <code class="language-plaintext highlighter-rouge">State_i</code>. Later I can use these classes to enter the appropriate state.</p>
<p>The project is quite an experiment: no tests and just 2 examples. It can be found at Github https://github.com/NSFWObject/MarkovChains</p>
copy vs strong (retain)2015-08-27T00:00:00+00:00http://blog.zats.io/2015/08/27/copy-vs-retain<p>The question when to use <code class="language-plaintext highlighter-rouge">copy</code> vs <code class="language-plaintext highlighter-rouge">strong</code> (ex <code class="language-plaintext highlighter-rouge">retain</code>) is getting quite old, so I decided to summarise rules I follow in one place. Mostly this is Objective-C-related post.</p>
<h1 id="properties">Properties</h1>
<h2 id="must-copy-if-type-has-a-mutable-subclass">Must <code class="language-plaintext highlighter-rouge">copy</code> if type has a mutable subclass</h2>
<div class="language-objectivec highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">@property</span> <span class="p">(</span><span class="n">nonatomic</span><span class="p">,</span> <span class="n">copy</span><span class="p">)</span> <span class="n">NSArray</span> <span class="o">*</span><span class="n">puppies</span><span class="p">;</span>
</code></pre></div></div>
<p>or in Swift when using with Objective-C:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">@NSCopying</span> <span class="k">var</span> <span class="nv">name</span><span class="p">:</span> <span class="kt">String</span>
</code></pre></div></div>
<p>If type of a property has a mutable counterpart, you <em>must</em> use <code class="language-plaintext highlighter-rouge">copy</code>, since you might get <code class="language-plaintext highlighter-rouge">NSMutable<Class></code> instead of <code class="language-plaintext highlighter-rouge">NS<Class></code> and the value might simply change underneath you without you knowing about it.</p>
<h2 id="might-need-copy-if-type-conforms-nscopying">Might need <code class="language-plaintext highlighter-rouge">copy</code> if type conforms <code class="language-plaintext highlighter-rouge">NSCopying</code></h2>
<p>If type of a property conforms to <code class="language-plaintext highlighter-rouge">NSCopying</code>, it’s a sign that you <em>might</em> want to use <code class="language-plaintext highlighter-rouge">copy</code> but not necessarily. It would depend on implementation details of a particular class. Sadly, Cocoa doesn’t have strict guidelines on how class should implement <code class="language-plaintext highlighter-rouge">NSCopying</code>. Keep in mind there is a <code class="language-plaintext highlighter-rouge">NSMutableCopying</code> protocol, if you want to underline the fact you have mutable and immutable flavors of your class, implement both protocols.</p>
<h2 id="copy-doesnt-affect-ivars-assignment"><code class="language-plaintext highlighter-rouge">copy</code> doesn’t affect ivars assignment</h2>
<p>Keep in mind that <code class="language-plaintext highlighter-rouge">copy</code> affects only the assignment fo the property and not the underlying ivar:</p>
<div class="language-objectivec highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">@property</span> <span class="p">(</span><span class="n">nonatomic</span><span class="p">,</span> <span class="n">copy</span><span class="p">)</span> <span class="n">NSAttributedString</span> <span class="o">*</span><span class="n">attributedTitle</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">setAttributedTitle</span><span class="p">:(</span><span class="n">NSAttributedString</span> <span class="o">*</span><span class="p">)</span><span class="nv">title</span> <span class="p">{</span>
<span class="n">_attributedTitle</span> <span class="o">=</span> <span class="p">[</span><span class="n">title</span> <span class="nf">copy</span><span class="p">];</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="even-if-property-isreadonly">Even if property is<code class="language-plaintext highlighter-rouge">readonly</code></h2>
<p>Even if property is declared as <code class="language-plaintext highlighter-rouge">readonly</code>, it is a good practise to use <code class="language-plaintext highlighter-rouge">copy</code>: you don’t have to remember to copy values internally. Also it helps to avoid potential bugs later if you decided to expose property as <code class="language-plaintext highlighter-rouge">readwrite</code>.</p>
<h1 id="methods">Methods</h1>
<h2 id="arguments-might-need-to-be-copied-internally">Arguments might need to be copied internally</h2>
<div class="language-objectivec highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">applyParameters</span><span class="p">:(</span><span class="n">NSDictionary</span> <span class="o">*</span><span class="p">)</span><span class="nv">parameters</span> <span class="p">{</span>
<span class="n">parameters</span> <span class="o">=</span> <span class="p">[</span><span class="n">parameters</span> <span class="nf">copy</span><span class="p">];</span> <span class="c1">// not that it's nice to reassign parameters</span>
<span class="p">}</span>
</code></pre></div></div>
<p>When working with parameters, depending on the implementation details of your method, you might want to copy arguments. Sadly, there is no syntactic sugar for it. In the example above, it is valid to pass a <code class="language-plaintext highlighter-rouge">NSMutableDictionary</code> which might be changed from a different thread or, if you keep the reference to <code class="language-plaintext highlighter-rouge">parameters</code> once you leave the method.</p>
<h2 id="return-values-might-need-to-be-copied-before-returning">Return values might need to be copied before returning</h2>
<div class="language-objectivec highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Private proeprty declared in `.m`</span>
<span class="k">@property</span> <span class="p">(</span><span class="n">nonatomic</span><span class="p">,</span> <span class="n">strong</span><span class="p">)</span> <span class="n">NSMutableArray</span> <span class="o">*</span><span class="n">things</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="n">NSArray</span> <span class="o">*</span><span class="p">)</span><span class="n">currentStateOfThings</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">things</span> <span class="nf">copy</span><span class="p">];</span>
<span class="p">}</span>
</code></pre></div></div>
<p>When you’re promissing to return immutable object, while your internal property is mutable, you probably want to <code class="language-plaintext highlighter-rouge">copy</code> because consumers will make all sort of assumptions about the object, including its thread safety.</p>
<p>Consider user getting a reference to internally mutable array and using it a data source for table view. Some time later, you remove several objects from the array, next time consumer scrolls he will crash since he was not aware of count proeprty chagned on the array.</p>
GKRandomDistribution, GKShuffledDistribution and the GKGaussianDistribution2015-08-15T00:00:00+00:00http://blog.zats.io/2015/08/15/randoms<p>GameplayKit brings random numbers generation among other useful things. So what’s the difference between <code class="language-plaintext highlighter-rouge">GKRandomDistribution</code>, <code class="language-plaintext highlighter-rouge">GKGaussianDistribution</code> and <code class="language-plaintext highlighter-rouge">GKShuffledDistribution</code>?
As the name suggests, <code class="language-plaintext highlighter-rouge">GKShuffledDistribution</code> is useful for when you want to simulate card deck behaviour. Pulling a random card one after another. Until you go through entire deck, there is no way you will see the same card twice (putting magic tricks aside).
<code class="language-plaintext highlighter-rouge">GKGaussianDistribution</code> is targeting problem of generating random numbers around the center of the range (2 in the example below). Here is a little sample, illustrating the differences:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import Cocoa
import GameplayKit
let randoms = NSCountedSet()
let shuffles = NSCountedSet()
let gausians = NSCountedSet()
let randomD3 = GKRandomDistribution(lowestValue: 1, highestValue: 3)
let shuffledD3 = GKShuffledDistribution(lowestValue: 1, highestValue: 3)
let gausianD3 = GKGaussianDistribution(lowestValue: 1, highestValue: 3)
for i in 0..<30 {
randoms.addObject(randomD3.nextInt())
shuffles.addObject(shuffledD3.nextInt())
gausians.addObject(gausianD3.nextInt())
}
print("Random:")
randoms.forEach{
print("\($0) \(randoms.countForObject($0))")
}
print("Shuffled:")
shuffles.forEach{
print("\($0) \(shuffles.countForObject($0))")
}
print("Gausian:")
gausians.forEach{
print("\($0) \(gausians.countForObject($0))")
}
</code></pre></div></div>
<p>Here is the output it produces:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Random:
1 14
2 11
3 5
Shuffled:
1 10
2 10
3 10
Gausian:
1 2
3 2
2 26
</code></pre></div></div>
<p>And a visual version:</p>
<p><img src="/assets/2015-08-15/random.png" alt="" /></p>
<p>Although <code class="language-plaintext highlighter-rouge">GKRandomDistribution</code> instance produces equally distributed random numbers, it can result in so called “lucky streaks” - getting same value several times in a row. That’s exactly when you want to use <code class="language-plaintext highlighter-rouge">GKShuffledDistribution</code>. As for <code class="language-plaintext highlighter-rouge">GKGaussianDistribution</code>, it targets cases when you need to generate random numbers around center, not getting too close to the upper and lower bounds (1 and 3 in our example).</p>
<p>Very welcomed additions to Cocoa family.</p>
<p>Where to go from here: http://ericasadun.com/?s=GameplayKit</p>
Fizz Buzz with GameplayKit2015-08-15T00:00:00+00:00http://blog.zats.io/2015/08/15/fizz-buzz<p>A great idea found at <a href="http://www.knowing.net/index.php/2015/08/04/fizzbuzz-with-ios-9-gameplaykit-expert-system-in-c-with-xam-ios">knowing.net</a> and backported to swift.</p>
<p><a href="https://en.wikipedia.org/wiki/Fizz_buzz">Fizz buzz</a> is a simple game and GameplayKit API making it equally simple to describe the rules. Untyped state dictionary can definitely use some “swiftification”, but overall, code is quite simple. Here it is:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import Cocoa
import GameplayKit
let fizzRule = GKRule(blockPredicate: { system in
(system.state["value"] as! Int) % 3 == 0
}, action: { system in
system.state["output"] = "fizz"
})
fizzRule.salience = 1;
let buzzRule = GKRule(blockPredicate: { system in
return (system.state["value"] as! Int) % 5 == 0
}, action: { system in
if let out = system.state["output"] as? String {
system.state["output"] = "\(out) buzz"
} else {
system.state["output"] = "buzz"
}
})
buzzRule.salience = 2;
let printRule = GKRule(blockPredicate: { system in
let value = system.state["value"] as! Int
return (value % 5 != 0) && (value % 3 != 0)
}, action: { system in
let value = system.state["value"] as! Int
system.state["output"] = "\(value)"
})
printRule.salience = 0
let ruleSystem = GKRuleSystem()
ruleSystem.addRule(fizzRule)
ruleSystem.addRule(buzzRule)
ruleSystem.addRule(printRule)
for i in 1...100 {
ruleSystem.state["value"] = Int(i)
ruleSystem.state["output"] = nil
ruleSystem.evaluate()
print(ruleSystem.state["output"]!)
ruleSystem.reset()
}
</code></pre></div></div>
<p>Output is</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1
2
fizz
4
buzz
...
</code></pre></div></div>
<p>I’m looking forward to seeing gaming and not only frameworks emerging on top of GameplayKit! Foundation is very promising.</p>
Improving view debugging in Xcode2015-06-16T00:00:00+00:00http://blog.zats.io/2015/06/16/improving-view-debugging-in-xcode<p>Normally view debugging in Xcode is somewhat hard: you have to attribute bunch of faceless <code class="language-plaintext highlighter-rouge">UIViews</code> to relevant view controller. Here is a before and after:</p>
<p><img src="/assets/2015-06-16/view-debugging-xcode-before.png" alt="" /></p>
<p><img src="/assets/2015-06-16/view-debugging-xcode-after.png" alt="" /></p>
<p>And the code that made it possible:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#ifdef DEBUG
#import "WMLSwizzler.h"
static SEL wml_loadViewSEL;
static void wml_swizzleLoadViewForClass(Class class) {
typedef void(*load_view_t)(id, SEL);
__block load_view_t loadView = (load_view_t)[class S_replaceInstanceMethod:wml_loadViewSEL withBlock:^(UIViewController *self){
loadView(self, wml_loadViewSEL);
if (!self.isViewLoaded) {
return;
}
Class viewClass = [self.view class];
Class viewControllerClass = [self class];
// in case this method was called twice
if ([NSStringFromClass(viewClass) hasPrefix:NSStringFromClass(viewControllerClass)]) {
return;
}
NSString *viewClassName = viewClass == [UIView class] ?
[NSString stringWithFormat:@"%@.view", NSStringFromClass(viewControllerClass)] :
[NSString stringWithFormat:@"%@.view: %@", NSStringFromClass(viewControllerClass), NSStringFromClass(viewClass)];
Class newViewClass = NSClassFromString(viewClassName);
if (!newViewClass) {
newViewClass = objc_allocateClassPair(viewClass, [viewClassName cStringUsingEncoding:NSUTF8StringEncoding], 0);
objc_registerClassPair(newViewClass);
}
object_setClass(self.view, newViewClass);
}];
}
static BOOL const wml_isKindOfClass(Class class, Class possibleAncestor) {
if (class == possibleAncestor) {
return YES;
}
do {
class = class_getSuperclass(class);
if (class == possibleAncestor) {
return YES;
}
} while (class && class != [NSObject class]);
return NO;
}
@interface UIViewController (WMLViewDebugging)
@end
@implementation UIViewController (WMLViewDebugging)
+ (void)load {
@autoreleasepool {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
wml_loadViewSEL = @selector(loadView);
IMP originalIMP = [UIViewController instanceMethodForSelector:wml_loadViewSEL];
wml_swizzleLoadViewForClass([UIViewController class]);
unsigned int classesCount = 0;
Class *classList = objc_copyClassList(&classesCount);
for (unsigned int i = 0; i < classesCount; ++i) {
Class cls = classList[i];
const char *cClassName = class_getName(cls);
if (strcmp(cClassName, "JSExport") == 0 ||
strcmp(cClassName, "Object") == 0 ||
strcmp(cClassName, "__NSGenericDeallocHandler") == 0 ||
strcmp(cClassName, "__NSMessageBuilder") == 0 ||
strcmp(cClassName, "_NSZombie_") == 0){
continue;
}
// If you encounter crash here, add exception to the previous if case
if (cls == [UIViewController class] ||
!wml_isKindOfClass(cls, [UIViewController class]) ||
[cls instanceMethodForSelector:wml_loadViewSEL] == originalIMP) {
continue;
}
wml_swizzleLoadViewForClass(cls);
}
});
}
}
@end
#endif
</code></pre></div></div>
<p>Obviously this code is guarded to run only in <code class="language-plaintext highlighter-rouge">DEBUG</code>.</p>
<p>Although I can think of obscure cases when proposed solution might cause bugs, we’ve been using it in our app for a while and haven’t seen any problems yet. Please do tweet me if you can think of or will run into any issues!</p>
Generational analysis for tests2015-02-18T00:00:00+00:00http://blog.zats.io/2015/02/18/generational-analysis-for-tests<h1 id="tldr">TL;DR</h1>
<ul>
<li>Execute a typical scenario, returning to the original state.</li>
<li>Repeat the scenario several (≥ 4) times.</li>
<li>Call <code class="language-plaintext highlighter-rouge">-[LeaksInstrument measure]</code> after each run.</li>
<li>Assert on <code class="language-plaintext highlighter-rouge">-[LeaksInstrument hasLeaksInRepresentativeSession]</code> being falsy.</li>
</ul>
<p><a href="https://github.com/NSFW-Objective-C/Generational-Analysis">Source code</a></p>
<h1 id="intro">Intro</h1>
<p>Whether you test your code or not, you’ve probably heard of <a href="https://developer.apple.com/library/ios/recipes/Instruments_help_articles/FindingAbandonedMemory/FindingAbandonedMemory.html">generational analysis</a>. In short, it’s an invaluable tool that allows you to detect if you have a retain cycle or a leak, and some nasty objects are not being released when you expect them to. The way you can test it is:</p>
<ul>
<li>Run app, you’re profiling in Instruments.app.</li>
<li>Go through a logically complete flow and return to starting point.</li>
<li>Click “Mark generation”.</li>
<li>Repeat several times.</li>
</ul>
<p>What is a logically complete flow? That depends on what your app is doing. For example you’re building one-more-note-taking-app. You have a list of notes, tapping on a note takes you to the editing screen. In this case one of the possible flows would be:</p>
<ul>
<li>Start from the list view</li>
<li>Tap one of the notes</li>
<li>Edit it (preferably do the same editing every time)</li>
<li>Return back to the list</li>
</ul>
<p>Why would we want to run this several times? Well, depending on your app, first time you might need to warm up some caches and such. While the last time some objects might naturally still persist in memory - either due to autorelease scope, or a particular framework quirks. That’s why you want to take in account all the runs except for the first one and the last one.</p>
<p>As a good practise you should fire this tool once in a while and walk over your application checking if you introduce any retain cycles. While very useful, this can be quite annoying. Once, an iOS engineer told me how he wrote a test checking for retain cycle in a particular scenario. While we didn’t discuss any specifics, from what I understood there was a particular reference (let’s assume a view controller) that was not released. My assumption, is that the test was simply checking for a particular weak variable to turn <code class="language-plaintext highlighter-rouge">nil</code>:</p>
<div class="language-objectivec highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">__weak</span> <span class="n">id</span> <span class="n">obj</span> <span class="o">=</span> <span class="p">...;</span> <span class="c1">// this is what we expect to become nil if there are no retain cycles</span>
<span class="p">[</span><span class="n">self</span> <span class="nf">_executeScenario1</span><span class="p">];</span> <span class="c1">// our typical user-flow</span>
<span class="n">XCTAssertNil</span><span class="p">(</span><span class="n">obj</span><span class="p">);</span>
</code></pre></div></div>
<h1 id="automate-all-the-things">Automate all the things!</h1>
<p>Some time ago I stumbled upon a brilliant library by <a href="http://rheard.com/blog/">Richard Heard</a>, called <a href="https://github.com/heardrwt/RHObjectiveBeagle">Objective Beagle</a>. It is a great tool for debugging. It searches all allocated instances, and finds those, matching specified class. I figured that this is just what I needed. After slight refactoring, I had a running prototype, here is how to use it:</p>
<div class="language-objectivec highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">testLeakingExample</span> <span class="p">{</span>
<span class="n">XCTestExpectation</span> <span class="o">*</span><span class="n">leaksExpectation</span> <span class="o">=</span> <span class="p">[</span><span class="n">self</span> <span class="nf">expectationWithDescription</span><span class="p">:</span><span class="s">@"No leaks detected"</span><span class="p">];</span>
<span class="p">[</span><span class="n">self</span> <span class="nf">_runFlowNTimes</span><span class="p">:</span><span class="mi">5</span> <span class="nf">progressHandler</span><span class="p">:</span><span class="o">^</span><span class="p">{</span>
<span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">instrument</span> <span class="nf">measure</span><span class="p">];</span>
<span class="p">}</span> <span class="n">completionHandler</span><span class="o">:^</span><span class="p">{</span>
<span class="n">XCTAssertFalse</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">instrument</span><span class="p">.</span><span class="n">hasLeaksInRepresentativeSession</span><span class="p">,</span> <span class="s">@"%@"</span><span class="p">,</span> <span class="n">self</span><span class="p">.</span><span class="n">instrument</span><span class="p">);</span>
<span class="p">[</span><span class="n">leaksExpectation</span> <span class="nf">fulfill</span><span class="p">];</span>
<span class="p">}];</span>
<span class="p">[</span><span class="n">self</span> <span class="nf">waitForExpectationsWithTimeout</span><span class="p">:</span><span class="mi">10</span> <span class="nf">handler</span><span class="p">:</span><span class="nb">nil</span><span class="p">];</span>
<span class="p">}</span>
</code></pre></div></div>
<ol>
<li>We set up an expectation (new awesome feature of XCTest, works in pair with <code class="language-plaintext highlighter-rouge">waitForExpectationsWithTimeout:handler:</code>).</li>
<li>We run our test scenario (editing a note in the example above).</li>
<li>After finishing each run, we measure memory footprint with our <code class="language-plaintext highlighter-rouge">instrument</code></li>
<li>Finally, we assert on a property <code class="language-plaintext highlighter-rouge">hasLeaksInRepresentativeSession</code> returning <code class="language-plaintext highlighter-rouge">YES</code> if at least one leak was found.</li>
</ol>
<p>So all you need to do, is to implement your flow (<a href="https://github.com/kif-framework/KIF">KIF</a> or any BDD library might come handy), make sure you are returning into the starting point, measure the leaks after each run and assert on leaks once you finish.</p>
<p>Why do I believe this is a great test to have? As time passes by, you will add more features to your app or simply redesign underlying architecture. But until the flow exists, this test will make sure that your refactoring did not introduce any leaks.</p>
<h1 id="the-guts">The guts</h1>
<p>Now a bit more about the way it works internally. Every recorded session is being diffed against its predecessors, so it contains only the newly added leaks. While you can access <code class="language-plaintext highlighter-rouge">allSessions</code> to get list of leaks from all the measured sessions, most of the times, you want to use <code class="language-plaintext highlighter-rouge">representativeSessions</code> instead. As mentioned above, it returns only meaningful measurements, i.e. <code class="language-plaintext highlighter-rouge">allSessions</code> excluding the first and the last one.</p>
<p>Currently leaks are stored as weakly referenced objects in a <code class="language-plaintext highlighter-rouge">NSHashTable</code>. I’m still experimenting with it, but the current approach is that the instrument will not extend the lifecycle of the object whether it’s leaking or not. However, you might see the <code class="language-plaintext highlighter-rouge">hasLeaksInRepresentativeSession</code> returning <code class="language-plaintext highlighter-rouge">YES</code> while enumeration over the leaks in <code class="language-plaintext highlighter-rouge">representativeSessions</code> will return nothing.</p>
<p>Original implementation in Object Beagle goes to great length to avoid using private or potentially unsafe classes<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>. In the current implementation, I decided to workaround this problem by limiting classes to those coming from the <code class="language-plaintext highlighter-rouge">[UIBundle mainBundle]</code>. It is both an improvement and a limitation: e.g. current implementation will ignore classes from shared frameworks.</p>
<h1 id="todos">TODOs</h1>
<p>One of the biggest improvements possible would be to allow a more flexible <code class="language-plaintext highlighter-rouge">measure</code> call. E.g. if I know that every run of my scenario produces <code class="language-plaintext highlighter-rouge">X</code> objects of cache, I could’ve specified something like</p>
<div class="language-objectivec highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">instruments</span> <span class="nf">measureIgnoring</span><span class="p">:@{</span>
<span class="p">[</span><span class="n">XYZImageCache</span> <span class="nf">class</span><span class="p">]</span><span class="o">:</span> <span class="err">@</span><span class="p">(</span><span class="n">NSRangeMake</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">3</span><span class="p">))</span>
<span class="p">}];</span>
</code></pre></div></div>
<p>Where passed dictionary contains a map of classes to the range of instances I expect to persist.<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup> In this case, I expect from 0 to 3 instance of <code class="language-plaintext highlighter-rouge">XYZImageCache</code> to survive each run.</p>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:1" role="doc-endnote">
<p>for example if you try to call any method on <code class="language-plaintext highlighter-rouge">_NSZombie_</code> class you will explode. It’s a private class used, as you might’ve guessed, for detecting zombies. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p><code class="language-plaintext highlighter-rouge">@(NSRange...)</code> suppose to be <code class="language-plaintext highlighter-rouge">[NSValue valueWithRange:...]</code> <a href="#fnref:2" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
Let's build toll-free bridged class2015-02-14T00:00:00+00:00http://blog.zats.io/2015/02/14/lets-build-tollfree-bridged-class<p>Source code for this blog post can be found at github: https://github.com/NSFW-Objective-C/Toll-Free-Bridging</p>
<h2 id="intro">Intro</h2>
<p>You know technology is well executed when it disappears completely. <a href="http://developer.apple.com/library/ios/#documentation/CoreFoundation/Conceptual/CFDesignConcepts/Articles/tollFreeBridgedTypes.html">Toll-free bridging</a> is a great example of “invisible” technology. You’re using it extensively if you’re wiring any Objective-C code probably without even knowing it. So what is toll-free bridging?</p>
<blockquote>
<p>Data types that can be used interchangeably are also referred to as toll-free bridged data types.</p>
</blockquote>
<p>In Cocoa, often, by calling a certain method, you get a Core Foundation class where you expected an Objective-C class instead. The beauty is, you don’t even know about it: <code class="language-plaintext highlighter-rouge">array.count</code> works on <code class="language-plaintext highlighter-rouge">CFArrayRef</code> as well as on <code class="language-plaintext highlighter-rouge">NSArray</code>. Furthermore, <code class="language-plaintext highlighter-rouge">NSError</code>, <code class="language-plaintext highlighter-rouge">NSCalendar</code>, <code class="language-plaintext highlighter-rouge">NSLocale</code> and others extend the list of bridged classes beyond simple data structures.</p>
<p>The technology manifested itself as a migration path from Core Foundation to NeXTSTEP framework during the creation of the first version of Mac OS X. Apple wanted neither to through away, nor to port all the CF-goodness they accumulated over years<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>. One might think that technology should’ve served its purpose during the transitioning period, but obscure <a href="https://developer.apple.com/library/prerelease/ios/documentation/CoreFoundation/Reference/CFMutableStringRef/index.html#//apple_ref/c/func/CFStringTransform"><code class="language-plaintext highlighter-rouge">CFStringTransform</code></a>, flexible <a href="https://developer.apple.com/library/mac/documentation/CoreFoundation/Reference/CFMutableArrayRef/index.html#//apple_ref/c/func/CFArrayCreateMutable"><code class="language-plaintext highlighter-rouge">CFArrayCreateMutable</code></a> and many other APIs are still unmatched.</p>
<h2 id="creating-bridged-class">Creating bridged class</h2>
<p>If you’re not familiar with general way the technology works, I suggest reading <a href="https://mikeash.com/pyblog/friday-qa-2010-01-22-toll-free-bridging-internals.html">Mike Ash’s post</a>. One particular sentence stood out to me though:</p>
<blockquote>
<p>You can’t bridge an existing, unbridged CoreFoundation class because it requires massive cooperation on the CoreFoundation side.</p>
</blockquote>
<p>Fair enough, I though, after all, Apple is known for keeping their secrets well-guarded and internals untouchable. But I kept coming back to it over and over again, until, finally, I had a whole intercontinental flight to myself and nothing but 11 hours to kill.</p>
<p>There are several not bridged classes I could’ve chosen. But since <a href="https://developer.apple.com/documentation/CoreFoundation/Reference/CFBitVectorRef/index.html"><code class="language-plaintext highlighter-rouge">CFBitVectorRef</code></a> seemed a bit too esoteric for my day-to-day needs, I decided to go with <a href="https://developer.apple.com/library/prerelease/ios/documentation/CoreFoundation/Reference/CFBinaryHeapRef/index.html"><code class="language-plaintext highlighter-rouge">CFBinaryHeapRef</code></a><sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup>.</p>
<p>So just like you might’d guessed, this project was going to have two major pieces: making C API aware of Objective-C counterpart and vice versa.</p>
<h3 id="core-foundation">Core Foundation</h3>
<p>Here we simply need to “swizzle” C functions, and, after making sure the subject (a first argument in any CF API) is an Objective-C class, we’d call an appropriate method of our Objective-C API. Here is what <code class="language-plaintext highlighter-rouge">CFBinaryHeapGetCount</code> might look like:</p>
<div class="language-objectivec highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">CFIndex</span> <span class="nf">CFBinaryHeapGetCount</span><span class="p">(</span><span class="n">CFBinaryHeapRef</span> <span class="n">heap</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">CFGetTypeID</span><span class="p">(</span><span class="n">heap</span><span class="p">)</span> <span class="o">==</span> <span class="n">CFBinaryHeapGetTypeID</span><span class="p">())</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">_CFBinaryHeapGetCount</span><span class="p">(</span><span class="n">heap</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="p">(</span><span class="n">CFIndex</span><span class="p">)[(</span><span class="n">__bridge</span> <span class="n">BinaryHeap</span> <span class="o">*</span><span class="p">)</span><span class="n">heap</span> <span class="nf">count</span><span class="p">];</span>
<span class="p">}</span>
</code></pre></div></div>
<p>I used <a href="https://github.com/facebook/fishhook">fishhook</a> by Facebook to do just this. Although, implemented inline, it is quite tedious, and there is a room for preprocess macro optimisation left as an exercise for a reader.</p>
<h3 id="objective-c">Objective-C</h3>
<p>This part is quite easy, it boils down to symmetrical actions on Objective-C side: verifying that <code class="language-plaintext highlighter-rouge">self</code> is pointing to a CF instance, and, if so, calling corresponding CF function instead of my Objective-C implementation:</p>
<div class="language-objectivec highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">count</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">CFGetTypeID</span><span class="p">((</span><span class="n">__bridge</span> <span class="n">CFTypeRef</span><span class="p">)</span><span class="n">self</span><span class="p">)</span> <span class="o">==</span> <span class="n">CFBinaryHeapGetTypeID</span><span class="p">())</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">CFBinaryHeapGetCount</span><span class="p">((</span><span class="n">__bridge</span> <span class="n">CFBinaryHeapRef</span><span class="p">)</span><span class="n">self</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">_count</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Now, consider following code:</p>
<div class="language-objectivec highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">CFBinaryHeapRef</span> <span class="n">heap</span> <span class="o">=</span> <span class="n">CFBinaryHeapCreate</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="mi">64</span><span class="p">,</span> <span class="o">&</span><span class="n">callBacks</span><span class="p">,</span> <span class="o">&</span><span class="n">context</span><span class="p">);</span>
<span class="p">[(</span><span class="n">__bridge</span> <span class="n">BinaryHeap</span> <span class="o">*</span><span class="p">)</span><span class="n">heap</span> <span class="nf">addObject</span><span class="p">:</span><span class="mi">@20</span><span class="p">];</span>
</code></pre></div></div>
<p>Executing it at this point would cause a crash</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-[__NSCFType addObject:]: unrecognized selector sent to instance
</code></pre></div></div>
<h3 id="bridge">Bridge</h3>
<p>It is not too hard to see the tricky part. In the last snippet of <code class="language-plaintext highlighter-rouge">count</code> method for <code class="language-plaintext highlighter-rouge">self</code> to be an instance of <code class="language-plaintext highlighter-rouge">CFBinaryHeapRef</code> we have to send an Objective-C method to CF class. But Objective-C runtime is not aware of my plans to bridge two classes at this point. Somehow, I had to register my intention first. Looking through <a href="http://opensource.apple.com/source/CF/">Core Foundation Lite</a> gave me nothing. After all, bridging is a part of a secret souse. Once again, Hopper Disassembler<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup> to the rescue.</p>
<p>After a little research I found <code class="language-plaintext highlighter-rouge">void _CFRuntimeBridgeClasses(CFTypeID cfType, const char *className)</code> in <code class="language-plaintext highlighter-rouge">CoreFoundation.framework</code>. The way it works is brilliantly simple. It creates a lookup table between corresponding <code class="language-plaintext highlighter-rouge">CFTypeID</code> and a class. Now, since all CF instances are being created using <code class="language-plaintext highlighter-rouge">_CFRuntimeCreateInstance</code> function, its proprietary version includes a lookup through bridged classes table. If it finds a class, registered for bridging, it makes sure that Objective-C will trampoline all method calls to the corresponding class (i.e. <code class="language-plaintext highlighter-rouge">-[CFArrayRef count]</code> would effectively become <code class="language-plaintext highlighter-rouge">-[NSArray count]</code>).</p>
<p>So, all we had to do to leverage all the goodness is:</p>
<div class="language-objectivec highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">_CFRuntimeBridgeClasses</span><span class="p">(</span><span class="n">CFBinaryHeapGetTypeID</span><span class="p">(),</span> <span class="n">class_getName</span><span class="p">([</span><span class="n">BinaryHeap</span> <span class="nf">class</span><span class="p">]));</span>
</code></pre></div></div>
<p>After that, code above “magically” started to forward messages to Objective-C.</p>
<h2 id="quirks">Quirks</h2>
<p>Following are several interesting observations I’ve made during this experiment.</p>
<h3 id="tail-optimisation">Tail optimisation</h3>
<p>If you are to break in any bridged method that has been called on a CF class, you won’t see anything in the stack trace between the caller and the implementation. CF uses <code class="language-plaintext highlighter-rouge">objc_setClass</code> in a proprietary version of <code class="language-plaintext highlighter-rouge">_CFRuntimeCreateInstance</code>, mentioned above. That’s why to the runtime it’s equivalent of calling a regular method where implicit first argument, representing <code class="language-plaintext highlighter-rouge">self</code> is replaced with CF instance. So as for performance overhead, it’s negligible.</p>
<h3 id="structure">Structure</h3>
<p>As we know from Objective-C runtime<sup id="fnref:4" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">4</a></sup>, <code class="language-plaintext highlighter-rouge">NSObject</code> has one ivar called <code class="language-plaintext highlighter-rouge">isa</code><sup id="fnref:5" role="doc-noteref"><a href="#fn:5" class="footnote" rel="footnote">5</a></sup> that points to the Class, representing the instance. All CF classes designed to match <code class="language-plaintext highlighter-rouge">NSObject</code>’s basic ivars structure and to point to <code class="language-plaintext highlighter-rouge">__NSCFType</code> in the <code class="language-plaintext highlighter-rouge">isa</code> field<sup id="fnref:6" role="doc-noteref"><a href="#fn:6" class="footnote" rel="footnote">6</a></sup>. So the actual magic of <code class="language-plaintext highlighter-rouge">_CFRuntimeBridgeClasses</code> is to simply call <code class="language-plaintext highlighter-rouge">object_setClass</code> with a registered bridged class, effectively replacing <code class="language-plaintext highlighter-rouge">isa</code>’s pointer from <code class="language-plaintext highlighter-rouge">__NSCFType</code> to let’s say <code class="language-plaintext highlighter-rouge">__NSCFArray</code>.</p>
<h3 id="mutability">Mutability</h3>
<p>Now, when we know how to register a class with toll-free bridging system, you might want to know how exactly does it work with mutable and immutable counterpart? After all, both for <code class="language-plaintext highlighter-rouge">CFGetTypeID(cfStr)</code> and <code class="language-plaintext highlighter-rouge">CFGetTypeID(cfMutableStr)</code> return the same <code class="language-plaintext highlighter-rouge">CFStringGetTypeID</code>. Given, that this is a key for lookup of a bridged Objective-C class to forward method calls to, it might be a bit confusing at first how does it differentiate between mutable and immutable versions. I realised this problem while porting <code class="language-plaintext highlighter-rouge">CFBitVectorRef</code> since it has both flavours. Solution is obvious though: we have to register against mutable Objective-C class. And, while a bit surprising, <code class="language-plaintext highlighter-rouge">__NSCFString</code><sup id="fnref:7" role="doc-noteref"><a href="#fn:7" class="footnote" rel="footnote">7</a></sup>, is, in reality, a subclass of <code class="language-plaintext highlighter-rouge">NSMutableString</code>.</p>
<hr />
<p>As an epilogue, I have to admit that this is more of an exercise, sole purpose of which is to test what’s possible and to better understand the technology we use every day. As for practical applications, I don’t see that many, but it never stopped me from writing code before.</p>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:1" role="doc-endnote">
<p>For more details, read the post by Peter Ammon http://ridiculousfish.com/blog/posts/bridge.html <a href="#fnref:1" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>Often implemented as maximum (minimum) heap. For more information, see http://en.wikipedia.org/wiki/Priority_queue <a href="#fnref:2" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:3" role="doc-endnote">
<p>This is an unmatched tool if you’re curious to learn about how Objective-C code works, but you don’t have sources to a particular binary. If you’re into this kind of adventures, definitely check it out http://www.hopperapp.com. <a href="#fnref:3" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:4" role="doc-endnote">
<p>The open source flavour of it http://opensource.apple.com/source/objc4 <a href="#fnref:4" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:5" role="doc-endnote">
<p>Not to mention tagged pointers and Apple discouraging you using <code class="language-plaintext highlighter-rouge">isa</code> directly. <a href="#fnref:5" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:6" role="doc-endnote">
<p>See <code class="language-plaintext highlighter-rouge">CFRuntimeBase</code> in Core Foundation Lite http://opensource.apple.com/source/CF/CF-855.17/CFRuntime.h. <a href="#fnref:6" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:7" role="doc-endnote">
<p><code class="language-plaintext highlighter-rouge">__NSCFString</code> is a private subclass of <code class="language-plaintext highlighter-rouge">NSString</code>, responsible for solely for bridging with <code class="language-plaintext highlighter-rouge">CFStringRef</code>. <a href="#fnref:7" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
Target-action for non-ui components. There is an easier way!2014-12-23T00:00:00+00:00http://blog.zats.io/2014/12/23/target-action-for-non-ui<h1 id="tldr">TL;DR</h1>
<p>Use <code class="language-plaintext highlighter-rouge">-[UIApplication sendAction:to:from:forEvent:]</code> instead of calling action on target directly if you want responder chain behaviour for free.</p>
<h1 id="typical-target-action-pattern">Typical target-action pattern</h1>
<p>Often enough, I found myself using this pattern to communicate between a non-ui objects. A simple case might look like this:</p>
<pre><code class="language-objective-c">@interface Foo : NSObject
@property (nonatomic, weak) id target;
@property (nonatomic) SEL action;
@end
// somehwere in .m
@implementation Foo
- (void)bar {
[self.target performSelector:self.action];
}
@end
</code></pre>
<p>Several details worth mentioning here:</p>
<ul>
<li>Your target <strong>must</strong> be weak, it’s no different from delegate.</li>
<li>Calling selector on a target requires either silencing the compiler complaining (reasonably so) about ARC not knowing semantics of the call.</li>
<li>You can get away with using <code class="language-plaintext highlighter-rouge">NSInvocation</code> or other technics instead.</li>
</ul>
<p>Now, let’s take a look at <code class="language-plaintext highlighter-rouge">UIControl</code> behaviour. You probably noticed how <code class="language-plaintext highlighter-rouge">-[UIControl addTarget:action:forControlEvents:]</code> accepts <code class="language-plaintext highlighter-rouge">nil</code> as a target parameter. What happens then is control, upon firing the event, will walk the responder chain starting from the <code class="language-plaintext highlighter-rouge">firstResponder</code> up to <code class="language-plaintext highlighter-rouge">UIWindow</code>, looking for someone who can handle specified <code class="language-plaintext highlighter-rouge">action</code>. This is what happening when you drag action to the first responder in your storyboard or nib files.</p>
<h1 id="uikit-to-the-rescue">UIKit to the rescue!</h1>
<p>So how do we get this behaviour without traversing responder chain manually?<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup> Luckily, apple got us covered, and, this time, it’s relatively straight forward. Let’s modify our example above:</p>
<pre><code class="language-objective-c">// somehwere in .m
@implementation Foo
- (void)bar {
[[UIApplication sharedApplication] sendAction:self.action to:self.target from:self forEvent:nil];
}
@end
</code></pre>
<p>As a bonus you can use one of following forms for action for free:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">- (void)action</code></li>
<li><code class="language-plaintext highlighter-rouge">- (void)action:(id)sender</code></li>
<li><code class="language-plaintext highlighter-rouge">- (void)action:(id)sender forEvent:(UIEvent *)event</code></li>
</ul>
<p>UIKit takes care of passing the right parameters for you!</p>
<p>In my example, I consider writing a non-ui feature, so I’m passing <code class="language-plaintext highlighter-rouge">nil</code> as the event. However, you can create a custom subclass of <code class="language-plaintext highlighter-rouge">UIEvent</code> and pass required data with it. Modifying type of the event parameter to a subclass in the <code class="language-plaintext highlighter-rouge">- action:forEvent:</code> feels a bit dirty though.</p>
<p>This technic allows a less-coupled design. However, you should be careful and try to avoid creating a mess of unidentified actions flying around a-la NSNotification-hell</p>
<p><strong>Note</strong> as it was mentioned, this technic is not a replacement for appropriate communication patterns such as delegation, notifications, blocks handlers etc. It’s one of many tools that you might want to use but you should evaluate in the context of a particular task.</p>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:1" role="doc-endnote">
<p>which is, apparently, not that easy on iOS http://optshiftk.com/2014/08/implementing-uiapplication-targetforactiontofrom <a href="#fnref:1" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
Optimizing tests running time2014-12-19T00:00:00+00:00http://blog.zats.io/2014/12/19/optimizing-tests<p>In our app we run a mix of unit, functional and integration tests, for example:</p>
<ul>
<li>Credit card validator is a unit test.</li>
<li>Tapping menu items takes you to the right section is a functional test.</li>
<li>Tapping a product, adding it to cart and going through all of the purchase steps is an integration test.</li>
</ul>
<p>While it’s widely acceptable to stub and mock for unit and functional tests, it’s not such a good idea for integration tests. Our previous setup included 3 different test targets one per test type, so you’re free to setup environment in a way that makes sense for a particular groups of tests. However it caused long build times and as a result, our CI machine was constantly busy building client, increasing latency between, let’s say, a pool request being submitted and confirmation that it’s safe to merge PR.</p>
<h1 id="optimization-merging-test-targets">Optimization: merging test targets.</h1>
<p>I decided to try out a different approach: to merge all the test targets into one. As a result we got faster build times: no need in building 3 targets, no need in restarting app (or simulator). Of course, you have to be more careful with stubs now. It’s not enough to just stub all the networking calls and leave stubs in place, you should carefully remove them once your test finished running.</p>
<p>There is another detail that added a complexity with this new approach. On the startup our app loads certain information while displaying a modal splash screen. This is not an ideal approach, but until it’s addressed, we have to work around with it. Integration tests use to wait for the absence of splash screen (using <a href="https://github.com/kif-framework/KIF">KIF</a>) before tapping around. Obviously, this solution worked because all the integration tests would be isolated into a separate target. Once all targets were merged, that caused an undesirable delay, affecting both unit and functional tests that do not need app to start in its “natural” way.</p>
<h1 id="rearranging-tests">Rearranging tests.</h1>
<p>So who is in charge of running all the tests? XCTest is not the most documented framework, so <a href="http://www.hopperapp.com">Hopper Disassembler</a> to the rescue! After poking around a bit, I learned, that <code class="language-plaintext highlighter-rouge">+[XCTestSuite defaultTestSuite]</code> is the method called to get the list of the tests. It returns a test suite containing all test targets with all tests enabled in the scheme configuration. Funny enough, in this case, all the knowledge turned out to be public: <code class="language-plaintext highlighter-rouge">tests</code> array contains all the tests and is backed by a <code class="language-plaintext highlighter-rouge">NSMutableArray *_tests</code> ivar.</p>
<h1 id="solution">Solution.</h1>
<p>By simply swizzling <code class="language-plaintext highlighter-rouge">defaultTestSuite</code> and sorting <code class="language-plaintext highlighter-rouge">tests</code> property to contain unit and functional tests at the beginning is enough to prioritize the tests that do not depend on the app state:</p>
<div class="language-objectivec highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">XCTestSuite</span> <span class="o">*</span><span class="n">defaultTestSuite</span> <span class="o">=</span> <span class="p">((</span><span class="n">XCTestSuite</span> <span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="p">)(</span><span class="n">id</span><span class="p">))</span><span class="n">originalImp</span><span class="p">)(</span><span class="n">self</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="n">XCTestSuite</span> <span class="o">*</span><span class="n">testSuite</span> <span class="k">in</span> <span class="n">defaultTestSuite</span><span class="p">.</span><span class="n">tests</span><span class="p">)</span> <span class="p">{</span>
<span class="n">NSMutableArray</span> <span class="o">*</span><span class="n">allTestsArray</span> <span class="o">=</span> <span class="p">[</span><span class="n">testSuite</span> <span class="nf">valueForKey</span><span class="p">:</span><span class="s">@"_tests"</span><span class="p">];</span>
<span class="p">[</span><span class="n">allTestsArray</span> <span class="nf">sortUsingComparator</span><span class="p">:</span><span class="o">^</span><span class="n">NSComparisonResult</span><span class="p">(</span><span class="n">XCTestSuite</span> <span class="o">*</span><span class="n">test1</span><span class="p">,</span> <span class="n">XCTestSuite</span> <span class="o">*</span><span class="n">test2</span><span class="p">)</span> <span class="p">{</span>
<span class="n">BOOL</span> <span class="n">isTest1UnitTest</span> <span class="o">=</span> <span class="n">test1</span><span class="p">.</span><span class="n">wml_isUnitTest</span><span class="p">;</span>
<span class="n">BOOL</span> <span class="n">isTest2UnitTest</span> <span class="o">=</span> <span class="n">test2</span><span class="p">.</span><span class="n">wml_isUnitTest</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">isTest1UnitTest</span> <span class="o">&&</span> <span class="o">!</span><span class="n">isTest2UnitTest</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">NSOrderedAscending</span><span class="p">;</span>
<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">isTest1UnitTest</span> <span class="o">&&</span> <span class="n">isTest2UnitTest</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">NSOrderedDescending</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">NSOrderedSame</span><span class="p">;</span>
<span class="p">}];</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">defaultTestSuite</span><span class="p">;</span>
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">-[XCTestSuite wml_isUnitTest]</code> is simply looking for a word <code class="language-plaintext highlighter-rouge">UnitTest</code> in the class name. Convention over configuration.</p>
<p><strong>Update</strong>: as it was pointed out, it’s quite easy to optimize the implementation and find a better point of swizzling. This is just a first implementation.</p>
<p>Without violating principle of tests not depending on one another, we gained a speed boost that will only increase as we grow number of tests.</p>
Whose symbol is this?2014-10-25T00:00:00+00:00http://blog.zats.io/2014/10/25/whose-symbol-is-this<p>Once in a while I found myself in need of finding who declared certain function or method. With Apple added support for iOS frameworks, the need in being sure where particular piece of code is coming is somewhat high.</p>
<pre><code class="language-objective-c">#import <dlfcn.h>
</code></pre>
<h1 id="function">Function</h1>
<pre><code class="language-objective-c">Dl_info info;
if (dladdr((void *)NSStringFromClass, &info)) {
printf("%s", info.dli_fname);
}
</code></pre>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>…/Frameworks/Foundation.framework/Foundation
</code></pre></div></div>
<h1 id="method">Method</h1>
<pre><code class="language-objective-c">IMP imp = [view methodForSelector:@selector(drawRect:)];
Dl_info info;
if (dladdr((void *)imp, &info)) {
printf("%s", info.dli_fname);
}
</code></pre>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>…/Frameworks/UIKit.framework/UIKit
</code></pre></div></div>
<p>Keep in mind that <code class="language-plaintext highlighter-rouge">methodForSelector:</code> resolves implementation that’d be actually called at runtime.
If you want to trace down an original implementation (e.g. before swizzling), it all boils down to finding (keeping) the right <code class="language-plaintext highlighter-rouge">IMP</code>:</p>
<h1 id="swizzled-methods">Swizzled methods</h1>
<pre><code class="language-objective-c">// after swizzling, our implementation can be reached through orignial selector
// and original implementation can be reached through our swzld_ selector
IMP swizzledIMP = [self methodForSelector:@selector(viewDidLoad)];
IMP originalIMP = [self methodForSelector:@selector(swzld_viewDidLoad)];
Dl_info info;
if (dladdr((void *)swizzledIMP, &info)) {
printf("%s\n", info.dli_fname);
}
if (dladdr((void *)originalIMP, &info)) {
printf("%s", info.dli_fname);
}
</code></pre>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>…/Test.app/Test
…/Frameworks/UIKit.framework/UIKit
</code></pre></div></div>
<p>Sadly you can not trace the origins of declarations, e.g. I couldn’t figure out how to find out who declared <code class="language-plaintext highlighter-rouge">-[UIApplicationDelegate applicationDidFinishLaunching:]</code></p>
<h1 id="keep-in-mind">Keep in mind</h1>
<p>If you mistype selector when obtaining implementation, you’ll get a confusing <code class="language-plaintext highlighter-rouge">…/usr/lib/libobjc.A.dylib</code> as an originating binary.</p>
<p>This is due to the fact that <code class="language-plaintext highlighter-rouge">methodForSelector:</code> short-circuits to <code class="language-plaintext highlighter-rouge">-[NSObject doesNotRecognizeSelector]</code>, which, as you probably guessed by now, is declared in Objective-C runtime.</p>
<h1 id="blocks">Blocks</h1>
<p>Finally, much more rare case of getting a pointer to a block and tracing its origin back to the binary. As turns out, it’s no different from a function:</p>
<pre><code class="language-objective-c">void(^block)(NSUInteger) = ^(NSUInteger a){
NSLog(@"%tu", a);
};
Dl_info info;
if (dladdr((__bridge void *)block, &info)) {
printf("%s", info.dli_fname);
}
</code></pre>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>…/Test.app/Test
</code></pre></div></div>
<h1 id="bonus">Bonus</h1>
<p>As a bonus though, here is a snippet on how to print names of all the loaded frameworks at runtime without:</p>
<pre><code class="language-objective-c">unsigned int imagesCount;
const char **bundles = objc_copyImageNames(&imagesCount);
for (unsigned int i = 0; i < imagesCount; ++i) {
printf("%s", bundles[i]);
}
</code></pre>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>…/usr/lib/system/introspection/libdispatch.dylib
…/usr/lib/system/libxpc.dylib
…/usr/lib/system/libsystem_network.dylib
…/usr/lib/libobjc.A.dylib
…/System/Library/Frameworks/Accelerate.framework/Frameworks/vecLib.framework/libLinearAlgebra.dylib
…/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation
…/System/Library/PrivateFrameworks/FontServices.framework/libFontParser.dylib
…/usr/lib/libextension.dylib
…/System/Library/Frameworks/CFNetwork.framework/CFNetwork
…/System/Library/Frameworks/MobileCoreServices.framework/MobileCoreServices
…/System/Library/Frameworks/Foundation.framework/Foundation
…/System/Library/Frameworks/JavaScriptCore.framework/JavaScriptCore
…/System/Library/PrivateFrameworks/AggregateDictionary.framework/AggregateDictionary
</code></pre></div></div>
<p>It returns a full list of names that can be used with <code class="language-plaintext highlighter-rouge">dlfcn</code> functions making it useful for further investigations.</p>
A backport of NSProcessInfo isOperatingSystemAtLeastVersion2014-10-19T00:00:00+00:00http://blog.zats.io/2014/10/19/NSProcessInfo-isOperatingSystemAtLeastVersion-backport<p>Make sure it’s added to the current target, the class will take care of everything else.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>@implementation NSProcessInfo (WMLCompatibility)
+ (void)wml_addSelector:(SEL)originalSelector implementedWithSelector:(SEL)newSelector {
if (![self instancesRespondToSelector:originalSelector]) {
Method newMethod = class_getInstanceMethod(self, newSelector);
class_addMethod(self, originalSelector, method_getImplementation(newMethod), method_getTypeEncoding(newMethod));
}
}
+ (void)load {
@autoreleasepool {
if (![self isSubclassOfClass:[NSProcessInfo class]]) {
return;
}
[self wml_addSelector:@selector(operatingSystemVersion)
implementedWithSelector:@selector(wml_operatingSystemVersion)];
[self wml_addSelector:@selector(isOperatingSystemAtLeastVersion:)
implementedWithSelector:@selector(wml_isOperatingSystemAtLeastVersion:)];
}
}
- (NSOperatingSystemVersion)wml_operatingSystemVersion {
static NSOperatingSystemVersion version;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSArray *components = [[UIDevice currentDevice].systemVersion componentsSeparatedByString:@"."];
if (components.count > 0) {
version.majorVersion = [components[0] integerValue];
if (components.count >= 2) {
version.minorVersion = [components[1] integerValue];
if (components.count >= 3) {
version.patchVersion= [components[2] integerValue];
}
}
}
});
return version;
}
- (BOOL)wml_isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion)version {
NSOperatingSystemVersion myVersion = self.operatingSystemVersion;
if (myVersion.majorVersion > version.majorVersion) {
return YES;
} else if (myVersion.majorVersion == version.majorVersion) {
if (myVersion.minorVersion > version.minorVersion) {
return YES;
} else if (myVersion.minorVersion == version.minorVersion) {
return myVersion.patchVersion >= version.patchVersion;
}
}
return NO;
}
@end
</code></pre></div></div>
Setting structures in Objective-C2014-10-02T00:00:00+00:00http://blog.zats.io/2014/10/02/structure-setter<p>You know how you always do this little dance to update couple of values on a structure property</p>
<pre><code class="language-objective-c">CGRect frame = self.view.frame;
frame.size.width = 100;
frame.origin.y = 30;
self.view.frame = frame;
</code></pre>
<p>There is a better way!</p>
<p>First, let’s start with a sligtly better way. If you don’t want to polute your scope with temporary variables (let’s say you have to change five different view’s frames)</p>
<pre><code class="language-objective-c">self.view.frame = ({
CGRect frame = self.view.frame;
frame.size.width = 100;
frame.origin.y = 30;
frame;
});
</code></pre>
<p>This code utilizes C feature of scopes but looks kind of ugly. That’s where C macros can help:</p>
<pre><code class="language-objective-c">#define WMLSetStructure(object, key, setterBlock) ({\
if (NO) {(void)((object).key);}\
object.key = ({\
typeof(object.key) key = object.key;\
setterBlock;\
key;\
});\
})
</code></pre>
<p>Here is how to use it</p>
<pre><code class="language-objective-c">WMLSetStructure(self.view, frame, {
frame.origin.y = 30;
frame.size.width = 100;
});
WMLSetStructure(self.mapView, region, {
region.center.longitude -= 0.0001;
region.span.latitudeDelta += 3.1415;
});
</code></pre>
<p>It creates a local vairable with the same name as the property and returns it at the end of the scope.</p>
<p>The only thing I don’t like about it is the need to separate object with key, I do it to provide you with the variable with the same name as the key in the setter scope.</p>
<p>Oh and see that line</p>
<pre><code class="language-objective-c">if (NO) {(void)((object).key);}
</code></pre>
<p>it helps to autocompete key according to the list of properties this object has.</p>
Advanced NSProxy2014-07-15T00:00:00+00:00http://blog.zats.io/2014/07/15/advanced-nsproxy<p>Imagine your <code class="language-plaintext highlighter-rouge">Dog</code> class has a following method:</p>
<pre><code class="language-objective-c">- (void)greetIfAwake {
if ([self isAwake]) {
[self bark];
[self jump];
}
}
</code></pre>
<p>Now imagine a mischievous <code class="language-plaintext highlighter-rouge">Cat</code> (a subclass of <code class="language-plaintext highlighter-rouge">NSProxy</code> obviously) wishing to get in a way…</p>
<p>Normally your flow would looks like this:</p>
<p><img src="/assets/nsproxy-flow/regular-nsproxy-flow.svg" alt="regular NSProxy flow" /></p>
<p>But what if we want to alter it to be more like this:</p>
<p><img src="/assets/nsproxy-flow/advanced-nsproxy-flow.svg" alt="advanced NSProxy flow" /></p>
<p>e.g. every time method on <code class="language-plaintext highlighter-rouge">self</code> is invoked, we want our proxy to be consulted prior to execution.</p>
<p><strong>TL;DR</strong> version can be found in <a href="https://gist.github.com/zats/c74f38fd5658970d5060">this gist</a></p>
<h1 id="spoofing-self">Spoofing <code class="language-plaintext highlighter-rouge">self</code></h1>
<p>First, let’s replace <code class="language-plaintext highlighter-rouge">self</code> within the scope of the original method. As you know, <code class="language-plaintext highlighter-rouge">self</code> is nothing more than a convention: it’s a regular reference passed to each method as a first implicit argument (so it doesn’t affect user-defined arguments). Normally, replacing an argument would be as easy as calling <code class="language-plaintext highlighter-rouge">[invocation setArgument:&argument atIndex:index];</code>, but, as I mentioned, <code class="language-plaintext highlighter-rouge">self</code> is a special one. If we follow a regular <code class="language-plaintext highlighter-rouge">forwardInvocation:</code> pattern, <code class="language-plaintext highlighter-rouge">invocation.target</code> is used to find receiver for <code class="language-plaintext highlighter-rouge">invocation.selector</code> and becomes <code class="language-plaintext highlighter-rouge">self</code> within the scope of the implementation.</p>
<pre><code class="language-objective-c">- (void)forwardInvocation:(NSInvocation *)invocation {
[invocation invokeWithTarget:self.originalObject];
}
</code></pre>
<h2 id="forwarding-invocation">Forwarding invocation</h2>
<p><a href="https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/Reference/Reference.html#//apple_ref/occ/instm/NSObject/forwardInvocation:">Documentation</a> is not clear on the topic of calling <code class="language-plaintext highlighter-rouge">forwardInvocation:</code> directly on <code class="language-plaintext highlighter-rouge">NSObject</code> subclasses.</p>
<p>Objective C <a href="http://www.opensource.apple.com/source/objc4/objc4-551.1/runtime/NSObject.mm">runtime code</a> states that <code class="language-plaintext highlighter-rouge">- [NSObject forwardInvocation:]</code> simply calls <code class="language-plaintext highlighter-rouge">doesNotRecognizeSelector:</code> however, iOS Simulator version of <code class="language-plaintext highlighter-rouge">libobjc.dylib</code> actually calls the original selector if it’s found instead. Therefore</p>
<pre><code class="language-objective-c">- (void)forwardInvocation:(NSInvocation *)invocation {
[self.originalObject forwardInvocation:invocation];
}
</code></pre>
<p>works on simulator but throws an exception on devices. I wonder what is the reason to have such a dramatic difference runtime versions.</p>
<h2 id="a-private-way">A private way</h2>
<p>Obviously, I want my code to run both on simulator and on a real device. For that we will need to dive into private <code class="language-plaintext highlighter-rouge">NSInvocation</code> API:</p>
<pre><code class="language-objective-c">@interface NSInvocation ()
- (void)invokeUsingIMP:(IMP)implementation;
@end
@implementation Cat
- (void)forwardInvocation:(NSInvocation *)invocation {
Method method = class_getInstanceMethod(object_getClass(self.originalObject), invocation.selector);
IMP implementation = method_getImplementation(method);
[invocation invokeUsingIMP:implementation];
}
@end
</code></pre>
<p>Here we have a bit more explicit story: invocation was clearly designated for our <code class="language-plaintext highlighter-rouge">NSProxy</code> subclass but instead of <code class="language-plaintext highlighter-rouge">invokeWithTarget:</code> that figures out implementation of specified <code class="language-plaintext highlighter-rouge">selector</code> for you, we take over and supplying implementation we believe is right. Besides, this approach works both with simulator and devices.</p>
<p>The downside is the usage of a private API. So, once again, this is definitely not an App Store-friendly code. However, at this point we can spoof <code class="language-plaintext highlighter-rouge">self</code> on any method.</p>
<h1 id="ivars">Ivars</h1>
<p>Another challenge when spoofing <code class="language-plaintext highlighter-rouge">self</code> lies in synthesized properties. Consider following implementation of <code class="language-plaintext highlighter-rouge">hasEnoughFuel</code> from our initial example:</p>
<pre><code class="language-objective-c">- (BOOL)isAwake {
return !self.isAsleep || self.isPlayingDead;
}
</code></pre>
<p>Our proxy code is going to crash due to ivar access. Here is autosynthesized implementation of <code class="language-plaintext highlighter-rouge">isPlayingDead</code> getter:</p>
<pre><code class="language-objective-c">- (BOOL)isPlayingDead {
return self->_playingDead;
}
</code></pre>
<p>which is what compiler turns your <code class="language-plaintext highlighter-rouge">_playingDead</code> ivar access statements into. You might remember it from accessing ivars from within certain blocks, when compiler warns you that <code class="language-plaintext highlighter-rouge">self->_ivar</code> might create a retain cycle.</p>
<p>Now let’s step aside for a second, how did we get here? What does the <code class="language-plaintext highlighter-rouge">-></code> operator have to do with our objective oriented world? All the classes in objective-c are pointers to structures, since <code class="language-plaintext highlighter-rouge">Class</code> is a merely <code class="language-plaintext highlighter-rouge">typedef struct objc_class *Class;</code>, we’re basically operating on struct pointers. Ivars are nothing more than additional fields in the struct. And since Objective C is a strict superset of C, nothing stops us from accessing those fields directly just like this:</p>
<pre><code class="language-objective-c">CGRect rect = CGSizeMake(3, 14, 15, 92);
CGRect *rectPointer = &rect;
rectPointer->size = (CGSize){65, 35};
</code></pre>
<p>All we have to do is just to detect <code class="language-plaintext highlighter-rouge">-></code> operator being used on our “fake” <code class="language-plaintext highlighter-rouge">self</code> instance. I don’t know a first thing about operators overloading (which seems possible with Objective C++). However I was interested in the solution from Objective C domain.</p>
<h1 id="dynamic-subclassing">Dynamic subclassing</h1>
<p>One of the benefits of Objective C is ability to create classes at runtime. Now all I need is to create a right superclass to inherit from. Barebones of the <code class="language-plaintext highlighter-rouge">DynamicProxy</code> are quite trivial: forwarding <code class="language-plaintext highlighter-rouge">respondsToSelector:</code> and <code class="language-plaintext highlighter-rouge">methodSignatureForSelector:</code> to the original object and call implementation of the original object in <code class="language-plaintext highlighter-rouge">forwardInvocation:</code> just as we discussed before.</p>
<p>Next we create a subclass for supplied <code class="language-plaintext highlighter-rouge">originalObject</code>. Here we have two options.</p>
<h2 id="kvos-way">KVO’s way</h2>
<p>First one is to use function called when you register first KVO observer on an instance, <code class="language-plaintext highlighter-rouge">objc_duplicateClass</code>:</p>
<pre><code class="language-objective-c">static inline Class DynamicProxyClassForClass(Class objectClass) {
Class baseClass = [DynamicProxy class];
NSString *newClassName = [NSString stringWithFormat:@"%@_%@", objectClass, baseClass];
Class dynamicProxyClass = objc_duplicateClass(objectClass, [newClassName UTF8String], 0);
class_setSuperclass(dynamicProxyClass, baseClass);
return dynamicProxyClass;
}
</code></pre>
<p>This is a fairly straight forward solution except for the <code class="language-plaintext highlighter-rouge">class_setSuperclass</code> which is deprecated, although being by Foundation’s KVO itself. Besides <code class="language-plaintext highlighter-rouge">objc_duplicateClass</code> has a warning next to it “Used by Foundation’s Key-Value Observing. Do not call this function yourself”. Which brings us to</p>
<h2 id="a-proper-way">A proper way</h2>
<p>Creating a new subclass from scratch, at runtime:</p>
<pre><code class="language-objective-c">static inline Class DynamicProxyClassForClass(Class objectClass) {
Class baseClass = [DynamicProxy class];
NSString *newClassName = [NSString stringWithFormat:@"%@_%@", objectClass, baseClass];
Class dynamicProxyClass = objc_allocateClassPair(baseClass, [newClassName UTF8String], 0);
class_setIvarLayout(dynamicProxyClass, class_getIvarLayout(objectClass));
class_setWeakIvarLayout(dynamicProxyClass, class_getWeakIvarLayout(objectClass));
CopyAllIvars(objectClass, dynamicProxyClass);
objc_registerClassPair(dynamicProxyClass);
return dynamicProxyClass;
}
</code></pre>
<p>Here we have a bit more going on, but it’s all fairly standard class allocation / registration dance except, probably, for copying ivar layouts and ivars (<code class="language-plaintext highlighter-rouge">CopyAllIvars</code>) from the object class over to the new dynamic class. Without copying layouts and ivars from the base class we will crash every time we’re trying to access them.</p>
<h1 id="making-it-all-click">Making it all click</h1>
<p>The only thing that left to do is to copy all the ivar values from original class over to the dynamic proxy prior to execution of any method to copy them back after (that is if you want original object to be in sync with our proxy). Sadly designated <code class="language-plaintext highlighter-rouge">object_setIvar</code> / <code class="language-plaintext highlighter-rouge">object_getIvar</code> pair doesn’t handle ivars of primitive types. This is why I had to implement my own set ivar method</p>
<pre><code class="language-objective-c">static inline void SetIvar(id destination, Ivar ivar, void *originalValue) {
ptrdiff_t ivarOffset = ivar_getOffset(ivar);
void **ivarPosition = ((__bridge void*)destination + ivarOffset);
*ivarPosition = originalValue;
}
</code></pre>
<p>Consider implementing some sort of <code class="language-plaintext highlighter-rouge">-[DynamicProxy performWithoutUpdatingIvars:]</code> method so you can avoid this behavior when necessary.</p>
<h1 id="a-word-of-warning-ivars-in-a-base-class">A word of warning: ivars in a base class</h1>
<p>I tried several approaches to make ivars in <code class="language-plaintext highlighter-rouge">DynamicProxy</code> play nicely with our dynamic subclass. When I would set first ivar from an original class on my proxy it would override first ivar from the proxy’s superclass. My guess is that pointer math doesn’t add up, so I used an old trick from the categories book: implementing properties using associated objects, e.g.:</p>
<pre><code class="language-objective-c">- (void)setZts_object:(id)zts_object {
objc_setAssociatedObject(self, @selector(zts_object), zts_object, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (id)zts_object {
return objc_getAssociatedObject(self, @selector(zts_object));
}
</code></pre>
<p>You really should prefix your properties with whatever <code class="language-plaintext highlighter-rouge">xyz</code> you prefer, since you never know which class are you going to copy over.</p>
<h1 id="afterword">Afterword</h1>
<p>Although it seems like a highly theoretical excursive, this technic might be a useful for partial mocking or just for cases when you want to proxy all calls to a particular instance of a class, not just the initial one performed on the proxy directly. Although, I have to acknowledge, this code most likely does not belong to your App Store branch, it is still highly useful for unit tests and debugging purposes.</p>
Signing ipa for different team ids2014-07-02T00:00:00+00:00http://blog.zats.io/2014/07/02/signing-ipa<p>As soon as you leave the cozy Xcode’s build process, you find yourself fiddling with <a href="https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/codesign.1.html"><code class="language-plaintext highlighter-rouge">codesign</code></a> dealing with, well, code signing. There are many tools that suppose to ease up the process: <a href="https://github.com/RichardBronosky/ota-tools">ota-tools</a>, <a href="https://github.com/nomad/shenzhen">shenzhen</a> and <a href="https://gist.github.com/mediabounds/1367348">gists</a> to name a few. However, once in a while you find yourself in need of more flexible solution.</p>
<p>Our flow includes distributing betas from one Apple account and submitting to the App Store from another. This calls for:</p>
<ul>
<li>Modifying whole bunch of resources (visual and internal such as bundle id);</li>
<li>Obtaining new entitlements file;</li>
<li>Sign ipa again.</li>
</ul>
<p>Modify resources is easy – everyone used <a href="https://developer.apple.com/library/mac/documentation/Darwin/Reference/Manpages/man8/PlistBuddy.8.html"><code class="language-plaintext highlighter-rouge">PlistBuddy</code></a> to change the app version. The trickier part is to obtain new entitlements. Remember new app id and a team id? Old entitlements simply won’t work (think keychain access etc).</p>
<p>Most of the articles on the internet cover signing of the apps with the same bundle ids. Therefore, no issues were noticed.</p>
<p>So where to find an entitlements file? “Capabilities” pane, introduced in Xcode 5, took away the pane of dealing with most of routine. But it comes with a price: unless you explicitly create an entitlements file or trigger one of the capabilities that would do it for you, you will never see it in your project folder.</p>
<p>The file is still being generated when “Code Signing” project setting demands so. Even if you add an entitlements file explicitly to your project, by default it will contain placeholders that would be populated according to the selected team, app id etc but only during the build. This file is generated at <code class="language-plaintext highlighter-rouge">$DERIVED_FILES_DIR/$PRODUCT_NAME.xcent</code>.</p>
<p>On the day of writing this post I have not received any answer nor on Apple <a href="https://devforums.apple.com/message/995715#995715">developer</a> <a href="https://devforums.apple.com/message/995748#995748">forums</a> nor on <a href="http://stackoverflow.com/questions/24477305/extracting-entitlements-from-xcode-capabilities">Stack Overflow</a>. That brought me to two possible solutions, either generate plist on the fly during signing or simply use the one that was generated previously by Xcode.</p>
<p>So the workflow itself is quite trivial:</p>
<ol>
<li>Unzip existent ipa;</li>
<li>Replace bundle ids, versions, display and product names;</li>
<li>Replace all resources that might be App Store unsafe (e.g. we watermark beta builds with versions to point to Jenkins jobs, which, in turn, points to a particular commit on GitHub);</li>
<li>Obtain / generate new entitlements file (stil unclear what is the best way to do it, for now it’s hardcoded);</li>
<li>Sign using <code class="language-plaintext highlighter-rouge">codesign</code> tool;</li>
<li>Ship it!</li>
</ol>
<p>Here is a ruby script that is tailored for our needs, but I’m sure, you can tweak it to a certain extent.</p>
<p>By the way, if you know an answer to my question, please drop me a line.</p>
"Nicer" crash messages when IBOutlets are not found2014-05-17T00:00:00+00:00http://blog.zats.io/2014/05/17/nicer-crashes-when-outlets-not-found<blockquote>
<p>[<ZTSViewController 0x8c46c60> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key textField.</p>
</blockquote>
<p>We’ve probably seen similar exceptions when Interface Builder was involved in the process of app design. StackOverflow is <a href="http://stackoverflow.com/search?q=setValue%3AforUndefinedKey%3A+this+class+is+not+key+value+coding-compliant+for+the+key">full of question</a> “what am I doing wrong?”.</p>
<p>By now more advanced users probably guessed that I’m talking about UIKit trying to decode a storyboard (or a nib) and failing to find an appropriate outlet in the corresponding class. The way this technology works is not a trick: it uses KVC to establish connections. And, in cases I’m talking about, it fails to find an appropriate key. Most likely it’s because someone renamed the control in the Interface Build and forgot to reflect the changes in code.</p>
<p>First, we need to establish who is throwing this exception. As we can see in the call stack, crash happening as a result of a default implementation of <code class="language-plaintext highlighter-rouge">-[NSObject(NSKeyValueCoding) setValue:forUndefinedKey:]</code> and just prior to that <code class="language-plaintext highlighter-rouge">-[UIRuntimeOutletConnection connect]</code> is probably trying to set a value for the missing key. It sounds like a case for method swizzling!</p>
<p>Sadly the class itself is not public, but fear not, as long as class registered with runtime, we can call <code class="language-plaintext highlighter-rouge">NSClassFromString</code> function to get a reference of a class. Then we just swizzle <code class="language-plaintext highlighter-rouge">connect</code> method with our implementation of a <code class="language-plaintext highlighter-rouge">zts_connect</code>:</p>
<pre><code class="language-objective-c">- (void)zts_connect {
@try {
[self zts_connect];
}
@catch (NSException *exception) {
if ([exception.name isEqualToString:NSUndefinedKeyException]) {
NSString *label = [self valueForKey:@"label"];
id source = [self valueForKey:@"source"];
id destination = [self valueForKey:@"destination"];
NSString *nicerDescription = [NSString stringWithFormat:@"Make sure you have an IBOutlet of type %@ called \"%@\" in %@", [destination class], label, source];
exception = [NSException exceptionWithName:exception.name
reason:nicerDescription
userInfo:exception.userInfo];
}
@throw exception;
}
}
</code></pre>
<p>In the code above, we call the original implementation (don’t let the method names limbo trick you, read <a href="http://nshipster.com/method-swizzling/">NSHipster</a> for more info) and check if exception thrown (if any) has a name equal to <code class="language-plaintext highlighter-rouge">NSUnknownKeyException</code>. Here we go on a stretch and assume that any exception of this type thrown during this method call is due to missing outlet. Next, we just re-throw this exception, now instead of a “cryptic” message we get</p>
<blockquote>
<p>Make sure you have an IBOutlet of type UIButton called “button” in <ZTSViewController: 0x8c46c60></p>
</blockquote>
<p>Now it’s important to keep in mind that you want to keep this code wrapped in <code class="language-plaintext highlighter-rouge">#ifdef DEBUG</code> since it mentions a private class and alters the core behavior of UIKit. Most importantly the issue we’re trying to solve is a pure development-time issue, therefore this code does not belong to production by any stretch.</p>
<p>Is there a simpler solution? Of course:) Sadly it is as not production safe as the first one, but a simpler one. Just override <code class="language-plaintext highlighter-rouge">setValue:forUndefinedKey:</code> in a category of <code class="language-plaintext highlighter-rouge">UIViewController</code>!</p>
<pre><code class="language-objective-c">#ifdef DEBUG
@implementation UIViewController (NicerStoryboardCrashes)
- (void)setValue:(id)value forUndefinedKey:(NSString *)key {
NSString *nicerDescription = [NSString stringWithFormat:@"Make sure you have an IBOutlet of type %@ called \"%@\" in %@", [value class], key, self];
@throw [NSException exceptionWithName:NSUndefinedKeyException
reason:nicerDescription
userInfo:nil];
}
@end
#endif
</code></pre>
<p>As I mentioned before, this solution is not a production grade because in this case we generalize too much: assuming that any undefined key coming our way was caused by storyboard outlet mismatch, which is wrong.</p>
NSArray's privates2014-05-09T00:00:00+00:00http://blog.zats.io/2014/05/09/nsarrays-privates<p>Several private methods from <code class="language-plaintext highlighter-rouge">NSArray</code> API, complexity analysis, and how to implement it yourself.</p>
<p>I remember reading how at Apple, API goes through several stages of internal usage before it gets published to 3rd party developers like us. It helps to test it properly, and helps to make sure that the names are well chosen (!).
Here is a rundown of some methods that didn’t make it in the <code class="language-plaintext highlighter-rouge">NSArray</code>’s public API (and probably won’t).</p>
<p>The good news is that most of them are based around <code class="language-plaintext highlighter-rouge">NSFastEnumeration</code> <code class="language-plaintext highlighter-rouge">for in</code> loop and quite straight forward to implement if want to. Just, please, don’t forget to prefix it with your branded <code class="language-plaintext highlighter-rouge">xyz_</code>. Or even better, call them something different all together to avoid potential problems when submitting the app.</p>
<h1 id="containsobjectidenticalto"><code class="language-plaintext highlighter-rouge">containsObjectIdenticalTo:</code></h1>
<p>Where <code class="language-plaintext highlighter-rouge">containsObject:</code> uses <code class="language-plaintext highlighter-rouge">isEqual:</code> to find if array contains specified object, this method uses pointer equality only. It might provide you a nice performance boost if the objects stored have complex <code class="language-plaintext highlighter-rouge">isEqual:</code> and all you care is pointer comparison. By the way, the default implementation of <code class="language-plaintext highlighter-rouge">-[NSObject isEqual:]</code> does pointer comparison, so if you have not overridden it, don’t bother, this is not your bottleneck.</p>
<h2 id="complexity">Complexity:</h2>
<p><em>O(n)</em></p>
<h2 id="usage">Usage</h2>
<pre><code class="language-objective-c">NSDictionary *person1 = @{ @"name" : @"Bob" };
NSDictionary *person2 = @{ @"name" : @"John" };
NSArray *array = @[ person1, person2 ];
// using isEqual:
[array containsObject:person1]; // YES
[array containsObject:@{ @"name" : @"Bob" }]; // YES
// using ==
[array containsObjectIdenticalTo:person1]; // YES
[array containsObjectIdenticalTo:@{ @"name" : @"Bob" }]; // NO
</code></pre>
<h2 id="how-to-implement">How to implement</h2>
<pre><code class="language-objective-c">- (BOOL)containsObjectIdenticalTo:(id)object {
for (id subobject in self) {
if (subobject == object) {
return YES;
}
}
return NO;
}
</code></pre>
<h1 id="arraybyapplyingselector"><code class="language-plaintext highlighter-rouge">arrayByApplyingSelector:</code></h1>
<p>This method is a somewhat simliar to the signal transformation that can be found in popular today <a href="https://github.com/ReactiveCocoa/ReactiveCocoa">reactive frameworks</a>. Somewhat similar, because you don’t get to return any value you want instead of the current one. Rather, you get to call a specified selector.</p>
<p>If your method of choise expects parameters – bad luck. Obviosuly, you method has to return an object and not primitive. If you method returnes <code class="language-plaintext highlighter-rouge">nil</code> for certain cases, object will not be inserted into a new array.</p>
<p>This method is usefull for arrays containing instances of one class only (or if objects happened to respond to the same selector which is not that safe really).</p>
<h2 id="complexity-1">Complexity</h2>
<p><em>O(n)</em></p>
<h2 id="usage-1">Usage</h2>
<pre><code class="language-objective-c">NSArray *array = @[ @1, @2, @3 ];
array = [array arrayByApplyingSelector:@selector(stringValue)];
[[array firstObject] isKindOfClass:[NSString class]]; // YES
</code></pre>
<h2 id="how-to-implement-1">How to implement</h2>
<pre><code class="language-objective-c">- (NSArray *)arrayByApplyingSelector:(SEL)selector {
if (!selector) {
[self doesNotRecognizeSelector:selector];
}
NSUInteger maxNumberOfNewObjects = [self count];
// allocate enough space to fit maxNumberOfNewObjects of objects
id objects[maxNumberOfNewObjects] = …;
NSUInteger newCount = 0;
for (id object in self) {
id newObject = [object performSelector:selector];
if (newObject) {
newCount++;
objects[newCount] = newObject;
}
}
NSArray *result = [NSArray arrayWithObjects:objects count:newCount];
// don't forget to release the allocated objects
return result;
}
</code></pre>
<h1 id="countforobject"><code class="language-plaintext highlighter-rouge">countForObject:</code></h1>
<p>A straightforward method, allowing to count all objects that are <code class="language-plaintext highlighter-rouge">isEqual</code> to the specified one. Another example of a convenience wrapper around <code class="language-plaintext highlighter-rouge">NSFastEnumeration</code> loop.</p>
<p>Interestingly, <code class="language-plaintext highlighter-rouge">NSSet</code> has a similar method, that returns <code class="language-plaintext highlighter-rouge">1</code> if object is a member of a set and <code class="language-plaintext highlighter-rouge">0</code> if not.</p>
<h2 id="complexity-2">Complexity</h2>
<p><em>O(n)</em></p>
<h2 id="usage-2">Usage</h2>
<pre><code class="language-objective-c">NSArray *test = @[ @1, @2, @3, @1, @1 ];
[test countForObject:@1]; // 3
</code></pre>
<h2 id="how-to-implement-2">How to implement</h2>
<pre><code class="language-objective-c">- (NSUInteger)countForObject:(id)object {
NSUInteger count = 0;
for (id subobject in self) {
if ([subobject isEqual:object]) {
count++;
}
}
return count;
}
</code></pre>
<p>Note usage of <code class="language-plaintext highlighter-rouge">isEqual:</code> rather than pointer comparison.</p>
<h1 id="arraybyexcludingobjectsinarray"><code class="language-plaintext highlighter-rouge">arrayByExcludingObjectsInArray:</code></h1>
<p>This method is somewhat similar to <code class="language-plaintext highlighter-rouge">minusSet:</code> of <code class="language-plaintext highlighter-rouge">NSMutableSet</code> or <code class="language-plaintext highlighter-rouge">NSMutableOrderedSet</code>. This method, however, leaves duplicates and overall order of the objects intact. This metod actually uses <code class="language-plaintext highlighter-rouge">+[NSSet setWithArray:]</code> from the parameter array to exclude. This ensures <code class="language-plaintext highlighter-rouge">NSFastEnumeration</code> over parameter-array won’t go through duplicates. Also it uses <code class="language-plaintext highlighter-rouge">containsObject:</code> on the receiver array, causing comparison by value and not by pointer.</p>
<h2 id="complexity-3">Complexity</h2>
<p><em>O(n+m)</em> where <em>n</em> is a number of elements in the receiver and <em>m</em> is a number of elements in the argument array.</p>
<h2 id="usage-3">Usage</h2>
<pre><code class="language-objective-c">NSArray *array = @[ @1, @2, @4, @3, @2 ];
[array arrayByExcludingObjectsInArray:@[ @1, @3, @3 ]; // @[ @2, @4, @2 ]
</code></pre>
<h2 id="how-to-implement-3">How to implement</h2>
<pre><code class="language-objective-c">- (NSArray *)arrayByExcludingObjectsInArray:(NSArray *)array {
NSSet *set = [NSSet setWithArray:array];
NSUInteger maxNumberOfNewObjects = [self count];
// allocate enough space to fit maxNumberOfNewObjects of objects
id objects[maxNumberOfNewObjects] = …;
NSUInteger newCount = 0;
for (id object in self) {
if (![set containsObject:object]) {
newCount++;
objects[newCount] = object;
}
}
NSArray *result = [NSArray arrayWithObjects:objects count:newCount];
// don't forget to release the allocated objects
return result;
}
</code></pre>
<p>Note, complexity of <em>O(n+m)</em> achieved by creating an <code class="language-plaintext highlighter-rouge">NSSet</code> from the argument array first, and iterating over all elements of the receiver. <code class="language-plaintext highlighter-rouge">containsObject:</code> for <code class="language-plaintext highlighter-rouge">NSSet</code> has complexity of <em>O(1)</em> unlike <code class="language-plaintext highlighter-rouge">NSArray</code>’s version, that would limit complexity of the method overall to <em>O(nm)</em>.</p>
<h1 id="arraybyexcludingtoobjectsinarray"><code class="language-plaintext highlighter-rouge">arrayByExcludingToObjectsInArray:</code></h1>
<p>Very similar to previous method, but, logically it’s more of a <code class="language-plaintext highlighter-rouge">intersectSet:</code> in <code class="language-plaintext highlighter-rouge">NSMutableSet</code> terms.</p>
<h2 id="complexity-4">Complexity</h2>
<p><em>O(n+m)</em></p>
<h2 id="usage-4">Usage</h2>
<pre><code class="language-objective-c">NSArray *test = @[ @1, @2, @3, @1, @2, @1 ];
[test arrayByExcludingToObjectsInArray:@[ @2, @1 ]]; // @[ @1, @2, @1, @2, @1 ]
</code></pre>
<h2 id="how-to-implement-4">How to implement</h2>
<pre><code class="language-objective-c">- (NSArray *)arrayByExcludingObjectsInArray:(NSArray *)array {
NSSet *set = [NSSet setWithArray:array];
NSUInteger maxNumberOfNewObjects = [self count];
// allocate enough space to fit maxNumberOfNewObjects of objects
id objects[maxNumberOfNewObjects] = …;
NSUInteger newCount = 0;
for (id object in self) {
if ([set containsObject:object]) {
newCount++;
objects[newCount] = object;
}
}
NSArray *result = [NSArray arrayWithObjects:objects count:newCount];
// don't forget to release the allocated objects
return result;
}
</code></pre>
Moarfonts after upgrading Xcode2014-04-14T00:00:00+00:00http://blog.zats.io/2014/04/14/moarfonts-after-upgrading-xcode<p>We are using <a href="http://pitaya.ch/moarfonts/">moarfonts</a> for WSYIWYG-style preview in Interface Builder. And if you’r not doing it yet, you really should. However, after upgrading to Xcode 5.1.1 some of the team members started seeing a strange error while building the project.</p>
<blockquote>
<p>Failed to install XXX: The file “XXX.ttf” couldn’t be opened because there is no such file.</p>
</blockquote>
<p>After fruitless googling for possible solutions, we took a closer look at the binary that makes moarfonts magic possible. Trying to run <code class="language-plaintext highlighter-rouge">$ moarfonts</code> in the command line revealed <code class="language-plaintext highlighter-rouge">moarfonts reset</code>. And although there is no documentation, it looked promising. However you can’t run it if you don’t have an <code class="language-plaintext highlighter-rouge">SDKROOT</code> environment variable set. So we ended up with the following cure:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">export </span><span class="nv">SDKROOT</span><span class="o">=</span>/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.1.sdk
moarfonts reset
</code></pre></div></div>
<p>That’s it. Clean Derived Data and build folder, restart Xcode and re-run your build. Hope it helps!</p>
<p><strong>Update</strong>: Cédric Luthi published <a href="http://pitaya.ch/moarfonts/#troubleshooting">troubleshooting guide</a> you should refer to</p>
<p><strong>Update</strong> Hail Xcode 6, the script is not needed anymore!</p>
State restoration: beyond iOS2014-04-13T00:00:00+00:00http://blog.zats.io/2014/04/13/state-restoration-beyond-ios<p>Just a brief thought on <a href="https://developer.apple.com/library/ios/documentation/iphone/conceptual/iphoneosprogrammingguide/StatePreservation/StatePreservation.html">Preservation & Restoration API</a>. It occurred to me that extending this technology to Mac OS might give us much more seamless experience when switching between apps on Mac OS and iOS apps.</p>
<p>Possible applications are:</p>
<ul>
<li>Moving your Face Time call from your laptop to your phone when you have to run to work.</li>
<li>Peeking up a draft of a document you sketched on your iPad lying on the couch.</li>
<li>Continuing the song or a movie you were enjoying on your desktop when you have to run.</li>
<li>Stepping into the game you started in the bus on your phone and now want to enjoy on your desktop.</li>
</ul>
<p>There is a partial solution provided by iCloud, but it requires time to sync. The major difference of this approach is you are giving an explicit cue to the app through the UI: move my state now to a particular client (ocontrary to the continues syncing that iCloud does). Obviously it implies your interface and data being highly decoupled. Obviously it requires finding a common denominator between two platforms functionalities.</p>
<p><strong>Update</strong> One of those cases when Apple <a href="https://developer.apple.com/library/prerelease/ios/documentation/UserExperience/Conceptual/Handoff/Introduction/Introduction.html">introduced API</a> serving the same purpose but implemented with Bluetooth LTE</p>
Designing your own class cluster. Initializers.2014-04-12T00:00:00+00:00http://blog.zats.io/2014/04/12/Designing-your-own-class-cluster-Initializers<p>I found myself creating a class cluster. Not just a notoriously studied subclass of <code class="language-plaintext highlighter-rouge">NSArray</code> or <code class="language-plaintext highlighter-rouge">UIButton</code> but a class cluster base class itself.</p>
<p>After fruitless attempts to google, I found little to none information (probably due to lack of the correct search term) regarding “the right way” of creating such a class.</p>
<p>So, I decided to find my own way of doing things. Starting point was <code class="language-plaintext highlighter-rouge">NSArray.h</code>:</p>
<pre><code class="language-objective-c">@interface NSArray (NSArrayCreation)
// ...
- (instancetype)init; /* designated initializer */
- (instancetype)initWithObjects:(const id [])objects count:(NSUInteger)cnt; /* designated initializer */
// ...
@end
</code></pre>
<p>So two designated initializers, ha? Documentation is <a href="https://developer.apple.com/library/mac/documentation/general/conceptual/devpedia-cocoacore/ClassCluster.html">not conclusive</a> <a href="https://developer.apple.com/library/ios/documentation/general/conceptual/CocoaEncyclopedia/ClassClusters/ClassClusters.html">either</a>, it only mentions subclassing class clusters and states that you have to override designated constructors.</p>
<p>Let’s try to deconstruct what’s happening when we initialize class cluster, for example following code</p>
<pre><code class="language-objective-c">NSString *strings[3] = {@"foo", @"bar", @"baz"};
id concreteClass = NSClassFromString(@"NSArray");
NSArray *arr = [[concreteClass alloc] initWithObjects:strings count:3];
</code></pre>
<p>creates an instance of <code class="language-plaintext highlighter-rouge">__NSArrayI</code> class and fills it with 3 objects.
Now, we can try replacing array class with <code class="language-plaintext highlighter-rouge">__NSArrayI</code> (a subclass used for immutable arrays) directly of with <code class="language-plaintext highlighter-rouge">_PFArray</code> (a subclass used by Core Data framework) and result is going to be predictable. But it’s not a default behavior we used to when dealing with subclasses: If you message superclass with init, you get an instance of a superclass. If you message a subclass – an instance of a subclass.</p>
<p>So how do we insure this behavior without causing nasty infinite lopps? Well, it’s rather simple, but involves one violation of a good object-oriented design. I ended up with following code in my initializers so far:</p>
<pre><code class="language-objective-c">@implementation ZTSStack
- (instancetype)init {
if ([self isMemberOfClass:[ZTSStack class]]) {
return [[_ZTSStack alloc] init];
}
return [super init];
}
- (instancetype)initWithCapacity:(NSUInteger)capacity {
if ([self isMemberOfClass:[ZTSStack class]]) {
return [[_ZTSStack alloc] initWithCapacity:capacity];
}
return [self init];
}
</code></pre>
<p>Just several things to note:</p>
<ul>
<li>Superclass has to know who is the “default implementation” subclass.</li>
<li>I don’t have the regular <code class="language-plaintext highlighter-rouge">if (!self) return nil;</code> routine since I do nothing in the “abstract” base class.</li>
<li>I check for <code class="language-plaintext highlighter-rouge">isMemberOfClass:</code> rather then <code class="language-plaintext highlighter-rouge">isKindOfClass:</code> to enbale strict equality.</li>
</ul>
<p>By implementing initializers like that I get the same behavior as when using <code class="language-plaintext highlighter-rouge">NSArray</code>:</p>
<ul>
<li>Initialize the base class directly and you get a default subclass implementation.</li>
<li>Initialize a (non-default) subclass with initialization method and you will “follow through” the initialization chain up to the <code class="language-plaintext highlighter-rouge">NSObject</code>.</li>
</ul>
<p>Now I can safely add convenience methods such as</p>
<pre><code class="language-objective-c">+ (instancetype)stackWithCapacity:(NSUInteger)capacity {
return [[self alloc] initWithCapacity:capacity];
}
+ (instancetype)stackBackedByTwoQueuesWithCapacity:(NSUInteger)capacity {
return [[_ZTSStackBackedByTwoQueues alloc] initWithCapacity:capacity];
}
+ (instancetype)stackBackedByLinkedListWithCapacity:(NSUInteger)capacity {
return [[_ZTSStackBackedByLinkedList alloc] initWithCapacity:capacity];
}
</code></pre>
<p>TODOs:</p>
<ul>
<li>I’m still not sure why <code class="language-plaintext highlighter-rouge">NSArray</code>, for example, has two designated initializers.</li>
<li>If I’d have a public subclass to my cluster class (e.g. what <code class="language-plaintext highlighter-rouge">NSMutableArray</code> to <code class="language-plaintext highlighter-rouge">NSArray</code>) and several private implementations for both, would adding <code class="language-plaintext highlighter-rouge">if [self isMemberOfClass:[NSMutableArray class]]</code> to a public subclass be enough?</li>
</ul>
<p>Solution, implemented above, works for my current (limited) set of use-cases and I will keep investigation.</p>
Radar: Xcode version editor not showing all commits2014-04-12T00:00:00+00:00http://blog.zats.io/2014/04/12/radar-xcode-version-editor<p>Starting from Xcode 4, IDE comes with a version editor allowing (in theory) to browse commits, diffs, blames, logs etc</p>
<p>Xcode 5.1 (at least) seems to find itself confused after pulling and jumping between branches several times.</p>
<p>As you can see, commit <code class="language-plaintext highlighter-rouge">edad969c…</code> is not the latest commit (even if we count only commits affecting current file).</p>
<p><img src="/assets/2014-03-04/xcode.png" alt="Xcode Comparison view" /></p>
<p><img src="/assets/2014-03-04/sourcetree.png" alt="SourceTree" /></p>
<p>To be honest, I can’t find a sure way to reproduce the bug. This exact bug affects every team member at the moment. Using 3rd-party git tools (including command line <code class="language-plaintext highlighter-rouge">git</code>) shows all commits, Xcode – doesn’t.</p>
<p>You can duplicate the bug at <a href="http://openradar.appspot.com/radar?id=5790409678651392">rdar://16511277</a>.</p>
+initialize in categories2014-04-12T00:00:00+00:00http://blog.zats.io/2014/04/12/initialize-in-categories<p>An interesting quirk for <code class="language-plaintext highlighter-rouge">+ initialize</code> method when implemented in a category. Documentation doesn’t really explain what is the correct behavior of the method, let’s figure it out by ourselves.</p>
<blockquote>
<p>The runtime sends <code class="language-plaintext highlighter-rouge">initialize</code> to each class in a program just before the class, or any class that inherits from it, is sent its first message from within the program […] Superclasses receive this message before their subclasses. The superclass implementation may be called multiple times if subclasses do not implement <code class="language-plaintext highlighter-rouge">initialize</code> — the runtime will call the inherited implementation — or if subclasses explicitly call <code class="language-plaintext highlighter-rouge">[super initialize]</code>.</p>
</blockquote>
<p>Imagine, we have following classes in an empty project:</p>
<ol>
<li><code class="language-plaintext highlighter-rouge">UIView (ZTSAdditions)</code> – a category on <code class="language-plaintext highlighter-rouge">UIView</code></li>
<li><code class="language-plaintext highlighter-rouge">ZTSView1 : UIView</code> – a subclass of <code class="language-plaintext highlighter-rouge">UIView</code></li>
<li><code class="language-plaintext highlighter-rouge">ZTSView2 : ZTSView1</code> – a subclass of <code class="language-plaintext highlighter-rouge">ZTSView1</code></li>
<li><code class="language-plaintext highlighter-rouge">ZTSView1 (ZTSAdditions)</code> – a category on <code class="language-plaintext highlighter-rouge">ZTSView1</code></li>
</ol>
<p>Every class from mentioned above implements <code class="language-plaintext highlighter-rouge">+ initialize</code></p>
<pre><code class="language-objective-c">// somewhere in .pch
#define ZTSLog() ({ NSLog(@"%s +[initialize] %@", __FILE__, NSStringFromClass(self)); })
+ (void)initialize {
ZTSLog();
}
</code></pre>
<p>In our app delegate we add following code (note, there is no import of categories).</p>
<pre><code class="language-objective-c">#import "ZTSView1.h"
#import "ZTSView2.h"
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self.window addSubview:[ZTSView1 new]];
[self.window addSubview:[ZTSView2 new]];
return YES;
}
</code></pre>
<p>What are we going to see in the console?</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>…UIView+ZTSAdditions.m +[initialize] UIView
…UIView+ZTSAdditions.m +[initialize] _UIScrollsToTopInitiatorView
…UIView+ZTSAdditions.m +[initialize] UIStatusBar
…
…ZTSView1+ZTSAdditions.m +[initialize] ZTSView1
…ZTSView2.m +[initialize] ZTSView2
…
…UIView+ZTSAdditions.m +[initialize] UIAlertView
…UIView+ZTSAdditions.m +[initialize] UIFieldEditor
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">+ initialize</code> is being fired for every subclass of your category class. Not really documented behavior but makes sense. But remember, we haven’t imported category in our app delegate, nor mentioned it in any imported class.</p>
<p>Something to be aware of when abusing <code class="language-plaintext highlighter-rouge">initialize</code> method. I’d try to avoid using it at all – if two categories override <code class="language-plaintext highlighter-rouge">initialize</code> method, there is no guarantee that your method is going to be called. Use <code class="language-plaintext highlighter-rouge">+load</code> instead.</p>
<p><strong>Update</strong> a very good article on this topic was published in 2009 by bbum: http://www.friday.com/bbum/2009/09/06/iniailize-can-be-executed-multiple-times-load-not-so-much/</p>
NSDate is a model not a view2014-04-12T00:00:00+00:00http://blog.zats.io/2014/04/12/NSDate-is-a-model<p>Following code <code class="language-plaintext highlighter-rouge">[[NSDate date] dateByAddingTimeInterval:60 * 60]</code> is a really common attempt to get the current time in, let’s say, France. Despite developer’s expectations, it does not represent current time in GMT+1 time zone. So where is all the confusion coming from?</p>
<p>Let’s execute <code class="language-plaintext highlighter-rouge">po [NSDate date]</code> in Xcode console. What are we seeing?</p>
<p>Not <code class="language-plaintext highlighter-rouge">1395089079</code> but <code class="language-plaintext highlighter-rouge">2014-03-17 20:53:28 +0000</code>. Quick look in Xcode doesn’t make it clearer: <code class="language-plaintext highlighter-rouge">NSDate *date = [NSDate date];</code> is presented as <code class="language-plaintext highlighter-rouge">2014-03-17 22:53:28 IST</code> (It shows the date as it appears in the developer’s time zone). I believe, this is what trips people up.</p>
<p>In MVC sense of things, you have an <code class="language-plaintext highlighter-rouge">NSDate</code> object representing a model. It is agnostic to the concept of time zone or particular localization. Then, you have a group of APIs dealing with displaying or parsing dates and performing calculations on them: <code class="language-plaintext highlighter-rouge">NSCalendar</code>, <code class="language-plaintext highlighter-rouge">NSDateComponent</code>, <code class="language-plaintext highlighter-rouge">NSDateFormetter</code> etc. Those are your “views”.</p>
<p>Just as you wouldn’t store view in your database, don’t store or pass around serialized dates, use NSDate instead – in the end of the day that’s why it exists, to provide a good abstraction of a unix timestamp, decoupled from the way you present it to the user.</p>
<p>To summarize, as soon as you received a date from web API, parse it to <code class="language-plaintext highlighter-rouge">NSDate</code>. Or, if API utilizes unix timestamps, use <code class="language-plaintext highlighter-rouge">[NSDate dateWithTimeIntervalSince1970:]</code>, just keep in mind that it expects seconds. Just before presentation to the user, render the date object into the human readable (meaning localized, time zone aware) string.</p>
<h2 id="where-to-go-from-here">Where to go from here</h2>
<p><a href="https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/DatesAndTimes/Articles/dtCalendars.html">Apple documentation</a> is a great place to start</p>
<p>WWDC sessions if you have enough time:</p>
<ul>
<li>2013 session 227: Solutions to Common Date and Time Challenges</li>
<li>2012 session 212: Internationalization Tips and Tricks</li>
<li>2011 session 117: Performing Calendar Calculations</li>
</ul>
<p>Finish with NSHipster on <a href="http://nshipster.com/nsdatecomponents/"><code class="language-plaintext highlighter-rouge">NSDateComponents</code></a>, <a href="http://nshipster.com/nsformatter/"><code class="language-plaintext highlighter-rouge">NSFormatter</code></a> and <a href="http://nshipster.com/nslocale/"><code class="language-plaintext highlighter-rouge">NSLocale</code></a></p>
Storyboards2014-03-12T00:00:00+00:00http://blog.zats.io/2014/03/12/storyboards<p>I’ve seen people quoting this <a href="http://stackoverflow.com/questions/9404471/when-to-use-storyboard-and-when-to-use-xibs/19457257#19457257">Stack Overflow answer</a> a lot when they need to convince someone not to use storyboards. I understand that it’s a somewhat a flamewar topic, but I’d like to address the points author makes.</p>
<blockquote>
<p>Storyboards fail at runtime, not at compile time</p>
</blockquote>
<p>So does AutoLayout, CoreData or KVO if misused</p>
<blockquote>
<p>Storyboards get confusing fast</p>
</blockquote>
<p>It’s only common sense to split storyboards into logical groups</p>
<blockquote>
<p>Storyboards make working in a team harder</p>
</blockquote>
<p>This is something I have heard a lot. But storyboards are not binary blobs anymore. Merging a storyboard is not any harder than a regular class. Although I heard that it’s still challenging even with XML, I’d like to see those merge conflicts, clearly I was dealing with a fairly trivial cases.</p>
<blockquote>
<p>Storyboards make code reviews hard or nearly impossible</p>
</blockquote>
<p>True, reviewing storyboard as XML doesn’t make much sence</p>
<blockquote>
<p>Storyboards hinder code reuse</p>
</blockquote>
<p>True, hopefully will be addressed in the future, and if <code class="language-plaintext highlighter-rouge">Container View</code> doesn’t solve you problem, there is a workaround <code class="language-plaintext highlighter-rouge">nibs</code> + <code class="language-plaintext highlighter-rouge">awakeAfterUsingCoder:</code></p>
<blockquote>
<p>Storyboards make you do everything twice [for iPad and iPhone]</p>
</blockquote>
<p>That is a where AppStore shines by offering experiences tailored for iPad and not just streched iPhone apps. If you’re reusing your view controllers from iPhone to iPad one to one it might be a bad sign.</p>
<blockquote>
<p>Storyboards require constant context switches</p>
</blockquote>
<p>True, it depends on your mindset. For me it’s not harder than switch between photoshop mockup and the code. Maybe it’s due to my designer past.</p>
<p>Storyboards are hard to refactor – let’s face it, Xcode is much worse than App Code when it comes to refactoring, although it always finds outlets and actions.</p>
<blockquote>
<p>Storyboards are not searchable</p>
</blockquote>
<p>True, hopefully will be addressed in the future updates of Xcode or maybe you will be the author of a <a href="http://alcatraz.io/">clever plugin</a> that does that?</p>
<blockquote>
<p>Storyboards are less flexible [than code]</p>
</blockquote>
<p>Well, code is always more flexible. Are you setting up your core data scheme in code, too?</p>
<blockquote>
<p>Storyboards don’t let you change the type of special view controllers</p>
</blockquote>
<p>The argument that it’s much easier to make this kind of change in code is questionable to say the least.</p>
<blockquote>
<p>Storyboards add two extra liabilities to your project [XML source and compiled storyboards]</p>
</blockquote>
<p>I can see author of the answer using assembly to write his next submission to the App Store, because objective-c is an extra liability. It’s just a matter of whether the advantages outweigh the complication certain technology brings.</p>
<blockquote>
<p>Storyboards don’t allow you to add a subview to a UIImageView</p>
</blockquote>
<p>Normally, I would say if you’re adding a subview to <code class="language-plaintext highlighter-rouge">UIImageView</code>, it’s a good sign that you better to have a custom class instead. It’s no coincidence that <code class="language-plaintext highlighter-rouge">userInteractionEnabled</code> is <code class="language-plaintext highlighter-rouge">NO</code> by default for image views, if you’re adding subview just for the sake of alignment, consider using AutoLayout instead.</p>
<p>What wasn’t mentioned, is that storyboards (and nibs) introduce a problem of responsibility separation. It becomes yet another point where the views (and now with segues, even more than just views) might be configured. But, like with other code practices such as <a href="https://developer.apple.com/library/ios/documentation/uikit/reference/UIAppearance_Protocol/Reference/Reference.html"><code class="language-plaintext highlighter-rouge">UIAppearance</code></a> or IOC, it’s all about being consistent.</p>
<p>All and all I see storyboards as a future with tools that are in the active development, meaning you might want to become an (not so) early adapter and dial with imperfection of the tools but benefit from the technology itself. On The bright side, there are many projects out there that help to dial with shortcomings:</p>
<ul>
<li><a href="https://github.com/square/objc-codegenutils">objc-codegenutils</a> similar to <a href="https://github.com/rentzsch/mogenerator">mogenerator</a> in a way, spits files with strongly typed images, string constants etc.</li>
<li><a href="https://github.com/jfahrenkrug/StoryboardLint">StoryboardLint</a> a lint tool for UIStoryboard to find wrong classes and wrong storyboard/segue/reuse identifiers.</li>
</ul>
RTFM performSelector:withObject:2014-03-12T00:00:00+00:00http://blog.zats.io/2014/03/12/performSelector-withObject<p>Recently, while going through the code review, I stumbled upon a curious bug that manifested itself on iOS 7.1 64 bit simulator. A committer had a boolean setter that he wanted to call with a delay, so he had a following code</p>
<pre><code class="language-objective-c">@property (nonatomic, assign) BOOL splashFinishedDisplaying;
[self performSelector:@selector(setSplashFinishedDisplaying:)
withObject:@YES
afterDelay:2];
</code></pre>
<p>This code didn’t work on iOS 7.1 in 64 bit simulator. The workaround he offered was to declare a wrapper method <code class="language-plaintext highlighter-rouge">setSplashFinishedDisplayingWithNumber:</code> and use that with <code class="language-plaintext highlighter-rouge">performSelector:…</code>.</p>
<p>I didn’t really like this approach for several reasons, and proposed to use <code class="language-plaintext highlighter-rouge">dispatch_after</code> instead. The major reason is it produces ARC-friendly analyzable code where <code class="language-plaintext highlighter-rouge">performSelector:</code> does not (also creating a proxy method feels kinda kind of dirty).</p>
<p>While I, personally, don’t like the <code class="language-plaintext highlighter-rouge">performSelector:</code> group of methods, I was curious what is the deal with it. I wrote a simple code to debug the case and ran it in several environment combinations of iOS version and 64 / 32 bit systems.</p>
<pre><code class="language-objective-c">- (void)setFrame:(CGRect)frame {
NSLog(@"Frame: %@", NSStringFromCGRect(frame));
}
- (void)setInteger:(NSInteger)integer {
NSLog(@"Integer: %i", integer);
}
- (void)setBoolean:(BOOL)boolean {
NSLog(@"Boolean: %@", boolean ? @"YES" : @"NO");
}
- (void)testCase {
NSValue *frameValue = [NSValue valueWithCGRect:CGRectMake(3, 14, 15, 92)];
NSLog(@"Rect value %@ %p", frameValue, frameValue);
[self performSelector:@selector(setFrame:) withObject:frameValue];
NSNumber *integerValue = @300;
NSLog(@"Integer number %@ %p", integerValue, integerValue);
[self performSelector:@selector(setInteger:) withObject:integerValue];
NSNumber *booleanValue = @YES;
NSLog(@"Boolean value %@ %p", booleanValue, booleanValue);
[self performSelector:@selector(setBoolean:) withObject:booleanValue];
}
</code></pre>
<p>32 bit, iOS 6 console output is</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Rect value NSRect: {3, 14}, {15, 92} 0xacb8820
Frame: {1.95994e-32, 2.1209e-35}, {1.95994e-32, 4.03828e-37}
Integer number 300 0xacb8800
Integer: 181110784
Boolean value 1 0x30d795c
Boolean: YES
</code></pre></div></div>
<p>Replacing string format for integer with <code class="language-plaintext highlighter-rouge">%li</code>, console output for 64 bit, iOS 7.1 is</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Rect value NSRect: {3, 14}, {15, 92} 0x10e635bb0
Frame: {3, 14}, {15, 92}
Integer number 300 0xb0000000000012c2
Integer: 4802
Integer number 1 0x103d2e0e0
Boolean: NO
</code></pre></div></div>
<p>The test case produces randomly wrong / right results depending on the iOS version and 64 / 32 bit. As you can see, I added the address of the variable I’m sending to the selector. I didn’t have it at first, but added in the second round of tests and it proved my guess. Method simply interprets the address variable as the primitive type it expects. That’s why <code class="language-plaintext highlighter-rouge">setInteger:</code> with <code class="language-plaintext highlighter-rouge">300</code> with address <code class="language-plaintext highlighter-rouge">0xacb8800</code> receives <code class="language-plaintext highlighter-rouge">181110784</code>. The Big Nerd Ranch has a <a href="blog.bignerdranch.com/564-bools-sharp-corners/">very good article</a> about craziness of boolean defined as <code class="language-plaintext highlighter-rouge">char</code> on 32 bit systems.</p>
<p>Only after that I went into the documentation for the <code class="language-plaintext highlighter-rouge">performSelector:withObject:</code></p>
<blockquote>
<p>This method is the same as <code class="language-plaintext highlighter-rouge">performSelector:</code> except that you can supply an argument for <code class="language-plaintext highlighter-rouge">aSelector</code>. <code class="language-plaintext highlighter-rouge">aSelector</code> should identify a method that takes a single argument of type <code class="language-plaintext highlighter-rouge">id</code>. For methods with other argument types and return values, use <code class="language-plaintext highlighter-rouge">NSInvocation</code>.</p>
</blockquote>
<p>Here is a <a href="http://stackoverflow.com/questions/904515/how-to-use-performselectorwithobjectafterdelay-with-primitive-types-in-cocoa/1735045#1735045">stack overflow answer</a>, illustrating usage of <code class="language-plaintext highlighter-rouge">NSInvocation</code>. I believe that invocation doesn’t produce ARC-friendly code in a sense of an arbitrary executed code, but the application for invocation is much broader, while <code class="language-plaintext highlighter-rouge">dispatch_after</code> solves a very particular task.</p>
<p>Another case of RTFM. What still doesn’t make much sense is that structure randomly works with 64 bit system.</p>