Upload
natasha-murashev
View
1.722
Download
0
Embed Size (px)
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
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