NSApplicationDelegate and notification

Issue #34

In an iOS project, we often see this in AppDelegate

1
2
3
4
5
6
7
8
9
10
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

return true
}
}

But in a Cocoa project, we see this instead

1
2
3
4
5
6
7
8
9
10
11
12
13
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {



func applicationDidFinishLaunching(aNotification: NSNotification) {
// Insert code here to initialize your application
}

func applicationWillTerminate(aNotification: NSNotification) {
// Insert code here to tear down your application
}
}

In this case the param is of type NSNotification

Delegate and notification

Reading Cocoa Core Competencies - Delegation

The delegate of most Cocoa framework classes is automatically registered as an observer of notifications posted by the delegating object. The delegate need only implement a notification method declared by the framework class to receive a particular notification message. Following the example above, a window object posts an NSWindowWillCloseNotification to observers but sends a windowShouldClose: message to its delegate.

So the pattern is that the delegate should strip the NS and Notification, like NSWindowWillCloseNotification to windowShouldClose:

Understanding SDK and Deployment Target in iOS

Issue #33

I see that my answer to the question What’s the meaning of Base SDK, iOS deployment target, Target, and Project in xcode gets lots of views, so I think I need to elaborate more about it

Good read

Base SDK

  • We can’t configure this anymore, as Xcode will use the latest SDK. For Xcode 7, the SDK is iOS 9
  • If we upgrade Xcode, it will use the newer version of the SDK. Like Xcode 7.2, the SDK is iOS 9.1
  • Choosing the latest SDK for your project lets you use the new APIs introduced in the OS update that corresponds to that SDK. When new functionality is added as part of a system update, the system update itself does not typically contain updated header files reflecting the change. The SDKs, however, do contain updated header files.

Deployment Target

  • We can set in Xcode -> Target -> Deployment Info -> Deployment Target
  • State that we support this iOS version

What does it mean

So, a modern App might use iOS 9 as the Target SDK, and iOS 7 as the deployment target. This means that you can run on iOS 7, iOS 8 and iOS 9, and that you have available to you any iOS 9 calls when actually running on iOS 9.

.

Each .sdk directory resembles the directory hierarchy of the operating system release it represents: It has usr, System, and Developer directories at its top level. OS X .sdk directories also contain a Library directory. Each of these directories in turn contains subdirectories with the headers and libraries that are present in the corresponding version of the operating system with Xcode installed.

.

The libraries in an iOS or OS X SDK are stubs for linking only; they do not contain executable code but just the exported symbols. SDK support works only with native build targets.

So the SDK is just like stub and header only. It means that we can use certain APIs, but on OS that does not have the real symbols for those APIs, it crashes

available

Swift 2 introduces available construct that guards against failure when trying to use newer APIs.

Note that available is runtime, not compile time. All the code is inside your executable

1
2
3
4
5
if #available(iOS 9, OSX 10.10, *) {
// Code to execute on iOS 9, OS X 10.10
} else {

}

deprecated APIs

Always check to see if you are using deprecated APIs; though still available, deprecated APIs are not guaranteed to be available in the future

Compile time vs Runtime

1
2
3
4
5
#if (arch(i386) || arch(x86_64)) && os(iOS)
// code inside gets inserted into executable when builds for simulator
#else
// code inside gets inserted into executable when builds for device
#endif
1
2
3
4
5
#if os(OSX)
import Cocoa
#elseif os(iOS)
import UIKit
#endif
1
2
3
4
5
6
// All the code gets inserted into executable, but is run depending on the version of the OS
if #available(iOS 9, *) {
// use UIStackView
} else {
// show your manual Auto Layout skill
}

Weakly vs strongly linked

For example, suppose in Xcode you set the deployment target (minimum required version) to “OS X v10.5” and the base SDK (maximum allowed version) to “OS X v10.6”. During compilation, the compiler would weakly link interfaces that were introduced in OS X v10.6 while strongly linking interfaces defined in earlier versions of the OS. This would allow your application to run in OS X v10.5 and take advantage of newer features when available.

.

None of the (platform) frameworks is really “included in the bundle”. Instead, your app has a reference (“link”) to a framework once you add it to the “Link Binary with Library” build phase. The frameworks are pre-installed on the devices. When you run an app, all the app’s framework references are resolved by the dynamic linker (on the device), which means the framework code is loaded so your app can use it.

Reference

App backed by website in iOS 9

Issue #32

iOS 9 introduces new ways for your app to work better, backed by your websites

Smart App Banners

If the app is already installed on a user’s device, the banner intelligently changes its action, and tapping the banner will simply open the app. If the user doesn’t have your app on his device, tapping on the banner will take him to the app’s entry in the App Store

To add a Smart App Banner to your website, include the following meta tag in the head of each page where you’d like the banner to appear:

1
<meta name="apple-itunes-app" content="app-id=myAppStoreID, affiliate-data=myAffiliateData, app-argument=myURL">

When you support universal links, iOS 9 users can tap a link to your website and get seamlessly redirected to your installed app without going through Safari. If your app isn’t installed, tapping a link to your website opens your website in Safari.

Web Markup

If some or all of your app’s content is also available on your website, you can use web markup to give users access to your content in search results. Using web markup lets the Applebot web crawler index your content in Apple’s server-side index, which makes it available to all iOS users in Spotlight and Safari search results.

Shared Web Credentials

Shared web credentials is a programming interface that enables native iOS apps to share credentials with their website counterparts. For example, a user may log in to a website in Safari, entering a user name and password, and save those credentials using the iCloud Keychain. Later, the user may run a native app from the same developer, and instead of the app requiring the user to reenter a user name and password, shared web credentials gives it access to the credentials that were entered earlier in Safari.

Reference

Disingenuousness

Issue #31

I’m very happy to be on open source movement, and it ‘ll be great to hear about what people have achieved

And @merowing_ also mentioned in Writing Xcode plugin in Swift

Attribution

Writing this was much simpler because I was able to look at other people plugins, mostly those related to console, without them being open sourcing it would be more work to figure this stuff out with hopper.

Open source helps us move forward, learn and share together

The dark side of the Force

Luke: Is the dark side stronger?

Yoda: No, no, no. Quicker, easier, more seductive.

It’s a pain to see plagiarism around

Open source softwares are in fact intellectual properties, and the authors should get acknowledgement for the work that they do.

It’s not fair to take the credit of other’s work and not giving any attribution

By its nature, open source software has a unique relationship with intellectual property rights

One thing that’s not up for debate in most circles is that it’s dishonest and disingenuous to take someone else’s project, modify it slightly, and call it your own.

Further, regardless of whether or not a project crosses that line, it must (by the terms of most open source licenses) acknowledge the original work/author.

And the reaction

