Quick architecture review of Signal’s iOS App using SwiftAlyzer

Today, I want to present to you SwiftAlyzer, a tool to review Swift project’s, a tool to help refactoring and keeping it maintainable. As a software architect I find myself oftentimes reviewing projects. Either new projects that are taken over from other companies. Or monitoring the health of an ongoing in-house development. While every feature of a software can be well structured applying design patterns and code heuristics, it’s oftentimes the ensemble of all features to a whole app, that lacks a good structure. It’s where dependencies from one feature reach out to another and back and forth, that lead to an overall maintainance nightmare. Every feature on its own can be quality-checked by looking at the source code, reviewing in so called pull requests to review its quality. It’s hard to get an overview of the inter-class dependencies when looking at source code solely. But often it’s these dependencies that ruin the maintainability slowly but steadily when not supervised.

What makes a good (Swift) software project? That depends on a vast number of variables. In this article I don’t want to start a broad discussion on the „best“ architecture to choose or pinpoint Signal’s weaknesses. My aim is to demonstrate SwiftAlyzer and explain its unique strength as review tool. Therefore I will analyse Signal’s iOS app – but without ever looking at the source code or doing any analysis beforehand.

As mentioned above, I focus on dependencies as a main root of evil. This is explained further below. I try to give more information in these yellow boxes whenever I feel like my arguments could do with some more explanations.

Their’s a lack of tools that support a quick review and an oversight of the app’s structure and its dependencies. That’s why I started SwiftAlyzer. Today I want to demonstrate it’s review capabilities using Signal’s iOS app. If you want to follow along you can get your free copy of SwiftAlyzer on https://swiftalyzer.com and download Signal’s source code here https://github.com/signalapp/Signal-iOS.
(I checked out the develop branch at commit 962369b2676a10da9cf130aa27c87f7c45c325cb)

Analysing the building blocks on 1st level

Displaying the first building block view level zero of Signal iOS app
The first impression are the modules the app is separated into. Swift’s standard libraries (and Cocoapods dependencies) can be shown too, but are hidden by default. These modules are the building blocks on the highest level. We will dive deeper into those later on and see building blocks for every Xcode group down to the classes at the lowest level.
What we see here is the four modules the app consists of and what is immediately noticeable, is the interconnection of each pair of modules. While it’s a good idea to break down big projects into several modules, these should have as few dependencies as possible. Modules should (as far as possible) work on its own, consisting of features that belong together. Features of different modules should (as far as possible) stay independent and therefor should have no connection among each other. The current situation leads to a very high CCD value which is definitely a thing to avoid.

Dependencies are unavoidable, but the number of dependencies should be as low as possible. Since every dependency introduces some complexity. If a class A depends on class B, changes on class B could lead to bugs and incompatibilities in class A. If class B has 10 dependent classes, every change on B could lead to followup changes on those 10 further classes. If furthermore class B depends on a class C, these dependencies sum up and can lead to maintainability nightmares.

The correct term is Cumulative Component Dependency or CCD in short.
It’s defined as follows:
CCD is the sum over all components Ci in a subsystem of the number of components needed in order to test each Ci incrementally. This is true for direct and indirect dependencies. 
SwiftAlyzer calculates this metric for classes, Xcode groups and modules.

The difference between Signal module and Signal Messaging module is not clear, but SignalShareExtension module will probably implement an iOS share extension according to App Extension Programming guide. The NotificationServiceExtension module will be used to implement notification previews, using iOS notification services. So what’s more interesting here is the first mentioned two modules. So let’s dive deeper.

As mentioned before, I didn’t take a look at the source code. But that would not help here too much, since we’re looking at bigger structures than classes. At this level it’s not as easy to guess the purpose of a structuring unit. We can make an educated guess looking at the names and hope that the content follows the semantic proposed by the naming.
At this level I usually resort to architecture documentation like ARC42. But in one of SwiftAlyzer’s upcoming versions, there’ll be a documentation feature. Hovering over or selecting a unit fades in its description – provided as contained readme or so.

