Upgrade to Pro — share decks privately, control downloads, hide ads and more …

iOS Development in 2016/2017: upcoming trends r...

iOS Development in 2016/2017: upcoming trends review from Andrian Budantsov

Thanks to Apple's efforts and contributions of open source society, iOS is one of the fastest growing mobile platforms nowadays. In talk “iOS development in 2016/2017: upcoming trends review” key trends of iOS development and usage of new technologies will be reviewed.

uaMobiTech

July 28, 2016
Tweet

More Decks by uaMobiTech

Other Decks in Programming

Transcript

  1. • makes iOS apps since the launch of the App

    Store; Mac apps since 2015 • 6 large code bases • RD2, ScannerPro, RDPDFKit, SmartMail, Calendars, PrinterPro • ~ million lines of Obj-C code • ~ 50K lines of Swift code
  2. • Faster & More Better • With New Tech •

    Cross-Platform (Faster & More) • Secure
  3. [C]

  4. Obj-C: fbinfer [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(observer:) name:UIApplicationDidBecomeActiveNotification object:nil]; NSNumber *n

    = [self randomBinaryNumber]; if (n) { CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, "uamobi.tech", kCFStringEncodingASCII); FILE *f = fopen(“~/Desktop/Hello.txt“, "w"); if (!f) { str = (CFStringRef)f; // have no idea } const char *strPtr = CFStringGetCStringPtr(str, kCFStringEncodingASCII); fwrite(str, 1, strlen(strPtr), f); CFRelease(str); }
  5. Starting analysis (Infer version v0.8.1) FFF.............. Analyzed 3 files Found

    4 issues StaticAnalyzerCheck/ViewController.m:15: warning: REGISTERED_OBSERVER_BEING_DEALLOCATED Object self is registered in a notification center but not being removed before deallocation at line 15, column 1. Consider removing the object from the notification center before its deallocation. 13. @end 14. 15. > @implementation ViewController 16. 17. - (NSString * _Nonnull)string { 18. StaticAnalyzerCheck/ViewController.m:34: error: BAD_POINTER_COMPARISON Implicitly checking whether NSNumber pointer n is nil at line 34, column 9. Did you mean to compare against the unboxed value instead? Please either explicitly compare n to nil or use one of the NSNumber accessors before the comparison. 32. 33. FILE *f = NULL; 34. > if (n) { 35. 36. CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, "uamobi.tech", kCFStringEncodingASCII); StaticAnalyzerCheck/ViewController.m:45: error: RESOURCE_LEAK resource acquired to f by call to fopen() at line 39, column 13 is not released after line 45, column 9 43. 44. const char *strPtr = CFStringGetCStringPtr(str, kCFStringEncodingASCII); 45. > fwrite(str, 1, strlen(strPtr), f); 46. CFRelease(str); 47. } StaticAnalyzerCheck/ViewController.m:46: error: NULL_DEREFERENCE pointer str last assigned on line 41 could be null and is dereferenced at line 46, column 9 44. const char *strPtr = CFStringGetCStringPtr(str, kCFStringEncodingASCII); 45. fwrite(str, 1, strlen(strPtr), f); 46. > CFRelease(str); 47. } Summary of the reports REGISTERED_OBSERVER_BEING_DEALLOCATED: 1 NULL_DEREFERENCE: 1 BAD_POINTER_COMPARISON: 1 RESOURCE_LEAK: 1
  6. Obj-C __auto_type randomDouble = drand48(); __auto_type string = [NSString stringWithFormat:@"%@",

    [NSDate date]]; __auto_type rect = self.view.bounds; double randomDouble = drand48(); NSString *string = [NSString stringWithFormat:@"%@", [NSDate date]]; CGRect rect = self.view.bounds;
  7. Obj-C static UIColor *_carDefaultColor = nil; @interface Car : NSObject

    @property (class) UIColor *defaultColor; @end @implementation Car + (UIColor *)defaultColor { return _carDefaultColor; } + (void)setDefaultColor:(UIColor *)defaultColor { _carDefaultColor = defaultColor; } @end - class property - is not synthesized
  8. Swift is more Swifter • Swifter API Guidelines • Swifter

    C functions • Swift Package Manager
  9. Swifter API Guidelies let blue = UIColor.blueColor() let min =

    numbers.minElement() attributedString.appendAttributedString(anotherString) names.insertObject("test", atIndex: 0) UIDevice.currentDevice() let blue = UIColor.blue() let min = numbers.min() attributedString.append(anotherString) names.insert("test", at: 0) UIDevice.current()
  10. Swifter C Functions let queue = dispatch_queue_create(“tech.uamobi.gcdexample”, nil) dispatch_async(queue) {

    print("Hello World") } let queue = DispatchQueue(label: "tech.uamobi.gcdexample") queue.async { print("Hello World") }
  11. Swift Package Manager import PackageDescription let package = Package( name:

    "DeckOfPlayingCards", targets: [], dependencies: [ .Package(url: "https://github.com/apple/example-package-fisheryates.git", majorVersion: 1), .Package(url: "https://github.com/apple/example-package-playingcard.git", majorVersion: 1), ] ) Started by Homebrew author; a bit like NPM
  12. Realm 1.0 class Dog: Object { dynamic var name =

    "" dynamic var age = 0 } class Person: Object { dynamic var name = "" let dogs = List<Dog>() }
  13. // Create a standalone object let mydog = Dog() //

    Set & read properties mydog.name = "Rex" mydog.age = 9 print("Name of dog: \(mydog.name)") // Realms are used to group data together let realm = try! Realm() // Create realm pointing to default file // Save your object realm.beginWrite() realm.add(mydog) try! realm.commitWrite()
  14. // Query let results = realm.objects(Dog.self). filter(NSPredicate(format:"name contains 'x'")) //

    Queries are chainable! let results2 = results.filter("age > 8") print("Number of dogs: \(results.count)") print("Dogs older than eight: \(results2.count)")
  15. LayoutKit let image = SizeLayout<UIImageView>(width: 50, height: 50, config: {

    imageView in imageView.image = UIImage(named: "earth.jpg") }) let label = LabelLayout(text: "Hello World!", alignment: .center) let stack = StackLayout( axis: .horizontal, spacing: 4, sublayouts: [image, label]) let insets = UIEdgeInsets(top: 4, left: 4, bottom: 4, right: 8) let helloWorld = InsetLayout(insets: insets, layout: stack) helloWorld.arrangement().makeViews(inView: rootView)
  16. /// A simple hello world view that uses Auto Layout.

    public class HelloWorldAutoLayout: UIView { private lazy var imageView: UIImageView = { let imageView = UIImageView() imageView.translatesAutoresizingMaskIntoConstraints = false imageView.setContentHuggingPriority(UILayoutPriorityRequired, forAxis: .Vertical) imageView.setContentHuggingPriority(UILayoutPriorityRequired, forAxis: .Horizontal) imageView.setContentCompressionResistancePriority(UILayoutPriorityRequired, forAxis: .Vertical) imageView.setContentCompressionResistancePriority(UILayoutPriorityRequired, forAxis: .Horizontal) imageView.image = UIImage(named: "earth.png") return imageView }() private lazy var label: UILabel = { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false label.text = "Hello World!" return label }() public override init(frame: CGRect) { super.init(frame: frame) addSubview(imageView) addSubview(label) let views = ["imageView": imageView, "label": label] var constraints = [NSLayoutConstraint]() constraints.appendContentsOf(NSLayoutConstraint.constraintsWithVisualFormat("V:|-4-[imageView(==50)]-4-|", options: [], metrics: nil, views: views)) constraints.appendContentsOf(NSLayoutConstraint.constraintsWithVisualFormat(“H:|-4-[imageView(==50)]-4-[label]-8-|", options: [], metrics: nil, views: views)) constraints.append(NSLayoutConstraint(item: label, attribute: .CenterY, relatedBy: .Equal, toItem: self, attribute: .CenterY, multiplier: 1, constant: 0)) NSLayoutConstraint.activateConstraints(constraints) } }
  17. Architecture : DI let viewModel = GithubSignupViewModel( input: ( username:

    username, password: password, repeatedPassword: repeatedPassword, loginTaps: signupOutlet ), dependency: ( API: GitHubAPI.sharedAPI, validationService: GitHubValidationService.sharedValidationService, wireframe: DefaultWireframe.sharedInstance ) ) ⚠ DI is meaningless without protocols
  18. Improving  MVC • POO: Protocols and Extensions • Separation

    of Concerns ( Services & Formatters ) • More layers: MVVM • VIPER
  19. class Store { var counterValue = 0 init() { dispatcher.addObserver(forName:

    actionNotification, using: { let action = $0.object as! Action switch(action) { case is ActionIncrease: self.counterValue = self.counterValue + 1 default: self.counterValue = self.counterValue - 1 } self.notifyStoreChange(); }); }
  20. class Store { // (continued) // incoming actions func dispatch(anAction

    : AnyObject) { dispatcher.post(name: actionNotification, object: anAction); } // stores func notifyStoreChange() { dispatcher.post(name: storeNotification, object: self) } func subscribe(_ subscriber: AnyObject, selector: Selector) { dispatcher.addObserver(subscriber, selector: selector, name: storeNotification, object: nil); }
  21. class ViewController: UIViewController { // ... override func viewDidLoad() {

    super.viewDidLoad() self.createUI() store.subscribe(self, selector: #selector(updateNumber)) } func updateNumber(n: Notification) { let num = (n.object as! Store).counterValue valueLabel?.text = "\(num)" } func plusPressed() { store.dispatch(anAction: ActionIncrease()) } func minusPressed() { store.dispatch(anAction: ActionDecrease()) }
  22. class Store { var state = State(); init() { dispatcher.addObserver(forName:

    actionNotification, using: { let action = $0.object as! Action self.state = reduce(state: self.state, action: action) self.notifyStoreChange(); }); }
  23. func reduce(state: State, action: Action) -> State { var newState

    = state; switch(action) { case is ActionIncrease: newState.counterValue = state.counterValue + 1 default: newState.counterValue = state.counterValue - 1 } return newState; }
  24. Voice [SFSpeechRecognizer requestAuthorization:^(SFSpeechRecognizerAuthorizationStatus status) { if (status == SFSpeechRecognizerAuthorizationStatusAuthorized){ SFSpeechRecognizer

    *recognizer = [[SFSpeechRecognizer alloc] initWithLocale:[NSLocale currentLocale]]; speechRequest = [[SFSpeechAudioBufferRecognitionRequest alloc] init]; speechRequest.taskHint = SFSpeechRecognitionTaskHintSearch; [recognizer recognitionTaskWithRequest:speechRequest delegate:self]; dispatch_async(dispatch_get_main_queue(), ^{ [self startCapture]; }); } }];
  25. TrueTone UIWhitePointAdaptivityStyle (9.3 & higher) UIWhitePointAdaptivityStyleStandard Default value. Standard white-point

    adaptivity. UIWhitePointAdaptivityStyleReading For reading-focused apps (stronger adaptivity than provided with the UIWhitePointAdaptivityStyleStandard option) UIWhitePointAdaptivityStylePhoto For photography-focused apps (weaker adaptivity than provided with the UIWhitePointAdaptivityStyleStandard option) UIWhitePointAdaptivityStyleVideo For video-focused apps (weaker adaptivity than provided with the UIWhitePointAdaptivityStyleStandard option) UIWhitePointAdaptivityStyleGame For games (weaker adaptivity than provided with the UIWhitePointAdaptivityStyleStandard option)
  26. More Stuff • SiriKit • Wide Color • App Search

    • Core Data / Core Image • SceneKit / SpriteKit • Basic Neural Network Subroutines
  27. Go • Compiled, static, structural • Used mostly for backend

    development in practice • Basic Apps (OpenGL) and bind (library integration)
  28. Go

  29. Rust • Compiled, static, object-oriented • Mozilla Servo & System

    Programming • can build static libs for arm • Bridge using C API • May work for Models
  30. Rust ———————— src/lib.rs #[no_mangle] pub extern fn rust_hello_world() -> i32

    { println!("Hello, I'm in Rust code! I'm about to return 10."); 10 } ———————— hello.h #pragma once #include <stdint.h> int32_t rust_hello_world(void); Source: https://www.bignerdranch.com/blog/building-an-ios-app-in-rust-part-1/
  31. React • JavaScript (ES 6) • JSX: built-in XML-like extensions

    • Manages View Hierarchies • Updates efficiently, using cache (VDOM)
  32. import React, { Component } from 'react'; import { ActivityIndicator,

    AppRegistry, StyleSheet, Text, View } from 'react-native'; class MyComponent extends Component { render() { return ( <View> <ActivityIndicator animating={true} style={styles.actStyle} /> <Text style={styles.instructions}> Hello uamobi.tech </Text> </View> ) } } class ReactNativeAwesomeProject extends Component { render() { return ( <View style={styles.container}> <MyComponent /> </View> ); } }
  33. React Native Native Components @implementation ActivityIndicator RCT_EXPORT_MODULE() - (UIView *)view

    { return [UIActivityIndicatorView new]; } RCT_EXPORT_VIEW_PROPERTY(hidesWhenStopped, BOOL) RCT_CUSTOM_VIEW_PROPERTY(animating, BOOL, UIActivityIndicatorView) { BOOL animating = json ? [RCTConvert BOOL:json] : [defaultView isAnimating]; if (animating != [view isAnimating]) { if (animating) { [view startAnimating]; } else { [view stopAnimating]; } } } @end
  34. Signal Protocol • By Open Whisper Systems • Adopted by:

    Google Allo, WhatsApp, Facebook Messenger • Open Source, including iOS app
  35. Overview • fbinfer, new in Obj-C, new in Swift •

    SQLite, Realm, LayoutKit • Architecture: General Notes, Flux/Redux • iOS 10 • Cross-Platform: Go / Rust / Other / React Native • Security: TLS, Signal
  36. Links • General Reliability • Top 5 Most Frequent Crashes

    on iOS • WWDC • Swift API Guidelines • Thread Sanitizer and Static Analysis • Static Analysis • fbinfer
  37. Links • Libs • LayoutKit (auto-layout alternative) • Realm (Core-Data

    alternative) • Architecture: • iOS Application Architecture talk by Krzysztof Zabłocki • iOS Architecture Patterns by Bohdan Orlov • Redux (for JS frontend) • ReSwift (Unidirectional Data Flow in Swift - Inspired by Redux)
  38. Links • What’s New in iOS 10 • Cross-Platform •

    Go Mobile • Building iOS app in Rust • JVM: Parpar VM and BugVM • React Native