It’s always sad to see blatant plagiarism, and I think it really hurts the community more than the author itself. It gives people a good reason to keep the sources private.

Being nice

I often hear people say that

It is easier to find good developer than developer with good attitude

Github also states that

We understand and agree that copying others’ work without permission goes against the spirit of the open source community

Do the right things

Is it MIT ‘s fault? Definitely no

False choice. Giving up freedom does not lead to more security, just less freedom.

Takeaways

  • Don’t take things personally
  • It’s hard to be perfect, but we can learn to do the right things
  • We may do the wrong things, but don’t worry, there ‘ll be help via Issues and Pull Requests

How to do curry in Swift

Issue #30

Haskell is notorious for currying, and Swift has currying, too

I love ReactiveCocoa, RxSwift and I always take time to dig into it. The other day, I was practise making Signal based on this talk UIKonf 2015 - Jens Ravens: Functional Reactive Programming without Black Magic

Take a look at my repo Signal

filter

I was making a filter for a Signal. The idea of filter is that we should update signal if the Event is Next with right filtered value

Signal.swift

1
2
3
4
5
6
7
8
9
10
11
12
13
public func filter(f: T -> Bool) -> Signal<T>{
let signal = Signal<T>()
subscribe { result in
switch(result) {
case let .Success(value):
if f(value) {
signal.update(result)
}
case let .Error(error): signal.update(.Error(error))
}
}
return signal
}

2 params

But having Event as another monad, I think it should be more encapsulated if that switching logic gets moved into the Event. Here the filter takes 2 params

Event.swift

1
2
3
4
5
6
7
8
9
10
func filter(f: T -> Bool, callback: (Event<T> -> Void)) {
switch self {
case let .Next(value) where f(value):
callback(self)
case .Failed:
callback(self)
default:
break
}
}

Signal.swift

1
2
3
4
5
6
7
8
9
public func filter(f: T -> Bool) -> Signal<T> {
let signal = Signal<T>()

subscribe { event in
event.filter(f, callback: signal.update)
}

return signal
}

Currying

With currying, we can make filter a more abstract function, and defer the decision to pass the callback param. It is a little carried away but I find it helpful this way

Now filter accepts 1 param, and it returns a function that takes callback as its param

Event.swift

1
2
3
4
5
6
7
8
9
10
11
12
func filter(f: T -> Bool) -> ((Event<T> -> Void) -> Void) {
return { g in
switch self {
case let .Next(value) where f(value):
g(self)
case .Failed:
g(self)
default:
break
}
}
}

Signal.swift

1
2
3
4
5
6
7
8
9
public func filter(f: T -> Bool) -> Signal<T> {
let signal = Signal<T>()

subscribe { event in
event.filter(f)(signal.update)
}

return signal
}

Curry syntax in Swift 2

Swift 2 supports curry syntax function

1
2
3
4
5
6
7

func sum(a: Int)(b: Int) -> Int {
return a + b
}

let sumWith5 = sum(5)
let result = sumWith5(b: 10)

No more curry syntax in Swift 3

You may want to find out

Reference

How to use push notification in iOS

Issue #29

Here are my notes for working with Push Notification, updated for iOS 9

How to register

  • Register to receive push notification

registerForRemoteNotificationTypes is deprecated in iOS 8+

1
UIApplication.sharedApplication().registerForRemoteNotifications()
  • Register to alert user through UI

If your app displays alerts, play sounds, or badges its icon, you must call this method during your launch cycle to request permission to alert the user in these ways

1
2
3
4
5
let types: UIUserNotificationType = [.Badge, .Sound, .Alert]
let categories = Set<UIUserNotificationCategory>()
let settings = UIUserNotificationSettings(forTypes: types, categories: categories)

UIApplication.sharedApplication().registerUserNotificationSettings(settings)

You don’t need to wait for registerUserNotificationSettings to callback before calling registerForRemoteNotifications

When to register

Never cache a device token; always get the token from the system whenever you need it. If your app previously registered for remote notifications, calling the registerForRemoteNotifications method again does not incur any additional overhead, and iOS returns the existing device token to your app delegate immediately. In addition, iOS calls your delegate method any time the device token changes, not just in response to your app registering or re-registering

The user can change the notification settings for your app at any time using the Settings app. Because settings can change, always call the registerUserNotificationSettings: at launch time and use the application:didRegisterUserNotificationSettings: method to get the response. If the user disallows specific notification types, avoid using those types when configuring local and remote notifications for your app.

didReceiveRemoteNotification

About application:didReceiveRemoteNotification:

Implement the application:didReceiveRemoteNotification:fetchCompletionHandler: method instead of this one whenever possible. If your delegate implements both methods, the app object calls the application:didReceiveRemoteNotification:fetchCompletionHandler: method.

If the app is not running when a remote notification arrives, the method launches the app and provides the appropriate information in the launch options dictionary. The app does not call this method to handle that remote notification. Instead, your implementation of the application:willFinishLaunchingWithOptions: or application:didFinishLaunchingWithOptions: method needs to get the remote notification payload data and respond appropriately.

About application:didReceiveRemoteNotification:fetchCompletionHandler:

This is for silent push notification with content-available

Unlike the application:didReceiveRemoteNotification: method, which is called only when your app is running in the foreground, the system calls this method when your app is running in the foreground or background

In addition, if you enabled the remote notifications background mode, the system launches your app (or wakes it from the suspended state) and puts it in the background state when a push notification arrives. However, the system does not automatically launch your app if the user has force-quit it. In that situation, the user must relaunch your app or restart the device before the system attempts to launch your app automatically again.

If the user opens your app from the system-displayed alert, the system may call this method again when your app is about to enter the foreground so that you can update your user interface and display information pertaining to the notification.

How to handle

Usually, the use of push notification is to display a specific article, a specific DetailViewController, … in your app. So the good practices are

  • When the app is in foreground: Gently display some kind of alert view and ask the user whether he would like to go to that specific page or not
  • When user is brought from background to foreground, or from terminated to foreground: Just navigate to that specific page. For example, if you use UINavigationController, you can set that specific page the top most ViewController, if you use UITabBarController, you can set that specific page the selected tab, something like that
1
2
3
4
5
6
7
8
9
10
11
- func handlePushNotification(userInfo: NSDictionary) {
// Check applicationState
if (applicationState == UIApplicationStateActive) {
// Application is running in foreground
showAlertForPushNotification(userInfo)
}
else if (applicationState == UIApplicationStateBackground || applicationState == UIApplicationStateInactive) {
// Application is brought from background or launched after terminated
handlePushNotification(userInfo)
}
}