Analysing the Signal module and its packages

A deeper look into the „Signal“ module, one of Signal app’s main modules, unfolds a series of packages. There’s a separation of test code from production code and some further packages filled with resources.
A deeper look into the Signal module reveals six packages.

Actually they’re Xcode groups but I like to call it packages which should not be confused with Swift packages. In the Java world packages are the means to structure classes into groups of common functionality. In Swift projects we got Xcode groups to structure classes into bigger units. SwiftAlyzer makes use of classes, Xcode groups and modules to give a higher level overview of the project and its dependencies.

Four resource packages filled with fonts, sounds, Lottie animations and support files. The remaining two are distinct into test and production code. Hiding all resource and test packages and further extending the src package shows the following:
Eight packages inside the src package: Storyboards, User Interface, util, network, Models, Jobs, environment, Calls.
The first thing that comes to mind, is that the Signal messaging module has a bi-directional dependency to almost every package. And a circular dependency to every package due to inter-dependencies among the packages. As mentioned earlier, this breeds a maintenance nightmare and reads as very high CCD value.

The cause of the dependencies between these packages and the Signal Messaging module is left as exercise for the reader 😉 I’ll take a closer look at the inner-package dependencies of the src package further blow.


The second thing that strikes me as odd, is the organisation of content by source type, i.e., user interface, model, Jobs, etc, instead of a feature-based separation. This type of partition does not grow well. When implementing a new feature, it’s models, user interfaces, etc are distributed among several packages, mixed with classes of every other feature. This has two main drawbacks. Firstly, there’s no limit on the growth of a package, which makes it harder to navigate around the Xcode project. Secondly, there’s no (semantic) correlation between the classes of a package, which makes it impossible to plan dependencies on a package or feature level.
A look into the UserInterface > ViewControllers package confirms this issue. There’s a huge amount of ViewController classes, all stuffed together without a semantical connection. With a huge amount of files per package, and a huge amount of dependencies, the project’s complexity explodes and even a package-based visualization gets to its limit. But that is not solely a visualization problem, it’s also an understanding problem. It’s easier to comprehend a feature that consists of 10 files instead of 100. It’s easier to navigate and grasp a project one feature at a time instead of being confronted with all the view controllers at the same time. If a project is separated into distinct features, each as a separate package, it becomes possible to trace and monitor a feature’s dependencies on other parts of the app by tracing it’s package dependencies. If all view controllers of all features are bundled into the same package, it’s impossible to distinguish the good dependencies from the superfluous or wrongly created ones.

Deep dive into a package to discover applied design patterns and infringements

Investigating the inter-dependencies of packages inside the „src“ package. The connections from Model to network package alongside User Interface to network package clearly indicate a lack of communication architecture.
At this level the dependencies disclose a lack of communication plan. Without looking into the source code and investigating the underlying design patterns, a connection from Model to Network indicate a smart, reactive (View) Model. MVVM as a design pattern suggests View layer classes (View Controllers) to use View Models, which in turn take care of data retrieval, typically isolated by Use Case or Interactor classes. Here we see View layer classes (originated from User Interface) using Model classes but also directly classes of the Network module. This mix of communication pipelines further increases the project’s complexity. An application of a common pattern helps to understand and navigate the source code, since one can rely to come across the same structures. Assuming MVVM is the preferred way to go, the illegal dependencies are the ones from the UI layer to the Network layer. To eliminate those lets first hide the other packages. It won’t help much to expand the View Controller package due to its size. Instead the information panel can be used to investigate the incoming and outgoing edges section as seen in the following screenshots:
The incoming edges section lists the ContactViewController and GifPicker classes as directly accessing the Network layer. One improvement can be to move that dependency into the Model layer and eliminate the direct connection to the Network layer. This makes the communication pattern more uniform and thus easier to understand and maintain.

Where to go from here:

