Optimizing Binaries - High Level Xcode Build Pipeline

This the first post of a series I’m doing on how to optimize your app’s binaries. The post is more of a high level intro. Depending on the action (build, run, test, profile, analyze, archive) of your scheme, the process will have all or some of the following steps: Dependency analysis What happens when you press build? So the first step is for the build system to take the build description, your Xcode project file. Parse it, take into account all the files in your project, your targets and the dependency relationships. Your build settings, and turn it into a tree-like structure called a directed graph. And this represents all the dependencies between the input and output files in your project and the tasks that will be executed to process them. Next the low-level execution engine processes this graph, looks at the dependency specifications and figures out which tasks to execute. The sequence or order in which they must be run and which tasks can be run in parallel. Then proceeds to execute them. From WWDC 2018 - Behind the Scenes of the Xcode Build Process 4:57 ...

Difference between an app bundle and a binary

Whats the Difference Between an App (bundle) and a Binary

A binary is the final product from linking all your source code. It’s executable. You can run commands against it. An app, is merely a wrapper / directory, which includes that binary and other things. How do you create a binary? First it’s important to understand what a binary is. You’ve used them every day in the terminal. Examples: ls, cp, mkdir. You pass certain parameters to them. They don’t have any file extension. They’re in machine code i.e. zeros and ones. With some simplification, this is how we create a binary from our source code: ...

The power and expressiveness of Swift ranges

Ranges in swift are super simple to create. Yet they come in various forms. let r1 = 1...3 let r2 = 1..<3 let r3 = ...3 let r4 = 3... let r5 = ..<3 They all have range like characteristics, but have slightly different traits. It’s because they’re actually different types. Different Range Types let r1 = 1...3 // ClosedRange<Int> let r2 = 1..<3 // Range<Int> let r3 = ...3 // PartialRangeThrough<Int> let r4 = 3... // PartialRangeFrom<Int> let r5 = ..<3 // PartialRangeUpTo<Int> By having different types, the compiler can enforce certain behavior/restrictions within each type. Looking at the names without seeing the syntax that generates them can be confusing. Hopefully the code above helps with that. ...

How cp case-insensitivity can cause chaos!

Been doing Advent of Code in the last couple of days. I completed Day 6. I have been doing it from an Xcode project. However I was thinking it would be nice if I could do it from command line. So I started to do some code clean up. First I started with renaming the folder from AOC to aoc. I did: cp -r AOC aoc I saw a new aoc directory created. I was happy. It was easy. Or at least it seemed easy. I went back to my AOC directory. I noticed a whole bunch of changes that I didn’t make. Confused! I tried figuring it out. I couldn’t. Decided to remove the changes with: ...

How to Think Recursively - Part 2

Please read How to Think Recursively before reading this post. This post re-applies the steps mentioned in the previous post on a more challenging question. Question Return all possible ways we can generate a well-formed parenthesis? Examples: if n = 1 then we can only form () if n = 2 then we can form (()) and ()() if n = 3 then we can form ((())), (())(), ()(()), (()()), (), (), () Let’s try applying our 4 steps: ...

How to Think Recursively - Part 1

These articles are about the gotchas I faced when trying to think recursively. The logic in principle should apply to most recursive problems. In this post, I will use the following question as a point of reference: Count how many ways you can climb a staircase. You can jump either one step at a time or two steps at a time. Example if there are 3 stair cases then you can either jump: ...

Why does pod lib lint suddenly fail to build?

I made some changes to the repo of our private pod. Pushed up my branch. Tests all ran. Then my colleague asked for some updates to my PR (pull request). I made changes and pushed it to GH. I wanted to merge the changes. But then CI was failing. So I ran CI again. It failed again. They say third time is the charm. So I ran it two more times. It still failed. I thought I had changed something in the project file, because I was getting some Swift compatibility error. I erased the derived data and clean build. I was able to build and run all tests. I wasn’t sure why things were still failing. ...

How Understanding State Machines Helps With Building Trees and Graphs

My team was dealing with a large flow, where user can transition from multiple states or sometimes skip certain states. We didn’t have a centralized controller, every screen just had logic on where it should go next. This made it difficult for us to see all our logic at once. We asked around and was told state machines are a good fit for our situation. State machines are void of any UX. You just pass an event to it. Based on the event and the current state, you update to a new state along with an optional command to act upon. ...

self-contained rv

What Resources Does Apple Provide for teaching iOS to students?

Note: This post has got a bit longer than what I originally intended. You might want to skip to the very end to see the verdict and table first and then read again. I’ve started an iOS training course in my local community. At the beginning I thought it would be easy for me to just start training people with whatever I know. Later I decided to look at some available resources. I found great amount of material prepared by Apple. Only problem was that there were soo many that I got confused. In this article I plan on cataloging and comparing the different resources provided by Apple. ...

Which Way Am I Sorting?

I always got confused as to what’s the end result my sort. I wasn’t sure if it would end up being ascending or descending. The ultimate trick is to not think of up vs down. Instead think of increasing/decreasing from left to right. We perceive arrays as horizontal beings. Hence left and right make more sense vs up and down let nums = [1,4,2,3] let sorted_nums = arr.sorted(by: { $0 < $1 // left is smaller [1,2,3,4] i.e. ascending }) If you see $0 < $1 then left side is smaller than the next item. i.e. it’s ascending. ...