Here we create another method `handlePushNotification:`` to handle push notification. When you receive push notification, 3 cases can occur

Case 1: Foreground

Loud push

  • No system alert
  • application:didReceiveRemoteNotification:fetchCompletionHandler: called

Silent push

  • No system alert
  • application:didReceiveRemoteNotification:fetchCompletionHandler: called

Case 2: Background

Loud push

  • System alert
  • No method called
  • Tap notification and application:didReceiveRemoteNotification:fetchCompletionHandler: called
  • Tap on App Icon and nothing is called

Silent push

  • System alert
  • application:didReceiveRemoteNotification:fetchCompletionHandler: called. If app is suspended, its state changed to UIApplicationStateBackground
  • Tap notification and application:didReceiveRemoteNotification:fetchCompletionHandler: called
  • Tap on App Icon and nothing is called

Case 3: Terminated

Loud push

  • System alert
  • No method called
  • Tap notification and application:didFinishLaunchingWithOptions: with launchOptions, application:didReceiveRemoteNotification:fetchCompletionHandler: called
  • Tap on App Icon and application:didFinishLaunchingWithOptions: is called with launchOptions set to nil

Silent push

  • System alert
  • application:didReceiveRemoteNotification:fetchCompletionHandler: called. If app was not killed by user, it is woke up and state changed to UIApplicationStateInactive.
  • Tap notification and application:didFinishLaunchingWithOptions: with launchOptions, application:didReceiveRemoteNotification:fetchCompletionHandler: called
  • Tap on App Icon and application:didFinishLaunchingWithOptions: is called with launchOptions set to nil

System alert

System alert only show if the payload contains “alert”

1
2
3
4
5
6
7
8
9
10
11
12
{
"aps" : {
"alert" : {
"title" : "Game Request",
"body" : "Bob wants to play poker",
"action-loc-key" : "PLAY"
},
"badge" : 5
},
"param1" : "bar",
"param2" : [ "bang", "whiz" ]
}

Silent push payload

For now I see that silent push must contain “sound” for application:didReceiveRemoteNotification:fetchCompletionHandler: to be called when app is in background

1
2
3
4
5
6
7
8
9
{
"aps": {
"content-available": 1,
"alert": "hello" // include this if we want to show alert
"sound": "" // this does the trick
},
"param1": 1,
"param2": "text"
}

Reference

Understanding push and pull signal in reactive paradigm

Issue #28

The idea of Signal may originate from Elm Reactivity, and it has now been widely adopted in iOS

I once asked What are examples of hot and cold signal in ReactiveCocoa?

Whether it is hot vs cold, Signal vs Signal Producer, Observable vs Enumerable, … it’s good to understand how it gets implemented, so that to have a good sense of how they work

Monad

Basically, Signal and its Result are just monads, which are thing that can be mapped and chained.

Signal makes use of deferred execution callback blocks, and push vs pull is just how the Signal updates its value and the order the callbacks are called

Execution callback block is that we pass a function to another function, and it will get called when appropriated

Sync vs Async

Monad can be in either sync or async mode. Sync is easier to understand, but async is somewhat you’re already familiar and used in practice

Basically,

  • Sync: you get the returned value right away via return
  • Aync: you get the returned value via callback block

Here is an example of a simple function

1
2
3
4
5
6
7
8
9
10
11
12
// Sync
func sum(a: Int, b: Int) -> Int {
return a + b
}

// Async
func sum(a: Int, b: Int, completion: Int -> Void) {
// Assumed it is a very long task to get the result
let result = a + b

completion(result)
}

Here is an example of Event

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Sync
public func map<U>(@noescape f: T -> U) -> Event<U> {
switch self {
case let .Next(value):
return .Next(value: f(value))
case let .Failed(error):
return .Failed(error: error)
}
}

// Async
public func map<U>(f: (T, U -> Void) -> Void) -> ((Event<U> -> Void) -> Void) {
return { g in // g: Event<U> -> Void
switch self {
case let .Next(value):
f(value) { transformedValue in // transformedValue: U
g(.Next(value: transformedValue))
}
case let .Failed(error):
g(.Failed(error: error))
}
}
}

Push Signal

Take a look at my Push Signal, called Signal, it is like how Promise A+ Then works

Implementation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public final class Signal<T> {
var event: Event<T>?
var callbacks: [Event<T> -> Void] = []

func notify() {
guard let event = event else {
return
}

callbacks.forEach { callback in
callback(event)
}
}

func update(event event: Event<T>) {
dispatch_sync(lockQueue) {
self.event = event
}

notify()
}

public func subscribe(f: Event<T> -> Void) -> Signal<T> {
// Callback
if let event = event {
f(event)
}

callbacks.append(f)

return self
}

public func map<U>(f: T -> U) -> Signal<U> {
let signal = Signal<U>()

subscribe { event in
signal.update(event: event.map(f))
}

return signal
}
}

Usage

1
2
3
4
5
6
7
8
9
10
11
12
13
let signal = Signal<String>()

signal.map { value in
return value.characters.count
}.subscribe { event in
if case let .Next(value) = event {
XCTAssert(value == 4)
} else {
XCTAssert(false)
}
}

signal.sendNext("test")

Callbacks

Given a chained signals like this

A -(map)-> B -(flatMap)-> C -(flatMap)-> D -(subscribe)

  • The idea is we send event to the source signal, and it propagates events through via callbacks.
  • Triggered by sending event to the source signal.
  • We must keep A as it keeps the others around
  • We subscribe the last D
  • We send event to the first A
  • A ‘s callback gets called, it it in turn calls callback of B with the result of A ‘s map, then B ‘s callback calls C ‘s callback with the result of B
    ‘s flatMap, …

Pull Signal

Take a look at my Pull Signal, called Future

Implementation

Here operation is a task, when called and completed, will notify its completion

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public struct Future<T> {
let operation: (Event<T> -> Void) -> Void

public init(operation: (Event<T> -> Void) -> Void) {
self.operation = operation
}

public func start(completion: Event<T> -> Void) {
operation() { event in
completion(event)
}
}

public func map<U>(f: T -> U) -> Future<U> {
return Future<U> { completion in
self.start { event in
completion(event.map(f))
}
}
}
}

Usage

1
2
3
4
5
6
7
8
9
10
11
12
13
let _ = Future<String> { completion in
// There is some work here
completion(Event(value: "test"))
}
.map { value in
value.characters.count
}.start { event in
if case let .Next(value) = event {
XCTAssert(value == 4)
} else {
XCTAssert(false)
}
}

Callbacks

Given a chained signals like this

A -(map)-> B -(flatMap)-> C -(flatMap)-> D -(subscribe)

  • The idea is we subscribe to the final signal D, and it cause the previous signals to action.
  • Triggered by subscribing to the final signal.
  • We must keep D as it keeps the others around
  • We subscribe the last D
  • D ‘s operation actions, and it cause C ‘s operation to action, … then A ‘s operation actions. It is in A that the task is performed (like fetching network, retrieving database, file access, heavy computation, …) to get the result, and A ‘s completion gets called. Then A’s completion calls B ‘s completion with the result mapped by B ‘s map, … all the way to the subscriber ‘s completion block

How to make iOS Stretchy Header with Auto Layout

Issue #27

Stretchy header is cool. People are familiar with changing frames to achieve this, like Design Teardown: Stretchy Headers. But with Auto Layout, we can achieve this with much nicer declarative constraints

The demo project is StretchyHeader

demo

I use SnapKit to make it clear what constraints we need

scrollView

The scrollView should pin its 4 edges to the ViewController 's view

1
2
3
4
5
6
7
8
9
func setupScrollView() {
scrollView = UIScrollView()
scrollView.delegate = self

view.addSubview(scrollView)
scrollView.snp_makeConstraints { make in
make.edges.equalTo(view)
}
}

scrollViewContentView

The scrollViewContentView must pin its 4 edges to the scrollView to help determine scrollView contentSize

The height of scrollViewContentView is determined by its subviews. The subviews inside must pin their top and bottom to the scrollViewContentView

1
2
3
4
5
6
7
8
9
func setupScrollViewContentView() {
scrollViewContentView = UIView()

scrollView.addSubview(scrollViewContentView)
scrollViewContentView.snp_makeConstraints { make in
make.edges.equalTo(scrollView)
make.width.equalTo(view.snp_width)
}
}

The header must pin its top to the scrollView parent, which is the ViewController 's view

Read the title section, you ‘ll see that in order to make header stretchy, it must be pinned top and bottom

But if we scroll up, there will be a constraint conflict between these pinned top and bottom constraints

So we must declare headerTopConstraint priority as 999, and headerLessThanTopConstraint

1
2
3
4
5
6
7
8
9
10
11
12
13
func setupHeader() {
header = UIImageView()
header.image = UIImage(named: "onepiece")!

scrollViewContentView.addSubview(header)
header.snp_makeConstraints { make in
// Pin header to scrollView 's parent, which is now ViewController 's view
// When header is moved up, headerTopConstraint is not enough, so make its priority 999, and add another less than or equal constraint
make.leading.trailing.equalTo(scrollViewContentView)
self.headerTopConstraint = make.top.equalTo(view.snp_top).priority(999).constraint
self.headerLessThanTopConstraint = make.top.lessThanOrEqualTo(view.snp_top).constraint
}
}

title

The title must pin its top to the scrollViewContentView to help determine scrollViewContentView height

The title must also pin its top the header bottom in order to make header stretchy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func setupTitleLabel() {
titleLabel = UILabel()
titleLabel.numberOfLines = 0
titleLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleTitle1)
titleLabel.text = "One Piece"

scrollViewContentView.addSubview(titleLabel)
titleLabel.snp_makeConstraints { make in
make.leading.equalTo(scrollViewContentView).offset(20)
make.trailing.equalTo(scrollViewContentView).offset(-20)
// Pin to the header to make it stretchy
make.top.equalTo(header.snp_bottom).offset(20)
// Pin to the content view to help determine scrollView contentSize
make.top.equalTo(scrollViewContentView.snp_top).offset(headerHeight)
}
}

scrollViewDidScroll

The header is always pinned to the top, unless you adjust it, here in scrollViewDidScroll

Here I use Constraint, which is a class from SnapKit, but the idea is to change the constant of the NSLayoutConstraint

1
2
3
4
5
6
7
8
9
10
11
12
13
func scrollViewDidScroll(scrollView: UIScrollView) {
guard let headerTopConstraint = headerTopConstraint,
headerLessThanTopConstraint = headerLessThanTopConstraint
else {
return
}

let y = scrollView.contentOffset.y
let offset = y > 0 ? -y : 0

headerLessThanTopConstraint.updateOffset(offset)
headerTopConstraint.updateOffset(offset)
}

By the way, did you just learn the story of One Piece :]

Reference

How to group digits in Swift

Issue #26

When working on Scale I think it’s good to have a way to group the digit so that it is easier to reason

Luckily, Swift already supports this. See The Swift Programming Language - Numeric Literals

Numeric literals can contain extra formatting to make them easier to read. Both integers and floats can be padded with extra zeros and can contain underscores to help with readability. Neither type of formatting affects the underlying value of the literal

1
2
3
let paddedDouble = 000123.456
let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1

Talking about grouping digits after the decimal point, it is interesting too Convention of digit grouping after decimal point

So now we have

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public enum MetricUnit: Double {
case nano = 0.000_000_001
case micro = 0.000_001
case milli = 0.001
case centi = 0.01
case deci = 0.1
case base = 1
case deka = 10
case hecto = 100
case kilo = 1_000
case mega = 1_000_000
case giga = 1_000_000_000
case tera = 1_000_000_000_000
case peta = 1_000_000_000_000_000

static var defaultScale: Double {
return MetricUnit.base.rawValue
}
}

How to make a simple resolver in Swift

Issue #25

The Marvel world

Ant Man

We know Ant Man is Hank Pym

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct AntManSuit {
let name: String
}

struct HankPym {
let suit = AntManSuit(name: "Ant Man ID #101")

func fight() {
print("Fighting with the suit named " + suit.name)
}
}

let hankPym = HankPym()
hankPym.fight()

Everytime HankPym is created, he always uses the Ant Man suit. This time he is so coupled to the role Ant Man

More suits

Well, he does not have to be too dependent on the Ant Man suit. We know Hank Pym is a genius scientist, he has more suits to use. Let’s make it decoupled

Using Dependency Injection

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
protocol Suit {
var name: String { get }
}

struct AntManSuit: Suit {
let name: String
}

struct YellowJacketSuit: Suit {
let name: String
}

struct HankPym {
let suit: Suit

func fight() {
print("Fighting with the suit named " + suit.name)
}
}

let suit = YellowJacketSuit(name: "Yellow Jacket ID #33")
let hankPym = HankPym(suit: suit)
hankPym.fight()

Now Hank Pym can be more flexible on which suit to use.

Dependency Injection

The technique we just saw is called Dependency Injection, in which Hank Pym does not need to create the Suit, it will be provided through constructor or property.

Dependency Inversion Principle

In the first example, Hank Pym is dependent on the concrete implementation of the Suit

In the second example, both Hank Pym and the suits are dependent on the Suit protocol. This way Hank Pym only knows about the Suit protocol, and future suits must be crafted to that it conforms to the Suit protocol

This way the dependency is inverted

High level modules should not depend upon low level modules. Both should depend upon abstractions.

What is the high level policy? It is the abstractions that underlie the application, the
truths that do not vary when the details are changed

Inversion of Control Container

You may ask yourself Why is Inversion of Control named that way?

Framework vs library

People said “the framework calls you but you call the library”

Command line vs GUI

See What is Inversion of Control?

For example, in an old school menu, you might have:

1
2
3
4
5
6
print "enter your name"
read name
print "enter your address"
read address
etc...
store in database

thereby controlling the flow of user interaction.

In a GUI program or some such, instead we say

1
2
3
when the user types in field a, store it in NAME
when the user types in field b, store it in ADDRESS
when the user clicks the save button, call StoreInDatabase

You how have a brief understanding of how IoC means

IoC container

In the 2nd example of the Suit protocol, you can see how there is a inversion of control. What if there is a container that contains all the Suit conformances?

Let’s use my Resolver

1
2
3
4
5
6
7
let resolver = Resolver()
resolver.register {
YellowJacketSuit(name: "YellowJacket ID #404") as Suit
}

let suit = try! resolver.resolve() as Suit
let hankPym = HankPym(suit: suit)

Quite helpful, right? :]

Features

Actually, IoC container helps you more than that.

  • Circular Dependency Injection
  • Auto Injection
  • Object Scope

There are some IoC containers in Swift

Swinject

1
2
3
4
5
let container = Container()
container.register(AnimalType.self) { _ in Cat(name: "Mimi") }
container.register(PersonType.self) { r in
PetOwner(pet: r.resolve(AnimalType.self)!)
}

Swinject requires explicit type declaration. It has SwinjectStoryboard, which helps configuring the dependency for your view controller

Dip

Dip leverages generic and encourage protocols

1
2
container.register { ServiceImp() as Service }
let service = try! container.resolve() as Service

You ‘ll learn a lot just by reading Dip source code, on how factory and factory type are stored and checked using generic

1
2
3
4
5
6
7
8
9
10
11
public func resolve<T, F>(tag tag: Tag? = nil, builder: F->T) throws -> T {
let key = DefinitionKey(protocolType: T.self, factoryType: F.self, associatedTag: tag)
let nilTagKey = tag.map { _ in DefinitionKey(protocolType: T.self, factoryType: F.self, associatedTag: nil) }

guard let definition = (self.definitions[key] ?? self.definitions[nilTagKey]) as? DefinitionOf<T, F> else {
throw DipError.DefinitionNotFound(key)
}

let usingKey: DefinitionKey? = definition.scope == .ObjectGraph ? key : nil
return _resolve(tag, key: usingKey, definition: definition, builder: builder)
}

Build your own simple IoC container

You may have discovered, that the idea of all those framework is to use closure as factory method

1
2
3
4
5
let factory = {
YellowJacketSuit(name: "YellowJacket ID #007") as Suit
}

let suit = factory()

All we have to do is to store these factories closure

Take a look at my gist SimpleResolver.swift

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class SimpleResolver {
var factories = [String: Any]()

func factory<T>(factory: () -> T) {
let key = String(T.self)
factories[key] = factory
}

func resolve<T>() -> T {
let key = String(T.self)
if let factory = factories[key] as? () -> T {
return factory()
} else {
fatalError("Registration not found")
}
}
}

let resolver = SimpleResolver()

resolver.factory {
YellowJacketSuit(name: "YellowJacket IS #009") as Suit
}

let suit = resolver.resolve() as Suit
print(suit.name)

Reference

How to make lighter AppDelegate in iOS

Issue #24

There is Lighter View Controllers, and there is Lighter AppDelegate, too

Since working with iOS, I really like the delegate pattern, in which it helps us defer the decision to another party.

The iOS application delegates its event to AppDelegate, which over time will be a big mess. Usually, the AppDelegate is where you put your root view controller setup, crash tracking, push notification, debugging, … and we just somehow violent the Single Responsibility principle. Moreover, it makes us hard to reason about code in AppDelegate

Service

I like to think of each task in AppDelegate as a service. And the AppDelegate distributes the events into each service via ServiceDispatcher. Simple plain old composition and looping

I tend to have RootService as a place to setup root view controllers

It looks like this

ServiceDispatcher.swift

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class ServiceDispatcher : NSObject, UIApplicationDelegate {
let services: [UIApplicationDelegate]

init(services: [UIApplicationDelegate]) {
self.services = services
}

func application(application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool {

services.forEach { service in
service.application?(application, didFinishLaunchingWithOptions: launchOptions)
}

return true
}

func applicationDidBecomeActive(application: UIApplication) {
services.forEach { service in
service.applicationDidBecomeActive?(application)
}
}

func applicationWillResignActive(application: UIApplication) {
services.forEach { service in
service.applicationWillResignActive?(application)
}
}

func applicationWillEnterForeground(application: UIApplication) {
services.forEach { service in
service.applicationWillEnterForeground?(application)
}
}

func applicationDidEnterBackground(application: UIApplication) {
services.forEach { service in
service.applicationDidEnterBackground?(application)
}
}
}

RootService.swift

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class RootService : NSObject, UIApplicationDelegate {
func application(application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool {

appDelegate().window = UIWindow(frame: UIScreen.mainScreen().bounds)
showHome()
appDelegate().window?.makeKeyAndVisible()

return true
}
}

extension RootService {
func showHome() {
let home = HomeWireframe().makeHome()
let navC = UINavigationController(rootViewController: home!)
appDelegate().window?.rootViewController = navC
}
}

extension RootService {
func appDelegate() -> AppDelegate {
return UIApplication.sharedApplication().delegate as! AppDelegate
}
}

AppDelegate.swift

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?
let serviceDispatcher = ServiceDispatcher(services: [RootService()])


func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

serviceDispatcher.application(application, didFinishLaunchingWithOptions: launchOptions)

return true
}

func applicationWillResignActive(application: UIApplication) {
serviceDispatcher.applicationWillResignActive(application)
}

func applicationDidEnterBackground(application: UIApplication) {
serviceDispatcher.applicationDidEnterBackground(application)
}

func applicationWillEnterForeground(application: UIApplication) {
serviceDispatcher.applicationWillEnterForeground(application)
}

func applicationDidBecomeActive(application: UIApplication) {
serviceDispatcher.applicationDidBecomeActive(application)
}
}

I have more services like DebugService, PushNotificationService, CrashTrackingService, …

The downside to this approach is that in real life, there will be dependencies between those services, like that UserService must be called before RootService? In this case, I have to use comment to explain why I have that decision, which is hard for newcomers to understand at first. Take a look at How to Move Bootstrapping Code Out of AppDelegate for how dependencies are managed

JSDecoupledAppDelegate comes with another approach, in which service events are named according to the functions, like appStateDelegate, appDefaultOrientationDelegate, watchInteractionDelegate, …

But for me, Service and ServiceDispatcher suit my need

Reference

How to debug Auto Layout

Issue #23

hasAmbiguousLayout

Returns whether the constraints impacting the layout of the view incompletely specify the location of the view.

exerciseAmbiguityInLayout

This method randomly changes the frame of a view with an ambiguous layout between its different valid values, causing the view to move in the interface. This makes it easy to visually identify what the valid frames are and may enable the developer to discern what constraints need to be added to the layout to fully specify a location for the view.

_autolayoutTrace

This returns a string describing the whole view tree which tells you when a view has an ambiguous layout.

NSLayoutConstraint identifier

The name that identifies the constraint.

UIViewAlertForUnsatisfiableConstraints

DETECTED_MISSING_CONSTRAINTS

https://forums.developer.apple.com/thread/63811

View Debugger search by address

Read more

How to create a piano using iOS 9 Auto Layout

Issue #22

In the beginning, people use frame and Autoresizing Mask, then they use Auto Layout, then iOS 9 encourages them to use NSLayoutAnchor, UILayoutGuide and UIStackView

For more convenient Auto Layout, check How to make Auto Layout more convenient in iOS and Anchors

NSLayoutAnchor

The NSLayoutAnchor class is a factory class for creating NSLayoutConstraint objects using a fluent API. Use these constraints to programmatically define your layout using Auto Layout.

It has 3 subclasses

NSLayoutDimension

  • func constraintEqualToConstant(_ c: CGFloat) -> NSLayoutConstraint!

NSLayoutXAxisAnchor

  • Allows working with horizontal constraints
  • Prevent these
1
2
// This constraint generates an incompatible pointer type warning
cancelButton.leadingAnchor.constraintEqualToAnchor(saveButton.topAnchor, constant: 8.0).active = true

NSLayoutYAxisAnchor

  • Allows working with vertical constraints
  • Prevent these
1
2
// This constraint generates an incompatible pointer type warning
cancelButton.topAnchor.constraintEqualToAnchor(saveButton.trailingAnchor, constant: 8.0).active = true

UILayoutGuide

Previously, we used dummy views to aid constraints. Now we use UILayoutGuide

Define an equal spacing between a series of views

uilayoutguide_spacing

See full gist

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let space1 = UILayoutGuide()
view.addLayoutGuide(space1)

let space2 = UILayoutGuide()
view.addLayoutGuide(space2)

space1.widthAnchor.constraintEqualToAnchor(space2.widthAnchor).active = true

saveButton.trailingAnchor.constraintEqualToAnchor(space1.leadingAnchor).active = true

cancelButton.leadingAnchor.constraintEqualToAnchor(space1.trailingAnchor).active = true
cancelButton.trailingAnchor.constraintEqualToAnchor(space2.leadingAnchor).active = true

clearButton.leadingAnchor.constraintEqualToAnchor(space2.trailingAnchor).active = true

Layout guides can also act as a black box, containing a number of other views and controls

uilayoutguide_container

See the full gist

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
let container = UILayoutGuide()
view.addLayoutGuide(container)

// Set interior constraints
label.lastBaselineAnchor.constraintEqualToAnchor(textField.lastBaselineAnchor).active = true
label.leadingAnchor.constraintEqualToAnchor(container.leadingAnchor).active = true

textField.leadingAnchor.constraintEqualToAnchor(label.trailingAnchor, constant: 8.0).active = true
textField.trailingAnchor.constraintEqualToAnchor(container.trailingAnchor).active = true

textField.topAnchor.constraintEqualToAnchor(container.topAnchor).active = true
textField.bottomAnchor.constraintEqualToAnchor(container.bottomAnchor).active = true

// Set exterior constraints
// The contents of the container can be treated as a black box
let margins = view.layoutMarginsGuide

container.leadingAnchor.constraintEqualToAnchor(margins.leadingAnchor).active = true
container.trailingAnchor.constraintEqualToAnchor(margins.trailingAnchor).active = true

// Must use NSLayoutConstraint with the scene's top and bottom layout guides.
NSLayoutConstraint(item: container,
attribute: .Top,
relatedBy: .Equal,
toItem: topLayoutGuide,
attribute: .Bottom,
multiplier: 1.0,
constant: 20.0).active = true

layoutMarginsGuide

Margins are now represented as layoutMarginsGuide, a subclass of UILayoutGuide

topLayoutGuide and bottomLayoutGuide

In the container example, we saw how we must use NSLayoutConstraint with the topLayoutGuide. topLayoutGuide and bottomLayoutGuide are object conforming to UILayoutSupport protocol

layoutFrame

The layout guide defines a rectangular space in its owning view’s coordinate system. This property contains a valid CGRect value by the time its owning view’s layoutSubviews method is called.

In the above container example, the container layout guide frame is

1
(16.0, 40.0, 343.0, 21.0)

Piano

piano

See Piano on Github on how to create a Piano using UILayoutGuide, NSLayoutAnchor and UIStackView

How to handle RefreshControl in iOS

Issue #20

The other day I was doing refresh control, and I saw this Swift Protocols with Default Implementations as UI Mixins

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
extension Refreshable where Self: UIViewController
{
/// Install the refresh control on the table view
func installRefreshControl()
{
let refreshControl = UIRefreshControl()
refreshControl.tintColor = .primaryColor
refreshControl.addTarget(self, action: #selector(handleRefresh(_:)), for: .valueChanged)
self.refreshControl = refreshControl

if #available(iOS 10.0, *)
{
tableView.refreshControl = refreshControl
}
else
{
tableView.backgroundView = refreshControl
}
}
}

Protocol extension is cool but somehow I’m not a fan of it. I always consider composition first, to extract the specific task to one entity that does that well. It looks like this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class RefreshHandler: NSObject {
let refresh = PublishSubject<Void>()
let refreshControl = UIRefreshControl()

init(view: UIScrollView) {
super.init()
view.addSubview(refreshControl)
refreshControl.addTarget(self, action: #selector(refreshControlDidRefresh(_: )), for: .valueChanged)
}

// MARK: - Action

func refreshControlDidRefresh(_ control: UIRefreshControl) {
refresh.onNext(())
}

func end() {
refreshControl.endRefreshing()
}
}

It is a bit Rx, we can use block if we like, but the idea is we can declare this RefreshHandler and use it everywhere we want

1
2
3
4
5
6
refreshHandler = RefreshHandler(view: scrollView)

refreshHandler.refresh
.startWith(())
.bindTo(viewModel.input.fetch)
.addDisposableTo(bag)

How to hack iOS apps

Issue #19

We need to care about security nowadays, here are some links I find useful to read more about this matter

Private frameworks

Hack macOS apps

Private frameworks

Hack Android apps

How to deal with singleton in iOS

Issue #18

A single singleton

There are many classes that designed to be used as singleton, like UserDefaults.standard, FileManager.default, NotificationCenter.default or even our own classes like UserManager, Storage, … Singleton is a design patter and has its own use case, sometimes we still need to use it. But if we are to use singleton, we should just use 1, and group all other singleton under this single singleton. Thanks to Vadym for showing this to me

Swift makes it extremely easy to make singleton, let name it App then we have a single point of control for all the singletons

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
struct App {
static let model = AppModel()
static let realmProvider = RealmProvider()
static let networkingProvider = NetworkingProvider()
static var navigator = Navigator()
static let config = AppConfig()
static let pushNotificationCenter = PushNotificationCenter()
static let lifeCycle = LifeCycle()
}
```