If it made you curious feel free to sign up on swiftAlyzer.com and try it out on your own! There are more things that can and should be investigated, e.g. why the util package is not a sink.
Also feel free to reach out if you have any questions or comments. Love to hear feedback from other developers ❤️

SwiftAlyzer is progressing

In April I talked about my newest projekt, SwiftAlyzer, a tool to analyze the quality of software projects written in the Swift programming language. There’s now a clear milestone plan for the closed alpha and public beta releases. Right now, we’re heading for the alpha release and it looks pretty neat already. If you’re interested in joining the closed alpha programming, just drop me a line on Twitter pm or here: swiftalyzer-alpha@gretzki.name
In the last few days worked on these little loading animation. I’ll shortly write a little tutorial on how to create this image layer masking effect. Stay tuned ✌️

Smartified Garage Door

Making the best out of Corona-wise cancelled sports evenings, there was suddenly enough time to smartify my garade door. It already has connectors on the garage door hardware. That way, I could connect a button to the board that is used to open and close the garage. But what was missing is a way to control it remotely. Since the remote went missing it was nearby to integrate the button into my smart home setup: Homematic actuators and a raspberry pie transferring all traffic via MQTT.
As there’s already the possibility to control radio-relays via MQTT, the next move was to replace the connection from the button to board with a circuit integrating the relay HM-LC-Sw1-FM. https://de.elv.com/homematic-unterputzschalter-1fach-hm-lc-sw1-fm-fuer-smart-home-hausautomation-076793
But there was one problem. The relay works with an input and output voltage of 230V. That’s too much to control the board on the garage opener. So I had to integrate another relay that could switch an arbitrary input voltage but works with a rated Control Supply Voltage of 230V. I finally came up with an relay by Entrelec.

Now to the fun part. Connecting all parts together according to the wiring on the left. The Entrelec relay is directly connected to the garage opener board. The control supply is provided by the Homematic relay. The switch input of the Homematic relay is provided by the hardware button and finally some 230V to feed the relay. That’s it.

In order to test it, there’s no faster prototyping than to use Node-Red. It enables visually wiring up a control that either automates a workflow or provides a rudimentary GUI. https://nodered.org In this case, it’s a simple UI consisting of one toggle labeled „Garage“ sending out a message to the MQTT broker to fire up the Homematic relay.
Since that’s quite a boring interface, the next step was to write a control app, fooling around with Combine and SwiftUI. But that’s a story for another time 😉

Swift Dependency Analysis

Almost 3 years ago I started a tool to analyse dependencies of Swift projects. For bigger projects it’s essential to plan dependencies between classes and among modules beforehand. Otherwise a project’s inter-dependencies grow wild and after a while, everything depends on everything.
https://twitter.com/c_gretzki/status/837276844130983936
Why that’s bad you might ask? Because then it’s impossible to replace a class with different functionality, since too many other depend on it. And thus, it gets harder to implement new features, adapt existing features and keep the bug count low. So that’s planning, but what get’s implemented is another story. It’s easy to forget about planned dependencies while implementing and that’s even more true when working in teams of 5, 10 or more people. That’s where tools for visualizing dependencies come into play. Every now and then, one can use these tools to check the actual inter-dependencies of a project and compare them with the planned ones. The existing tools all have one big shortcoming: They ignore ordering structures like modules. All classes are layed out in one space, which gets confusing when visualizing projects with more several hundreds classes:
Demo from https://github.com/PrzemyslawCholewaDev/swift-dependency-visualizer
While this visualisation looks quite amazing it renders quite useless overwhelming when trying to check for unplanned dependencies. What’s more helping is a visualisation that considers modules and Xcode groups. Xcode groups can be used to organise a project’s classes in package-like structures.
Xcode project organising its classes into several nested groups
Like in the sample project above, one can see different features of the app organised in separate groups. There’s a Splash screen organised in the Splash group and an Integration group to accomodate a feature to setup smart kitchen appliances and a Network group to shelter the classes communicating to backends, etc. Inter-dependencies can be planned on these structures too. While it’s easily comprehensible why an Integration group is dependent on the Network group, the Splash group shouldn’t.
Swift dependency analysis tool showing one group, one contained file and its embedded class, enum and protocol definitions.
The above dependency tool shows dependencies between classes, enums and protocols. Furthermore, it depicts the groups and files as rectangles collapsable and expandable. When collapsed, the inter-dependencies of all contained elements to other elements outside this structure are still visible but depicted as dependency of the structuring element.
https://twitter.com/HeyDaveTheDev/status/1244909898464452608
This tool is worked on by David Piper as part of his master thesis. I’m glad to be his advisor and very confident that at the end of his thesis, we’ll see a wonderful tool to supervise the dependencies of Swift projects. What’s even better: As soon as the master thesis is completed, the project will be open-sourced and as a contributor, I’ll gladly keep you updated with more to come feature. So stay tuned ✌️

