Fantageek

Simple apps that make sense.

SDK and Deployment Target

| Comments

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

NSApplicationDelegate and Notification

| Comments

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:

Digit Grouping in Swift

| Comments

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
    }
}

iOS Best Practices

| Comments

Here are practices I found useful when developing iOS. They can be tools or framework that greatly affect your style. Sometimes, it applies to other platform as well

Architecture

We’re always looking for ways to structure our apps better, I collect some cool stuffs in ios-architecture

Name it right

Naming is hard. But we can start by naming correctly and with correct spelling. The best way is to stick with the platform naming convention

Project structure

Some prefer to group their projects by object role, like Model, View, View Controller. But I prefer to group by feature or use case, learning from Clean Architecture

  • Clean Architecture When you look at a software system, and all you see is MCV in a web configuration, then the architecture of that system is hiding the use cases of that system and exposing the delivery mechanism.

I often group my code like this

  • Share: Contains code that can be useful to other project. Not related to any project. Can be extract to a Pod
  • Engine: Contains code that is specific to this project. Like UserManager, ViewAnimator, …
  • Modules: Separate each screen into module. In each module, there are view, view model and wireframe

There are some architectures like MVC, MVVM, VIPER, VIP, … and you may want to leverage some templates to help creating projects faster, like

And learn how to make them

There are also some scripts to bootstrap your project

  • crafter Crafter - Xcode project configuration CLI made easy
  • xcake Create your Xcode projects automatically using a stupid simple DSL.
  • liftoff CLI for creating and configuring new Xcode projects

Functional Reactive Programming

The Reactive Extension inspired libraries are cool, and they greatly changes the way you develop, especially signal chaining

Unidirectional data flow

Another trend is React inspired libraries, which encourage Unidirectional data flow

Data manipulation

Leverage some functional style for better data manipulation

  • Swiftz It defines functional data structures, functions, idioms, and extensions that augment the Swift standard library.
  • Dollar.swift A functional tool-belt for Swift Language similar to Lo-Dash or Underscore.js in Javascript

Prefer decoration over extension

This maybe subjective. But in some case decoration wins

Often when we want to add custom color, font or animate a view, or custom NSDateFormatter, we often make categories on UIColor, UIFont, UIView, NSDateFormatter, …

But most of the case, we can group them inside class, like ColorBucket, FontBucket, ViewAnimator, DateFormatterBucket, …

So, instead of

1
2
3
4
5
@interface UIColor (Additions)

- (UIColor *)customColor;

@end

We can have ColorBucket

1
2
3
4
5
@interface ColorBucket

+ (UIColor *)customColor;

@end

Mixin

Another way to add functionality to an entity is mixin, which is cool

IoC container

Usage of IoC container can greatly change the app workflow, which praises Dependency Injection

Single Responsibility Principle

Always keep this in mind :]

Performance

Understanding of performance issue, especially some common uses like tableview pre rendering, helps

Main thread

It’s good to care about our main thread so see if it is blocked

Overlay app icon with build information

Show TODO FIXME as warnings

Use this script in Run Script Build Phase

1
2
KEYWORDS="TODO:|VERIFY:|FIXME:|\?\?\?:|\!\!\!:"
find "${SRCROOT}" -name "*.h" -or -name "*.m" -print0 | xargs -0 egrep --with-filename --line-number --only-matching "($KEYWORDS).*\$" | perl -p -e "s/($KEYWORDS)/ warning: \$1/"

Breakpoints

There are some common needed breakpoints, like Breakpoints_v2.xcbkptlist

Code snippets

Code snippets auto generate common code

Utility class

We can avoid duplicated helper classes in projects by using some cool frameworks

  • Sugar Sugar is a sweetener for your Cocoa implementations.

Xcode plugins

Using Xcode plugins can boost your productivity

And learning to write your own can assist you with more tasks

Xcode keyboard shortcuts

Navigate faster

xcconfig

Build yourself some predefined xcconfig

Strongly typed resource

There’s some scripts that generate strongly typed resource classes

  • SwiftGen A collection of Swift tools to generate Swift code (enums for your assets, storyboards, Localizable.strings, …)
  • R.swift Get strong typed, autocompleted resources like images, fonts and segues in Swift projects

Continuous learning

Technologies move really fast. We must learn continuously. I have ios-resources to keep track of all the cool stuffs

Also, I leverage Github as my notes ios-issues

Reference

Symbolic Breakpoints in Xcode

| Comments

Symbolic breakpoints are breakpoints based on symbols like functions or methods.

In Swift

You can set symbolic breakpoints on any free functions, instance and class methods, whether in your own classes or not.

Here is an example

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
func freeFunction() {
    print("freeFunction")
}

