Build Features Not Apps

Preview:

Citation preview

BUILD FEATURES, NOT APPS

@NATASHATHEROBOT

SWIFT ROBOT▸ NatashaTheRobot.com▸ @NatashaTheNomad▸ This Week in Swift▸ Swift Jobs▸ try! Swift

Most smartphone users download 0 apps per month

An average app loses up to 95% of users within the first month

!!!

!"

FEATURE:

NOTIFICATIONS

FEATURE:

SPEECH RECOGNITION

"As speech recognition accuracy goes from say 95% to 99%, all of us in the room will from barely using it today to using it all the time. Most

people underestimate the difference between 95% and 99% accuracy - 99% is a game changer" - Andrew NG, Chief Scientist at Baidu

SIRI INTENTS▸ Audio or video calling▸ Messaging▸ Payments

▸ Searching photos▸ Workouts▸ Ride booking

FEATURE:

EXTENSIONS

"It took Line Messenger almost four months to find its first two million

users ...

… but after stickers were launched, it took only two days to find the next

million...

The company now makes over $270M a year just from selling stickers."

THE FUTURE?

! -> "

ARCHITECTING FOR FEATURES

▸ Frameworks all the things!▸ Vectorize Images▸ NSUserActivity FTW

!

OPEN VS PUBLIC

let rootURL = FileManager.default().containerURLForSecurityApplicationGroupIdentifier("group.com.NatashaTheRobot.MyFavoriteGelato")

let defaults = UserDefaults(suiteName: "group.com.NatashaTheRobot.MyFavoriteGelato")

! + ⌚ + #

MULTIPLATFORM, SINGLE-SCHEME XCODE PROJECTS

by Max Howell on PromiseKit.org

FRAMEWORKS▸ DRY

▸ App Groups▸ iCloud Key-Value Storage▸ Cross-Platform

VECTORIZE IMAGES

.PDF

iceCreamImageView.tintColor = .purple

VECTORIZE IMAGES▸ Single Scale PDFs

▸ Template Image for Icons

NSUSERACTIVITY FTW

// AppDelegatefunc application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool{

if userActivity.activityType == NSUserActivityTypeBrowsingWeb, let webpageURL = userActivity.webpageURL {

// separate webpageURL using NSURLComponents // present the correct View Controller if valid // otherwise, open link in Safari } return false}

CREATING AN ACTIVITY// GelatoDetailViewController

override func viewDidLoad() { super.viewDidLoad() // other config here

let activity = NSUserActivity(activityType: "com.natashatherobot.GelatoFinder.gelato")

// will show up as this in Spotlight Search Results activity.title = gelato.name

// Other keywords to search by activity.keywords = Set([gelato.name, "gelato"])

// should be handed off to another device? activity.isEligibleForHandoff = true // should be indexed in App History? activity.isEligibleForSearch = true // should be eligible for indexing for any user of this application? activity.isEligibleForPublicIndexing = true

// Avoid deallocating before indexing, // global variable declared in UIResponder class userActivity = activity

// don't forget to activate! userActivity!.becomeCurrent()

}

SAVE UNIQUE INFO// GelatoDetailViewController

override func viewDidLoad() { // create activity and other config here activity.delegate = self activity.needsSave = true // assign to userActivity, etc}

extension GelatoDetailViewController: NSUserActivityDelegate { func userActivityWillSave(_ userActivity: NSUserActivity) { // info needed to recreate activity! userActivity.userInfo = ["index": gelatoIndex] }}

RESTORE ACTIVITY// AppDelegate

func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool{ let mainController = (window!.rootViewController! as! UINavigationController).viewControllers.first mainController?.restoreUserActivityState(userActivity) return true}

RESTORE ACTIVITY// GelatoListTableViewController

override func restoreUserActivityState(_ activity: NSUserActivity) { if let index = activity.userInfo?["index"] as? Int { searchedGelatoIdentifier = index performSegue(withIdentifier: "showGelato", sender: self) }}

RESTORE ACTIVITY// GelatoListTableViewController

override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if let gelatoDetailVC = segue.destination as? GelatoDetailViewController { let index = tableView.indexPathForSelectedRow?.row ?? searchedGelatoIdentifier ?? 0 gelatoDetailVC.gelato = gelatoFlavors[index] gelatoDetailVC.gelatoIndex = index }}

NSUSERACTIVITY▸ Handoff

▸ Universal Links▸ Search▸ Location

▸ Contextual Reminders▸ Contact Interactions

▸ Frameworks all the things!▸ Vectorize Images▸ NSUserActivity FTW

BUILD FEATURES, NOT APPS

@NATASHATHEROBOT