If your iOS code signing fails today

If your iOS code signing fails today, it may be due to an expired Apple Intermediate Certificate.

What you need for code signing beside your valid developer or distribution certificate is the
Apple Worldwide Developer Relations Certification Authority. It expired yesterday and there’s probably already a new one side by side in your keychain. (If not, download and install the new one here: WWDR Certificate (Expiring 02/07/23)) Alas, the expired one interferes with the chain of trust and as a result you get a

„This certificate has an invalid issuer.“

To get rid of this error, you simply have to delete the expired one
in three easy steps:

  1. Open the Keychain Access utility
  2. In the menu, select View -> Show Expired Certificates
    Screen Shot 2016-02-15 at 10.50.14
  3. Make sure to delete the expired “Apple Worldwide Developer Relations*” certificates from all keychains (probably login and system).
    Screen Shot 2016-02-15 at 10.50.06 copy

Now everything should work like a charm again 😉

Find out iOS SDK version from IPA

Recently I updated xcode on our CI server and additionally provide the option to use older xcode versions per project.
To verify that the option works I wanted to find out the iOS SDK version from the provided ipa.

Here we go:
Assuming the app is named APPNAME and the ipa my-app.ipa.

  1. rename my-app.ipa to my-app.ipa.zip
  2. unzip my-app.ipa.zip (Now we’ve got a folder named Payload)
  3. execute the following bash command:
    otool -l Payload/APPNAME.app/APPNAME | fgrep --after-context=3 LC_VERSION_MIN_IPHONEOS
  4. (Alternative)
    plutil -p Payload/APPNAME.app/Info.plist | grep DTSDKName

The output is something similar to:

cmd LC_VERSION_MIN_IPHONEOS
cmdsize 16
version 7.0
sdk 8.4
--
cmd LC_VERSION_MIN_IPHONEOS
cmdsize 16
version 7.0
sdk 8.4

UIWebView Cross Site Scripting Vulnerability

When integrating UIWebViews you have to pay attention to how the desired webpage is being loaded.
That’s why Apple lately added the following lines to the documentation of UIWebView:

To help you avoid being vulnerable to security attacks, be sure to use this method [-loadHTMLString:baseURL:] to load local HTML files; don’t use loadRequest:.

Loading a website via loadRequest: bears the risk of Cross Site Scripting, since it does not enforce the Same Origin Policy, i.e., access to resources of other websites or within the bundle container of the app is possible.

When installing an app on iOS, the following containers are being generated:

  • Bundle container
  • Data container
  • possibly an iCloud container

Without enforcing the Same Origin Policy a HTML file running inside a UIWebView can access resources within the bundle container of the app.

Example Attack Scenario

Screen Shot 2015-08-04 at 13.22.40
Hacking an app’s imprint webview with the aid of Charles.

Applying a Man-in-the-middle attack I could pass a primed website off as the desired app’s imprint website. An attacker could now prompt for sensitive data and capture it.