These are use cases where a single instance is needed

### AppModel
This is where we store model for an app, that can be
- is onboarding shown
- organization name
- `Session` that encapsulates token, current profile

### LifeCycle
This is where we listen to app life cycle, I use `rx` to make it easy, see https://github.com/onmyway133/blog/issues/12

### RealmProvider
I prefer `Realm` for storing and caching, usually 1 `Realm` is enough. This is where we return the a certain `Realm` instance

```swift
class RealmProvider {
static func realm() -> Realm {
let configuration = Realm.Configuration(schemaVersion: App.config.schemaVersion)
return try! Realm(configuration: configuration)
}
}

AppConfig

This is where we have configurations for staging and production environment, those can be client key, Firebase configuration, analytics keys, …

I use Compass to do central navigation, and there should be 1 Navigator that does the job

Inject a singleton

Sometime we rely on a singleton to do our job, to make dependencies clear and testing easier, we need to inject this singleton, and leverage Swift default parameter, thanks to John for showing this to me

Here is an example of a ViewModel that relies on networking

1
2
3
4
5
6
7
8
9
10
11
12
13
class ProfileViewModel {

let networking: Networking<APIEndpoint>

init(networking: Networking<APIEndpoint> = App.networking) {
self.networking = networking

networking.rxRequest(APIEndpoint.profile)
.bindNext({ profile in
print(profile)
})
}
}

Swift snippets

Issue #17

I always forget how to write correct #available( or #if swift(>=3.0) or just lazy to write required init?(coder aDecoder: NSCoder) every time I make a subclass. That’s why I made SwiftSnippets to save time for these tedious tasks. Installation is easy with script, so you should give it a try.

I can’t recommend this enough, it saves me tons of time

What you don't know is what you haven't learned

Issue #14

Some of my sayings that I like 😉

Mine

  • There are so many many many things to learn
  • The opportunities are endless
  • Everybody has access to the internet. Everybody has nearly the same chances. Your future is yours to decide
  • A dream is not a dream anymore when you don’t have time for it
  • Being single means free time. Being coupled means memorable time
  • You learn less with the happy path
  • I don’t like to be at the centre, nor being abandoned
  • Even sense of humour can be trained
  • Youth is your strength. Take advantage of it
  • Easy to please. Hard to impress
  • Don’t show me the evil sides of the world
  • Please don’t confuse peace vs boredom
  • What matters is your passion, not your ability
  • The ones that are likely to fail are the ones having the fewest friends. And the ones that have the fewest friends are the ones having the most boring life
  • Life is like a marathon. People run. Some are lucky enough to have support. Some are even luckier, they already crossed the finish line when they were born. Running, however, has its own fun
  • Life is predestined. But you can of course change it
  • Losers are easily the most hot tempered. It is the consequence, not the cause
  • What if there is no inheritance. Will that make everybody the same?
  • Some people become Norwegian when they were born. Others have to apply for the citizenship https://www.udi.no/en/word-definitions/norwegian-by-birth/
  • Every deck has a chance to win, as long as you believe in the heart of the cards
  • Life is a game. People play on different difficulty levels. “But mine is much harder”, said everybody
  • What you don’t know is what you haven’t learned

Others

  • I don’t know the key to success. But the key to failure is trying to please everybody ~ Bill Cosby

Composition in Realm

Issue #13

There is time we have models that have some kind of inheritance, like Dog, Cat, Mouse can be Animal. We can use composition to imitate inheritance, we just need to make sure it has unique primary key

Cat and Dog

These are pretty much basic Realm objects

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Dog: Object {
dynamic var id: Int = 0

required convenience init(json: [String: Any]) {
self.init()
id <- json.integer(key: "id")
}
}

class Cat: Object {
dynamic var id: Int = 0

required convenience init(json: [String: Any]) {
self.init()
id <- json.integer(key: "id")
}
}

Animal

Here Animal can contain either dog or cat, we can add more if there are many other “inheritance” of Animal. The required init makes sure Animal can only be init with 1 type of child class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Animal: Object {
dynamic var id: Int = 0

dynamic var cat: Cat?
dynamic var dog: Dog?

required convenience init(cat: Cat) {
self.init()
self.cat = cat
self.id = cat.id
}

required convenience init(dog: Dog) {
self.init()
self.dog = dog
self.id = dog.id
}
}

How to do delegate with RxSwift

Issue #12

We can use DelegateProxy and DelegateProxyType to make beautiful delegate with RxSwift. But in some other cases, we can just create a custom class with PublishSubject.

This is how we can make rx out of UIApplication life cycle events

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class LifeCycle {
let didEnterBackground = PublishSubject<Void>()
let willEnterForeground = PublishSubject<Void>()
let didBecomeActive = PublishSubject<Void>()
let willResignActive = PublishSubject<Void>()

init() {
let center = NotificationCenter.default
let app = UIApplication.shared

center.addObserver(forName: Notification.Name.UIApplicationDidEnterBackground,
object: app, queue: .main, using: { [weak self] _ in
self?.didEnterBackground.onNext(())
})

center.addObserver(forName: Notification.Name.UIApplicationWillEnterForeground,
object: app, queue: .main, using: { [weak self] _ in
self?.willEnterForeground.onNext(())
})

center.addObserver(forName: Notification.Name.UIApplicationDidBecomeActive,
object: app, queue: .main, using: { [weak self] _ in
self?.didBecomeActive.onNext(())
})

center.addObserver(forName: Notification.Name.UIApplicationWillResignActive,
object: app, queue: .main, using: { [weak self] _ in
self?.willResignActive.onNext(())
})
}
}

Usage

1
2
3
4
5
6
let lifeCycle = LifeCycle()
lifeCycle.didBecomeActive
.bindNext({ [weak self] in
self?.viewModel.reloadProfile()
})
.disposed(by: bag)

How to group extension methods in Swift

Issue #11

Swift allows us to define more methods on existing class using extension.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
extension UIView {

func shake() {

}

func fade() {

}

func centerIn(anotherView: UIView) {

}
}

If you ‘re afraid of the naming conflict, you can prefix your methods, like

1
2
3
view.abc_shake()
view.abc_fade()
view.abc_centerIn(anotherView: containerView)

Or a better way, reverse it 💃 , like

1
2
3
view.animation.shake()
view.animation.fade()
view.layout.centerIn(anotherView)

This way, no more conflict and we make it clear that shake() and fade() belongs to animation category
Actually, animation and layout are properties in UIView extension. This may cause naming conflict, but the number of them is reduced

This is how it works

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
extension UIView {

struct Animation {
let view: UIView

func shake() {
// Shake the view
}

func fade() {
PowerfulAnimationEngine.fade(view)
}
}

var animation: Animation {
return Animation(view: self)
}

struct Layout {
let view: UIView

func centerIn(anotherView: UIView) {

}
}

var layout: Layout {
return Layout(view: self)
}
}

How to execute an action only once in Swift

Issue #10

There is time we want to execute an action only once. We can surely introduce a flag, but it will be nicer if we abstract that out using composition. Then we have

1
2
3
4
5
6
7
8
9
10
11
12
13
class Once {

var already: Bool = false

func run(@noescape block: () -> Void) {
guard !already else {
return
}

block()
already = true
}
}

Usage

1
2
3
4
5
6
7
8
9
10
11
class ViewController: UIViewController {
let once = Once()

override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)

once.run {
cameraMan.setup()
}
}
}

In the same way, we can check to run a closure when a value changes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
final class WhenChange<T: Equatable> {
private(set) var value: T

init(value: T) {
self.value = value
}

func run(newValue: T, closure: (T) -> Void) {
if newValue != value {
value = newValue
closure(value)
}
}
}

Law of Jante

Issue #9

The other day I was watching Inside Sweden’s Silicon Valley, and he mentions Law of Jante

It is pretty much this

  • You’re not to think you are anything special.
  • You’re not to think you are as good as we are.
  • You’re not to think you are smarter than we are.
  • You’re not to convince yourself that you are better than we are.
  • You’re not to think you know more than we do.
  • You’re not to think you are more important than we are.
  • You’re not to think you are good at anything.
  • You’re not to laugh at us.
  • You’re not to think anyone cares about you.
  • You’re not to think you can teach us anything.

This is controversial, there are many discussions about this

Putting on your black hat, it sounds negative. Putting on your yellow hat, it sounds positive
But what I learn about it is the team work. No one lives alone, everyone lives among the others. It is about to be humble and learn collaboration

Advices to students

Issue #8

Some say these are from the book Dumbing Down America of Charles Sykes, some say they are from Bill Gates ‘s speech to high school students. I don’t know the origin, but they are cool enough, so I tend to share it again and again

  • Life is not fair. Get used to it ⭐️
  • The world won’t care about your self-esteem. The world will expect you to accomplish something BEFORE you feel good about yourself
  • You will NOT make 40 thousand dollars a year right out of high school. You won’t be a vice president with car phone, until you earn both.
  • If you think your teacher is tough, wait till you get a boss. He doesn’t have tenure.
  • If you mess up, it’s not your parents’ fault, so don’t whine about your mistakes, learn from them.
  • Your school may have done away with winners and losers, but life may not. In some schools they have abolished failing grades and they’ll give you as many times as you want to get the right answer. This doesn’t bear the slightest resemblance to ANYTHING in real life.
  • Life is not divided into semesters. You don’t get summers off and very few employers are interested in helping you find yourself. Do that on your own time.
  • Television is NOT real life. In real life people actually have to leave the coffee shop and go to jobs.
  • Be nice to nerds. Chances are you’ll end up working for one.
  • Before you were born your parents weren’t as boring as they are now. They got that way paying your bills, cleaning up your room and listening to you tell them how idealistic you are. And by the way, before you save the rain forest from the blood-sucking parasites of your parents’ generation, try delousing the closet in your bedroom ⭐️

Reference

Check before you commit

Issue #7

Original post https://medium.com/@onmyway133/check-before-you-commit-5a7601cffc87


We usually have some experiment code that we don’t want they to step into our commit. I usually mark my experiment with // but sometimes forget to unstage that
Starting with 2.9, Git has improvement on its commit hook which makes it globally using hooksPath

Create pre-commit file

Create a file called pre-commit, and place it into, for example /Users/khoa/hooks

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/bin/sh

# https://appventure.me/2016/04/04/prevent-accidental-test-code-commits/

if git rev-parse --verify HEAD >/dev/null 2>&1
then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

# The special marker tag to mark things which we still need to change
marker="<TEST>"

# Redirect output to stderr.
exec 1>&2

if test $(git diff --cached -z $against | grep $marker | wc -c) != 0
then
cat <<\EOF
Error: Still has invalid debug markers in code:
EOF
echo `git diff --cached -z $against -G $marker`
exit 1
fi

Apply the hook

In your project, run git config core.hooksPath /Users/khoa/hooks
That’s it. Whenever you commit a file with that pattern, it won’t let you commit

How to use

Try

1
2
// <TEST>
UserManager.shared.isActive = true

and git commit -m "my commit message" will assert with Error: Still has invalid debug markers in code:

Reference

Markdown editor

Issue #6

I like writing with markdown, it gives me comfortable experience with complete control over what I want to write.

I recommend vmd which renders exactly as GitHub. vmd is for rendering only, you need an editor to write, I use Sublime Text because it opens very fast

I also recommend using spectacle to easily split and organize windows

vmd

Primary key in Realm

Issue #4

Realm is great. But without primary key, it will duplicate the record, like https://github.com/realm/realm-java/issues/2730, http://stackoverflow.com/questions/32322460/should-i-define-the-primary-key-for-each-entity-in-realm, … So to force ourselves into the good habit of declaring primary key, we can leverage Swift protocol

Create primary constrain protocol like this

1
2
3
4
protocol PrimaryKeyAware {
var id: Int { get }
static func primaryKey() -> String?
}

and conform it in out Realm object

1
2
3
4
5
6
7
8
9
10
class Profile: Object, PrimaryKeyAware {

dynamic var firstName: String = ""
dynamic var lastName: String = ""
dynamic var id: Int = 0

override static func primaryKey() -> String? {
return "id"
}
}

This way, when using that object in out RealmStorage, we are safe to say that it has a primary key

1
2
3
4
5
6
7
8
9
10
11
12
13
class RealmStorage<T: Object> where T: PrimaryKeyAware {
let realm: Realm

init(realm: Realm = RealmProvider.realm()) {
self.realm = realm
}

func save(_ objects: [T]) {
try? realm.write {
realm.add(objects, update: true)
}
}
}

The usage is like this

1
2
3
let profile = Profile()
let storage = RealmStorage<Profile>()
storage.save([profile])