class Robot {
    init() {
        print("init")
    }

    func instanceMethod() {
        print("instanceMethod")
    }

    func instanceMethod(noise: Int) {
        print("instanceMethod")
    }

    func instanceMethodWithArguments(a: Int, b: Int) -> Int {
        print("instanceMethodWithArguments")
        return a + b
    }

    func instanceMethodWithArguments(a: Int, b: Int, c: Int) -> Int {
        print("instanceMethodWithArguments")
        return a + b + c
    }

    class func classMethod() {
        print("classMethod")
    }

    struct MyStruct {
        static func staticMethod() {
            print("staticMethod")
        }
    }
}

struct MyStruct {
    static func staticMethod() {
        print("staticMethod")
    }
}

You can have some breakpoints in Swift like

1
2
3
4
5
6
7
UIViewController.viewDidLoad
freeFunction
Robot.instanceMethod
instanceMethodWithArguments
Robot.classMethod
Robot.init
Robot.MyStruct.staticMethod
  • There seems no difference between instance and class methods !!
  • Robot.MyStruct.staticMethod says that it must match staticMethod inside Robot.MyStruct
  • With instanceMethodWithArguments, Xcode Breakpoint panel shows options for (Robot)(Swift.Int)(b: Swift.Int) -> Swift.Int and (Robot)(Swift.Int)(b: Swift.Int)(c: Swift.Int) -> Swift.Int. This may remind you of Instance Methods are Curried Functions in Swift
  • I thought that symbolic breakpoint must match Selector, like instanceMethodWithArguments:b:c, but it is not
  • Objective-C style -[UIViewController viewDidLoad] or -[Robot instanceMethod] does not work !!

And talking about Swift selector, you may want to take a look at this proposal Referencing the Objective-C selector of a method

In Objective-C

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
void freeFunction() {
    NSLog(@"freeFunction");
}


@interface Robot : NSObject

@property (nonatomic, copy) NSString *name;

- (void)instanceMethod;
- (void)instanceMethod:(NSInteger)a b:(NSInteger)b;
+ (void)classMethod;

@end

@implementation Robot

- (instancetype)initWithName:(NSString *)name {
    self = [super init];
    self.name = name;

    return self;
}

- (void)instanceMethod {
    NSLog(@"instanceMethod");
}

- (void)instanceMethod:(NSInteger)a b:(NSInteger)b {
    NSLog(@"instanceMethod:b:");
}

+ (void)classMethod {
    NSLog(@"classMethod");
}

@end

You can have some breakpoints in Objective-C like

1
2
3
4
5
6
-[UIViewController viewDidLoad]
freeFunction
-[Robot initWithName:]
-[Robot instanceMethod]
-[Robot instanceMethod:b:]
+[Robot classMethod]
  • We must specify the correct method with arguments like -[Robot instanceMethod:b:]
  • I use another Swift class into this Objective-C project
1
2
3
4
5
@objc public class Animal: NSObject {
    @objc func hello() {
        print("hello")
    }
}

but the symbolic breakpoint -[Animal hello] does not work. Only Animal.hello works !!

Syntax

  • There are Swift syntax Animal.hello and Objective-C syntax -[Animal hello]. It seems that Swift syntax must be used on Swift files. So in Swift project, we should use Swift syntax
  • init is instance method, see How to swizzle init in Swift

System symbols

Symbolic breakpoints are helpful in case you want to inspect system behaviours

Auto Layout

Breakpoints_v2.xcbkptlist

swift_willThrow

objc_exception_throw

It is your Exception Breakpoint with Break set to Throw

There’s a Break type Catch also

Swizzle

Symbolic breakpoints help when you want to understand system call, like when you try to make Xcode plugin

See How To Create an Xcode Plugin: Part 1/3 on how to break in initWithIcon:message:parentWindow:duration

Assembly

Break on system classes and you want to understand the parameters there, so an understanding of assembly helps

Interesting

Some interesting questions

chisel

Facebook has chisel, which is a collection of lldb commands in Python

Specifically, bmessage

Set a symbolic breakpoint on the method of a class or the method of an instance without worrying which class in the hierarchy actually implements the method.

Reference

Some Mac OSX Tools

| Comments

Mac OS X has some useful tools that you may overlook. They are useful in your daily development

Network Link Conditioner

Simulate network condition. Accessible from System Preferences -> Network Link Conditioner

ColorSync Utility

Pick and convert color. Accessible from Applications/Utilities/ColorSync Utility.app

Automator

Write script to automate task. Accessible from Applications/Automator.app

App Backed by Website in iOS 9

| Comments

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">

Universal Links

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

| Comments

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