Furthermore, the attacker could access sqlite cache files or other sensitive resources inside the bundle container. But since this attack requires guessing the id of the sandbox, which is part of the required URL, this is not very likely to happen.

Solution

A solution is to use the methodsloadData:baseURL:orloadData:MIMEType:textEncodingName:baseURL: to load external websites and specifying the baseURL property to point to the host of the desired website, preventing access to resources on different hosts.

Alternatively you could implement webView:shouldStartLoadWithRequest:navigationType: of the UIWebViewDelegate protocol, inspecting every request’s host address and whitelisting which to allow.

A Signal Light for your Jenkins Build Job

IMG_0340.png-2

Idea

A working master branch in a continuous integration environment is key for fast development. While we hack line after line into the project, we merge back to master branch often even while the feature branch is still in development.

Merging early and often helps to avoid merge conflict hell because otherwise feature branches  move too far apart. But this comes at the risk of breaking the master branch build. If that happens, the developer in charge has to stop his ongoing task and fix stuff immediately.

Until recently we used emails to notify the team of a failing build. But since email is old-fashioned, we hacked a signal light to show us the current build status. Follow the instructions below if you want to build your own Jenkins Traffic Light:

 

Prerequisites

Hardware Requirements

[table caption=“Things you’ll need“ colalign=“left|left|center|left“]
stuff,description,price
arduino, e.g.: uno rev 3. There are cheaper alternatives but some things may work differently, 20€
Ethernet Shield,, 33€
Toy traffic light, e.g. this one http://www.pearl.de/a-NC2046-4480.shtml does not require a separate power supply but the arduino digital pin output power, 4.90€
Soldering iron,I just assume you already got one. If not and you just gain first experiences I recommand one with adjustable heat,
Small screwdriver, You should really have a set of different sizes,
Some sort of case,,
Power supply,e.g. http://www.amazon.de/Aukru-Netzteil-Arduino-Platine-Neufassung/dp/B00PADO5CG/ref=sr_1_1?s=ce-de&ie=UTF8&qid=1432481528&sr=1-1&keywords=arduino+netzteil,8.99€
Cable stripper,A knife will do the trick too,
Bell wire,you get way more than you need for this project,1€
heat shrink tube & lighter, duct tape will work too,1€
drilling machine, knife could work too,
A Jenkins build job, that’s what this idea is all about right?, priceless
[/table]

Further requirements

  • A working build infrastructure to execute code on the Arduino.

For hacking on my mac, I prefer a simple text editor with syntax highlighting like Sublime Text and the command line tool INO. But since there are lots of good tutorials on how to setup your build infrastructure, I’ll skip this step. For beginners it’s probably easiest to start with the official IDE.

  • A basic knowledge of Arduino programs.

I don’t want to cover the basics here. There are tons of beginners guides out there that do that in much detail; Why not start with the official getting started guide.

 

Instructions

First aim: Toggle lights timer-based without any networking or consideration of Jenkins build status.

Decomposition

  1. Decompose the traffic light
  2. Dissolve cables from inside the traffic light off of the Platine.
  3. Connect the cables
    • Connect red cable to the plus port of the Arduino.
    • Connect green cable to digital pin 1 of the Arduino.
    • Connect yellow cable to digital pin 2 of the Arduino.
    • Connect white cable to digital pin 3 of the Arduino.
  4. Compile and upload the following script:
int PIN_GREEN_LED = 1;
int PIN_YELLOW_LED = 2;
int PIN_RED_LED = 3;

void setup()
{
pinMode(PIN_RED_LED, OUTPUT);
pinMode(PIN_GREEN_LED, OUTPUT);
pinMode(PIN_YELLOW_LED, OUTPUT);
}

void loop()
{
setSignalRed();
delay(1000);
setSignalGreen();
delay(1000);
setSignalYellow();
delay(1000);
}

void setSignalRed()
{
//HIGH=OFF
digitalWrite(PIN_GREEN_LED, HIGH);
digitalWrite(PIN_RED_LED, LOW);
digitalWrite(PIN_YELLOW_LED, HIGH);
}

void setSignalGreen()
{
digitalWrite(PIN_RED_LED, HIGH);
digitalWrite(PIN_GREEN_LED, LOW);
digitalWrite(PIN_YELLOW_LED, HIGH);
}

void setSignalYellow()
{
digitalWrite(PIN_RED_LED, HIGH);
digitalWrite(PIN_GREEN_LED, HIGH);
digitalWrite(PIN_YELLOW_LED, LOW);
}

 

After upload you should see the lights switching from red to green to yellow and back to red again.
If everything succeeded, congrats! 😀
If not, ping me on twitter or below in the comments section!

Next aim: Find out the right URL for your Jenkins project whose build status you want to observe.

For this we put the Arduino aside for a sec and try out the following URL in our preferred web server:

  • Base Address of your Jenkins Server
    http://YOUR-JENKINS-SERVER-URL
  • Address of project’s last build status
    /job/YOUR-PROJECT-BUILD-JOB-NAME/lastBuild
  • Suffix to tell Jenkins to output JSON and only the interesting part of it.
    /api/json?tree=result

In case it isn’t obvious, you have to replace YOUR-JENKINS-SERVER-URL with the URL pointing to your Jenkins server and YOUR-PROJECT-BUILD-JOB-NAME with the project’s name configured in Jenkins. The remaining parts can stay the same. Put the parts together and try it out on your desktop machine or laptop. If it doesn’t work from there, it won’t work for Arduino neither.
You should see something like this:

{"result":"SUCCESS"}

So make sure this works before you proceed.

The last mile: Packaging all together.

IMG_2210

  1. Drill a hole through the top of the casing.
  2. Glue the signal light to the top of the casing
    Make sure the cables peek through the hole.
  3. Extend the cables
    Otherwise it will get hard to put everything together.
  4. Use heat shrink tube or duct tape to cover the soldering joints.
  5. Install the network shield
    • Stack the network shield on top of the Arduino.
    • You’ll have to use the digital ports on the network shield now.
    • Make sure to use the same port numbers as before.
  6. Prepare the bottom part of the casing
    As the Arduino will go in there and the casing will get closed, drill holes into the side of the casing for power supply and the network cable.
    Put the Arduino into the casing to check if the holes are at the right position.
  7. Connect the wires
    Connect the wires as before.
    To spare you some scrolling:
    Connect red cable to the plus port of the Arduino.
    Connect green cable to digital pin 1 of the Arduino.
    Connect yellow cable to digital pin 2 of the Arduino.
    Connect white cable to digital pin 3 of the Arduino.
  8. Adapt, compile and upload the following script:
#include <SPI.h>
#include <Ethernet.h>
// Enter a MAC address for your controller below.
byte mac[] = {  0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };
char serverName[] = "YOUR-JENKINS-SERVER-URL";

String readString = String(100);
EthernetClient client;

int PIN_RED_LED = 2;
int PIN_GREEN_LED = 1;
int PIN_YELLOW_LED = 3;
int REQUEST_DELAY_IN_MICROSECONDS = 1000 * 10;

void setup() {
   // give the Ethernet shield a second to initialize:
   delay(1000);

   configurePINs();
   setSignalYellow();
   if (!initializeEthernet())
   {
      // Failed to configure ethernet.
      // Prevent entering main loop by never leaving setup procedure
      while(true)
      {
         setAllSignalsOff();
         delay(1000);
         setSignalRed(); 
         delay(1000);
      }
   }
}

bool initializeEthernet()
{
   return (Ethernet.begin(mac) != 0);
}

void configurePINs()
{
   pinMode(PIN_GREEN_LED, OUTPUT);
   pinMode(PIN_RED_LED, OUTPUT);
   pinMode(PIN_YELLOW_LED, OUTPUT);
}

void loop()
{
 // if there are incoming bytes available 
 // from the server, read them and print them:
   String url = "BUILD-JOB-JSON-OUTPUT-RELATIVE-PATH";

   while(connectToURL(url) == false)
   {
      delay(REQUEST_DELAY_IN_MICROSECONDS);
   }

   if (client.available()) {
      char c = client.read();
      readString.concat(c);
      // Serial.print(c);
   }

   // if the server's disconnected, stop the client:
   if (!client.connected()) {
      // connected to server, read in Jenkins's output
      bool isSuccessful = readString.indexOf("SUCCESS") > -1;
      readString.remove(0);
      if (isSuccessful)
      {
         setSignalGreen();
      } else
      {
         setSignalRed();
      }

      client.stop();
      delay(REQUEST_DELAY_IN_MICROSECONDS);
   }
}

bool connectToURL(String url)
{
   if (client.connected())
   {
      return true;
   }

   if (client.connect(serverName, 8080)) {
      // connected to server, make HTTP request
      String request = "GET ";
      request.concat(url);
      request.concat(" HTTP/1.0");
      client.println(request);
      client.println();
      return true;
   } 
   else {
      // no connection to server
      return false;
   }
}

void setSignalYellow()
{
   digitalWrite(PIN_GREEN_LED, HIGH);
   digitalWrite(PIN_YELLOW_LED, LOW);
   digitalWrite(PIN_RED_LED, HIGH);
}

void setSignalRed()
{
   digitalWrite(PIN_GREEN_LED, HIGH);
   digitalWrite(PIN_YELLOW_LED, HIGH);
   digitalWrite(PIN_RED_LED, LOW);
}

void setSignalGreen()
{
   digitalWrite(PIN_RED_LED, HIGH);
   digitalWrite(PIN_YELLOW_LED, HIGH);
   digitalWrite(PIN_GREEN_LED, LOW);
}

void setAllSignalsOff()
{
   digitalWrite(PIN_RED_LED, HIGH);
   digitalWrite(PIN_YELLOW_LED, HIGH);
   digitalWrite(PIN_GREEN_LED, HIGH);   
}

 

From the build status URL you found out in the previous step, replace YOUR-JENKINS-SERVER-URL with the base address and BUILD-JOB-JSON-OUTPUT-RELATIVE-PATH with the remaining part.

Plug in the network cable and test the output. If everything works, you should see the green light for successful builds and the red for unsuccessful ones.
If it does not work, there could be several reasons

  • Arduino does not have a working ethernet connection
  • Jenkins Server not reachable (from same network as Arduino is on)
  • There’s no build job yet
  • Typos in the URLs of the Arduino script

Please check the above.
This script is working fine for me, but there might be other circumstances under which it isn’t.
Have fun with your new Jenkins traffic light 🙂

Key-Value Observing Affected Keys

I like to write handy names for my properties like so:

@property (nonatomic, assign, getter = isLoading) BOOL loading;

As you can see I’ve defined a special name for the getter: isLoading.

There’s only one problem with this:

If another class is observing this class key path loading, it won’t get notified about changes, unless you overwrite your setter like so:

- (void)setLoading:(BOOL)loading
{
    [self willChangeValueForKey:NSStringFromSelector(@selector(isLoading))];
    _loading = loading;
    [self didChangeValueForKey:NSStringFromSelector(@selector(isLoading))];
}

Yesterday I stumbled upon a new way to solve this and a very related problem if different keys are affecting each other.

Registering Dependent Keys

You can implement a class method that follows the naming convention keyPathsForValuesAffecting<Key> to trigger notifications automatically for a (to-one relationship to a) dependent keyPath.

The above snippet could be abandoned using the following implementation:

+ (NSSet *)keyPathsForValuesAffectingIsLoading 
{
    return [NSSet setWithObjects:NSStringFromSelector(@selector(isLoading)), nil];
}

As you can see, the above method returns an instance of NSSet, allowing to specify a bunch of dependent properties that might change dependently.

Here’s the link to the Apple documentation on this topic: Key-Value Observing Programming Guide