iOS Notes For Professionals
iOS Notes For Professionals
iOS Developer
Notes for Professionals
®
Developer
Notes for Professionals
800+ pages
of professional hints and tricks
Disclaimer
GoalKicker.com This is an unocial free book created for educational purposes and is
not aliated with ocial iOS® Developer group(s) or company(s).
Free Programming Books All trademarks and registered trademarks are
the property of their respective owners
Contents
About ................................................................................................................................................................................... 1
Chapter 1: Getting started with iOS ..................................................................................................................... 2
Section 1.1: Creating a default Single View Application ............................................................................................. 2
Section 1.2: Hello World ................................................................................................................................................. 6
Section 1.3: Xcode Interface ....................................................................................................................................... 11
Section 1.4: Create your first program in Swift 3 ...................................................................................................... 17
Chapter 2: UILabel ...................................................................................................................................................... 22
Section 2.1: Create a UILabel ...................................................................................................................................... 22
Section 2.2: Number of Lines ..................................................................................................................................... 24
Section 2.3: Set Font .................................................................................................................................................... 25
Section 2.4: Text Color ................................................................................................................................................ 26
Section 2.5: Background Color .................................................................................................................................. 27
Section 2.6: Size to fit .................................................................................................................................................. 27
Section 2.7: Text alignment ........................................................................................................................................ 30
Section 2.8: Calculate Content Bounds (for i.e. dynamic cell heights) .................................................................. 30
Section 2.9: Label Attributed Text .............................................................................................................................. 32
Section 2.10: Clickable Label ...................................................................................................................................... 38
Section 2.11: Variable height using constraints ......................................................................................................... 39
Section 2.12: LineBreakMode ...................................................................................................................................... 39
Section 2.13: Add shadows to text ............................................................................................................................. 41
Section 2.14: Changing Text in an Existing Label ..................................................................................................... 41
Section 2.15: Auto-size label to fit text ....................................................................................................................... 42
Section 2.16: Get UILabel's size strictly based on its text and font ......................................................................... 43
Section 2.17: Highlighted and Highlighted Text Color .............................................................................................. 44
Section 2.18: Justify Text ............................................................................................................................................ 44
Section 2.19: Dynamic label frame from unknown text length ............................................................................... 45
Chapter 3: UILabel text underlining .................................................................................................................. 47
Section 3.1: Underlining a text in a UILabel using Objective C ................................................................................ 47
Section 3.2: Underlining a text in UILabel using Swift .............................................................................................. 47
Chapter 4: attributedText in UILabel ............................................................................................................... 48
Section 4.1: HTML text in UILabel ............................................................................................................................... 48
Section 4.2: Set dierent property to text in single UILabel ................................................................................... 48
Chapter 5: UIButton ................................................................................................................................................... 50
Section 5.1: Creating a UIButton ................................................................................................................................ 50
Section 5.2: Attaching a Method to a Button ........................................................................................................... 50
Section 5.3: Setting Font ............................................................................................................................................. 51
Section 5.4: Set Image ................................................................................................................................................ 51
Section 5.5: Get UIButton's size strictly based on its text and font ........................................................................ 51
Section 5.6: Disabling a UIButton ............................................................................................................................... 52
Section 5.7: Set title ..................................................................................................................................................... 52
Section 5.8: Set title color ........................................................................................................................................... 52
Section 5.9: Horizontally aligning contents .............................................................................................................. 53
Section 5.10: Getting the title label ............................................................................................................................. 53
Section 5.11: Adding an action to an UIButton via Code (programmatically) ....................................................... 54
Chapter 6: UIDatePicker .......................................................................................................................................... 55
Section 6.1: Create a Date Picker ............................................................................................................................... 55
Section 6.2: Setting Minimum-Maximum Date ......................................................................................................... 55
Section 6.3: Modes ....................................................................................................................................................... 55
Section 6.4: Setting minute interval ........................................................................................................................... 55
Section 6.5: Count Down Duration ............................................................................................................................. 56
Chapter 7: UILocalNotification ............................................................................................................................ 57
Section 7.1: Scheduling a local notification ............................................................................................................... 57
Section 7.2: Presenting a local notification immediately ........................................................................................ 57
Section 7.3: Managing local notifications using UUID ............................................................................................. 58
Section 7.4: Registering for local notifications ......................................................................................................... 59
Section 7.5: what's new in UILocalNotification with iOS10 ....................................................................................... 59
Section 7.6: Responding to received local notification ............................................................................................ 62
Section 7.7: Register and Schedule Local Notification in Swift 3.0 (iOS 10) ........................................................... 62
Chapter 8: UIImage .................................................................................................................................................... 64
Section 8.1: Creating UIImage .................................................................................................................................... 64
Section 8.2: Comparing Images ................................................................................................................................. 65
Section 8.3: Gradient Image with Colors ................................................................................................................... 66
Section 8.4: Convert UIImage to/from base64 encoding ....................................................................................... 66
Section 8.5: Take a Snapshot of a UIView ................................................................................................................ 66
Section 8.6: Change UIImage Color ........................................................................................................................... 67
Section 8.7: Apply UIColor to UIImage ...................................................................................................................... 67
Section 8.8: Creating and Initializing Image Objects with file contents ................................................................. 68
Section 8.9: Resizable image with caps .................................................................................................................... 68
Section 8.10: Gradient Background Layer for Bounds ............................................................................................ 69
Chapter 9: Convert NSAttributedString to UIImage ................................................................................. 70
Section 9.1: NSAttributedString to UIImage Conversion .......................................................................................... 70
Chapter 10: UIImagePickerController ............................................................................................................... 71
Section 10.1: Generic usage of UIImagePickerController ......................................................................................... 71
Chapter 11: UIImageView ......................................................................................................................................... 73
Section 11.1: UIImage masked with Label .................................................................................................................. 73
Section 11.2: Making an image into a circle or rounded .......................................................................................... 73
Section 11.3: How the Mode property aects an image .......................................................................................... 74
Section 11.4: Animating a UIImageView ..................................................................................................................... 80
Section 11.5: Create a UIImageView ........................................................................................................................... 81
Section 11.6: Change color of an image .................................................................................................................... 81
Section 11.7: Assigning an image to a UIImageView ................................................................................................ 81
Chapter 12: Resizing UIImage ............................................................................................................................... 83
Section 12.1: Resize any image by size & quality ...................................................................................................... 83
Chapter 13: Cut a UIImage into a circle ........................................................................................................... 84
Section 13.1: Cut a image into a circle - Objective C ................................................................................................ 84
Section 13.2: SWIFT 3 Example ................................................................................................................................... 85
Chapter 14: UITableView ......................................................................................................................................... 87
Section 14.1: Self-Sizing Cells ....................................................................................................................................... 87
Section 14.2: Custom Cells .......................................................................................................................................... 87
Section 14.3: Separator Lines ...................................................................................................................................... 90
Section 14.4: Delegate and Datasource .................................................................................................................... 92
Section 14.5: Creating a UITableView ........................................................................................................................ 98
Section 14.6: Swipe to Delete Rows ......................................................................................................................... 102
Section 14.7: Expanding & Collapsing UITableViewCells ....................................................................................... 105
Chapter 15: UITableViewController ................................................................................................................. 108
Section 15.1: TableView with dynamic properties with tableviewCellStyle basic ................................................ 108
Section 15.2: TableView with Custom Cell ............................................................................................................... 109
Chapter 16: UIRefreshControl TableView ..................................................................................................... 111
Section 16.1: Set up refreshControl on tableView: .................................................................................................. 111
Section 16.2: Objective-C Example .......................................................................................................................... 111
Chapter 17: UITableViewCell ............................................................................................................................... 113
Section 17.1: Xib file of UITableViewCell ................................................................................................................... 113
Chapter 18: Custom methods of selection of UITableViewCells ....................................................... 114
Section 18.1: Distinction between single and double selection on row ................................................................. 114
Chapter 19: Custom methods of selection of UITableViewCells ....................................................... 115
Section 19.1: Distinction between single and double selection on row ................................................................. 115
Chapter 20: UIView .................................................................................................................................................. 116
Section 20.1: Make the view rounded ...................................................................................................................... 116
Section 20.2: Using IBInspectable and IBDesignable ............................................................................................ 118
Section 20.3: Taking a snapshot .............................................................................................................................. 121
Section 20.4: Create a UIView .................................................................................................................................. 121
Section 20.5: Shake a View ...................................................................................................................................... 121
Section 20.6: Utilizing Intrinsic Content Size ........................................................................................................... 121
Section 20.7: Programmatically manage UIView insertion and deletion into and from another UIView
............................................................................................................................................................................. 124
Section 20.8: Create UIView using Autolayout ....................................................................................................... 125
Section 20.9: Animating a UIView ............................................................................................................................ 127
Section 20.10: UIView extension for size and frame attributes ............................................................................ 127
Chapter 21: Snapshot of UIView ........................................................................................................................ 129
Section 21.1: Getting the Snapshot ........................................................................................................................... 129
Section 21.2: Snapshot with subview with other markup and text ....................................................................... 129
Chapter 22: UIAlertController ............................................................................................................................. 131
Section 22.1: AlertViews with UIAlertController ...................................................................................................... 131
Section 22.2: Action Sheets with UIAlertController ................................................................................................ 132
Section 22.3: Adding Text Field in UIAlertController like a prompt Box .............................................................. 134
Section 22.4: Highlighting an action button ........................................................................................................... 135
Section 22.5: Displaying and handling alerts ......................................................................................................... 136
Chapter 23: UIColor ................................................................................................................................................. 140
Section 23.1: Creating a UIColor ............................................................................................................................... 140
Section 23.2: Creating a UIColor from hexadecimal number or string ............................................................... 141
Section 23.3: Color with Alpha component ............................................................................................................. 143
Section 23.4: Undocumented Methods ................................................................................................................... 144
Section 23.5: UIColor from an image pattern ........................................................................................................ 145
Section 23.6: Lighter and Darker Shade of a given UIColor ................................................................................. 146
Section 23.7: Make user defined attributes apply the CGColor datatype ........................................................... 147
Chapter 24: UITextView ........................................................................................................................................ 148
Section 24.1: Set attributed text ............................................................................................................................... 148
Section 24.2: Change font ........................................................................................................................................ 148
Section 24.3: Auto Detect Links, Addresses, Dates, and more ............................................................................. 148
Section 24.4: Change text ......................................................................................................................................... 149
Section 24.5: Change text alignment ...................................................................................................................... 149
Section 24.6: UITextViewDelegate methods .......................................................................................................... 149
Section 24.7: Change text color ............................................................................................................................... 150
Section 24.8: Remove extra paddings to fit to a precisely measured text ......................................................... 150
Section 24.9: Getting and Setting the Cursor Postition ......................................................................................... 150
Section 24.10: UITextView with HTML text .............................................................................................................. 152
Section 24.11: Check to see if empty or nil .............................................................................................................. 152
Chapter 25: UITextField Delegate .................................................................................................................... 153
Section 25.1: Actions when a user has started/ended interacting with a textfield ............................................. 153
Section 25.2: UITextField - Restrict textfield to certain characters ...................................................................... 154
Chapter 26: UINavigationController ............................................................................................................... 155
Section 26.1: Embed a view controller in a navigation controller programmatically ........................................ 155
Section 26.2: Popping in a Navigation Controller .................................................................................................. 155
Section 26.3: Purpose ................................................................................................................................................ 155
Section 26.4: Pushing a view controller onto the navigation stack ..................................................................... 156
Section 26.5: Creating a NavigationController ....................................................................................................... 156
Chapter 27: UIGestureRecognizer .................................................................................................................... 157
Section 27.1: UITapGestureRecognizer ................................................................................................................... 157
Section 27.2: UITapGestureRecognizer (Double Tap) .......................................................................................... 158
Section 27.3: Adding a Gesture recognizer in the Interface Builder .................................................................... 158
Section 27.4: UILongPressGestureRecognizer ....................................................................................................... 159
Section 27.5: UISwipeGestureRecognizer ............................................................................................................... 160
Section 27.6: UIPinchGestureRecognizer ................................................................................................................ 161
Section 27.7: UIRotationGestureRecognizer ........................................................................................................... 162
Chapter 28: UIBarButtonItem ............................................................................................................................ 163
Section 28.1: Creating a UIBarButtonItem in the Interface Builder ...................................................................... 163
Section 28.2: Creating a UIBarButtonItem ............................................................................................................. 166
Section 28.3: Bar Button Item Original Image with no Tint Color ........................................................................ 166
Chapter 29: UIScrollView ....................................................................................................................................... 167
Section 29.1: Scrolling content with Auto Layout enabled .................................................................................... 167
Section 29.2: Create a UIScrollView ........................................................................................................................ 170
Section 29.3: ScrollView with AutoLayout ............................................................................................................... 170
Section 29.4: Detecting when UIScrollView finished scrolling with delegate methods ...................................... 175
Section 29.5: Enable/Disable Scrolling ................................................................................................................... 175
Section 29.6: Zoom In/Out UIImageView ............................................................................................................... 176
Section 29.7: Scroll View Content Size ..................................................................................................................... 177
Section 29.8: Restrict scrolling direction ................................................................................................................. 177
Chapter 30: UIStackView ...................................................................................................................................... 178
Section 30.1: Center Buttons with UIStackview ....................................................................................................... 178
Section 30.2: Create a horizontal stack view programmatically ......................................................................... 182
Section 30.3: Create a vertical stack view programmatically .............................................................................. 183
Chapter 31: Dynamically updating a UIStackView .................................................................................. 184
Section 31.1: Connect the UISwitch to an action we can animate switching between a horizontal or vertical
layout of the image views ................................................................................................................................ 184
Chapter 32: UIScrollView with StackView child ......................................................................................... 185
Section 32.1: A complex StackView inside Scrollview Example ............................................................................. 185
Section 32.2: Preventing ambiguous layout ........................................................................................................... 186
Section 32.3: Scrolling to content inside nested StackViews ................................................................................ 187
Chapter 33: UIScrollView AutoLayout ............................................................................................................ 188
Section 33.1: ScrollableController ............................................................................................................................. 188
Section 33.2: UIScrollView dynamic content size through Storyboard ............................................................... 192
Chapter 34: UITextField ......................................................................................................................................... 194
Section 34.1: Get Keyboard Focus and Hide Keyboard ........................................................................................ 194
Section 34.2: Dismiss keyboard when user pushes the return button ................................................................. 194
Section 34.3: Hide blinking caret .............................................................................................................................. 195
Section 34.4: Input accessory view (toolbar) ......................................................................................................... 195
Section 34.5: Moving scroll when UITextView becomes first responder ............................................................. 196
Section 34.6: KeyboardType .................................................................................................................................... 198
Section 34.7: Change placeholder color and font ................................................................................................. 198
Section 34.8: Replace keyboard with UIPickerView ............................................................................................... 199
Section 34.9: Create a UITextField ........................................................................................................................... 202
Section 34.10: Getting and Setting the Cursor Position ......................................................................................... 203
Section 34.11: Dismiss Keyboard .............................................................................................................................. 204
Section 34.12: Initialize text field ............................................................................................................................... 207
Section 34.13: Autocapitalization .............................................................................................................................. 207
Section 34.14: Set Alignment .................................................................................................................................... 208
Chapter 35: Custom UITextField ....................................................................................................................... 209
Section 35.1: Custom UITextField for Filtering Input Text ...................................................................................... 209
Section 35.2: Custom UITextField to Disallow All Actions like Copy, Paste, etc .................................................. 209
Chapter 36: UIViewController ............................................................................................................................. 211
Section 36.1: Subclassing .......................................................................................................................................... 211
Section 36.2: Access the container view controller ................................................................................................ 213
Section 36.3: Set the view programmatically ......................................................................................................... 213
Section 36.4: Instantiate from a Storyboard .......................................................................................................... 213
Section 36.5: Create an instance ............................................................................................................................. 214
Section 36.6: Adding/removing a child view controller ......................................................................................... 215
Chapter 37: UISwitch ............................................................................................................................................... 216
Section 37.1: Set Image for On/O state ................................................................................................................ 216
Section 37.2: Set On / O ......................................................................................................................................... 216
Section 37.3: Set Background Color ........................................................................................................................ 216
Section 37.4: Set Tint Color ....................................................................................................................................... 217
Chapter 38: UICollectionView ............................................................................................................................. 218
Section 38.1: Create a UICollectionView .................................................................................................................. 218
Section 38.2: UICollectionView - Datasource ......................................................................................................... 218
Section 38.3: Basic Swift example of a Collection View ........................................................................................ 219
Section 38.4: Manage Multiple Collection view with DataSource and Flowlayout ............................................. 224
Section 38.5: UICollectionViewDelegate setup and item selection ...................................................................... 226
Section 38.6: Create a Collection View Programmatically ................................................................................... 227
Section 38.7: Swift - UICollectionViewDelegateFlowLayout ................................................................................. 228
Section 38.8: Performing batch updates ................................................................................................................ 228
Chapter 39: UISearchController ........................................................................................................................ 230
Section 39.1: Search Bar in Navigation Bar Title .................................................................................................... 230
Section 39.2: Search Bar in Table View Header ..................................................................................................... 233
Section 39.3: Implementation ................................................................................................................................... 236
Section 39.4: UISerachController in Objective-C .................................................................................................... 236
Chapter 40: UITabBarController ...................................................................................................................... 238
Section 40.1: Create an instance .............................................................................................................................. 238
Section 40.2: Navigation Controller with TabBar .................................................................................................. 238
Section 40.3: Tab Bar color customizing ................................................................................................................ 239
Section 40.4: Changing Tab Bar Item Title and Icon ............................................................................................. 239
Section 40.5: Create Tab Bar controller programmatically without Storyboard ............................................... 240
Section 40.6: UITabBarController with custom color selection ............................................................................ 241
Chapter 41: UIWebView ......................................................................................................................................... 244
Section 41.1: Create a UIWebView instance ............................................................................................................ 244
Section 41.2: Determining content size ................................................................................................................... 244
Section 41.3: Load HTML string ................................................................................................................................ 244
Section 41.4: Making a URL request ........................................................................................................................ 245
Section 41.5: Load JavaScript .................................................................................................................................. 245
Section 41.6: Stop Loading Web Content ................................................................................................................ 246
Section 41.7: Reload Current Web Content ............................................................................................................. 246
Section 41.8: Load Document files like .pdf, .txt, .doc etc ...................................................................................... 246
Section 41.9: Load local HTML file in webView ....................................................................................................... 246
Section 41.10: Make links That inside UIWebview clickable ................................................................................... 247
Chapter 42: UIActivityViewController ............................................................................................................ 249
Section 42.1: Initializing the Activity View Controller .............................................................................................. 249
Chapter 43: UIControl - Event Handling with Blocks ............................................................................. 250
Section 43.1: Introduction .......................................................................................................................................... 250
Chapter 44: UISplitViewController .................................................................................................................. 253
Section 44.1: Master and Detail View interaction using Delegates in Objective C .............................................. 253
Chapter 45: UISlider ................................................................................................................................................ 263
Section 45.1: UISlider ................................................................................................................................................. 263
Section 45.2: SWIFT Example ................................................................................................................................... 263
Section 45.3: Adding a custom thumb image ........................................................................................................ 263
Chapter 46: UIStoryboard ................................................................................................................................... 265
Section 46.1: Getting an instance of UIStoryboard programmatically ................................................................ 265
Section 46.2: Open another storyboard ................................................................................................................. 265
Chapter 47: UIPageViewController ................................................................................................................. 266
Section 47.1: Create a horizontal paging UIPageViewController programatically ............................................. 266
Section 47.2: A simple way to create horizontal page view controllers ( infinite pages ) ................................. 267
Chapter 48: UISplitViewController .................................................................................................................. 271
Section 48.1: Interacting Between Master and Detail View using Delegates in Objective C ............................. 271
Chapter 49: UIFont .................................................................................................................................................. 275
Section 49.1: Declaring and initializing UIFont ........................................................................................................ 275
Section 49.2: Changing the font of a label ............................................................................................................. 275
Chapter 50: UIDevice .............................................................................................................................................. 276
Section 50.1: Get iOS device model name .............................................................................................................. 276
Section 50.2: Identifying the Device and Operating .............................................................................................. 277
Section 50.3: Getting the Device Orientation ......................................................................................................... 278
Section 50.4: Getting the Device Battery State ...................................................................................................... 279
Section 50.5: Using the Proximity Sensor ............................................................................................................... 280
Section 50.6: Getting Battery Status and Battery Level ....................................................................................... 280
Chapter 51: Make selective UIView corners rounded ............................................................................. 281
Section 51.1: Objective C code to make selected corner of a UiView rounded ................................................... 281
Chapter 52: Custom UIViews from XIB files ................................................................................................ 282
Section 52.1: Wiring elements .................................................................................................................................. 282
Section 52.2: How to make custom reusable UIView using XIB ........................................................................... 296
Chapter 53: UIBezierPath ..................................................................................................................................... 297
Section 53.1: Designing and drawing a Bezier Path ............................................................................................... 297
Section 53.2: How to apply corner radius to rectangles drawn by UIBezierPath .............................................. 302
Section 53.3: How to apply shadows to UIBezierPath ........................................................................................... 304
Section 53.4: How to create a simple shapes using UIBezierPath ....................................................................... 306
Section 53.5: UIBezierPath + AutoLayout ............................................................................................................... 308
Section 53.6: pie view & column view with UIBezierPath ....................................................................................... 309
Chapter 54: UIPickerView ..................................................................................................................................... 312
Section 54.1: Basic example ..................................................................................................................................... 312
Section 54.2: Changing pickerView Background Color and text color ................................................................ 313
Chapter 55: UIFeedbackGenerator ................................................................................................................. 314
Section 55.1: Trigger Impact Haptic ........................................................................................................................ 314
Chapter 56: UIAppearance .................................................................................................................................. 316
Section 56.1: Set appearance of all instances of the class ................................................................................... 316
Section 56.2: Appearance for class when contained in container class ............................................................. 317
Chapter 57: UIKit Dynamics with UICollectionView ................................................................................. 318
Section 57.1: Creating a Custom Dragging Behavior with UIDynamicAnimator ................................................ 318
Chapter 58: UIPheonix - easy, flexible, dynamic & highly scalable UI framework ................. 328
Section 58.1: Example UI Components .................................................................................................................... 328
Section 58.2: Example Usage ................................................................................................................................... 330
Chapter 59: UIKit Dynamics ................................................................................................................................ 331
Section 59.1: Flick View Based on Gesture Velocity ............................................................................................... 331
Section 59.2: "Sticky Corners" Eect Using UIFieldBehaviors .............................................................................. 334
Section 59.3: UIDynamicBehavior Driven Custom Transition ............................................................................... 339
Section 59.4: Shade Transition with Real-World Physics Using UIDynamicBehaviors ...................................... 350
Section 59.5: Map Dynamic Animation Position Changes to Bounds .................................................................. 361
Section 59.6: The Falling Square ............................................................................................................................. 366
Chapter 60: UI Testing ........................................................................................................................................... 369
Section 60.1: Accessibility Identifier ......................................................................................................................... 369
Section 60.2: Adding Test Files to Xcode Project ................................................................................................... 371
Section 60.3: Disable animations during UI Testing .............................................................................................. 372
Section 60.4: Lunch and Terminate application while executing ......................................................................... 372
Section 60.5: Rotate devices .................................................................................................................................... 372
Chapter 61: Change Status Bar Color ............................................................................................................. 373
Section 61.1: For non-UINavigationBar status bars ................................................................................................ 373
Section 61.2: For UINavigationBar status bars ....................................................................................................... 373
Section 61.3: For ViewController containment ........................................................................................................ 374
Section 61.4: If you cannot change ViewController's code ................................................................................... 374
Section 61.5: Changing the status bar style for the entire application ................................................................ 374
Chapter 62: UISegmentedControl .................................................................................................................... 376
Section 62.1: Creating UISegmentedControl via code ........................................................................................... 376
Chapter 63: Passing Data between View Controllers ............................................................................ 377
Section 63.1: Using the Delegate Pattern (passing data back) ............................................................................ 377
Section 63.2: Using Segues (passing data forward) ............................................................................................. 379
Section 63.3: Passing data backwards using unwind to segue ............................................................................ 380
Section 63.4: Passing data using closures (passing data back) .......................................................................... 381
Section 63.5: Using callback closure(block) passing data back .......................................................................... 382
Section 63.6: By assigning property (Passing data forward) ............................................................................... 383
Chapter 64: Managing the Keyboard ............................................................................................................ 384
Section 64.1: Create a custom in-app keyboard .................................................................................................... 384
Section 64.2: Dismiss a keyboard with tap on view ............................................................................................... 388
Section 64.3: Managing the Keyboard Using a Singleton + Delegate ................................................................. 389
Section 64.4: Moving view up or down when keyboard is present ...................................................................... 392
Section 64.5: Scrolling a UIScrollView/UITableView When Displaying the Keyboard ....................................... 393
Chapter 65: Checking for Network Connectivity ...................................................................................... 395
Section 65.1: Creating a Reachability listener ......................................................................................................... 395
Section 65.2: Add observer to network changes ................................................................................................... 395
Section 65.3: Alert when network becomes unavailable ....................................................................................... 395
Section 65.4: Alert when connection becomes a WIFI or cellular network ......................................................... 395
Section 65.5: Verify if is connected to network ...................................................................................................... 396
Chapter 66: Accessibility ....................................................................................................................................... 398
Section 66.1: Make a View Accessible ...................................................................................................................... 398
Section 66.2: Accessibility Frame ............................................................................................................................ 398
Section 66.3: Layout Change ................................................................................................................................... 398
Section 66.4: Accessibility Container ....................................................................................................................... 398
Section 66.5: Hiding Elements .................................................................................................................................. 399
Section 66.6: Screen Change .................................................................................................................................... 399
Section 66.7: Announcement .................................................................................................................................... 399
Section 66.8: Ordering Elements ............................................................................................................................. 399
Section 66.9: Modal View .......................................................................................................................................... 400
Chapter 67: Auto Layout ....................................................................................................................................... 401
Section 67.1: Space Views Evenly ............................................................................................................................. 401
Section 67.2: Center Constraints .............................................................................................................................. 402
Section 67.3: Setting constraints programmatically .............................................................................................. 405
Section 67.4: UILabel & Parentview size According to Text in UILabel ................................................................ 406
Section 67.5: UILabel Intrinsic Size ........................................................................................................................... 411
Section 67.6: Visual Format Language Basics: Constraints in Code! ................................................................... 421
Section 67.7: Resolve UILabel Priority Conflict ....................................................................................................... 423
Section 67.8: How to animate with Auto Layout .................................................................................................... 425
Section 67.9: NSLayoutConstraint: Contraints in code! ......................................................................................... 426
Section 67.10: Proportional Layout .......................................................................................................................... 427
Section 67.11: Mixed usage of Auto Layout with non-Auto Layout ....................................................................... 428
Section 67.12: How to use Auto Layout ................................................................................................................... 428
Chapter 68: MKMapView ....................................................................................................................................... 430
Section 68.1: Change map-type ............................................................................................................................... 430
Section 68.2: Simulate a custom location ............................................................................................................... 434
Section 68.3: Set Zoom/Region for Map ................................................................................................................ 434
Section 68.4: Local search implementation using MKLocalSearch ..................................................................... 435
Section 68.5: OpenStreetMap Tile-Overlay ............................................................................................................ 435
Section 68.6: Scroll to coordinate and zoom-level ................................................................................................ 437
Section 68.7: Working With Annotation .................................................................................................................. 439
Section 68.8: Add MKMapView ................................................................................................................................ 439
Section 68.9: Show UserLocation and UserTracking example ............................................................................. 440
Section 68.10: Adding Pin/Point Annotation on map ............................................................................................. 443
Section 68.11: Adjust the map view's visible rect in order to display all annotations ......................................... 444
Chapter 69: NSArray ............................................................................................................................................... 445
Section 69.1: Convert Array into json string ............................................................................................................ 445
Chapter 70: NSAttributedString ....................................................................................................................... 446
Section 70.1: Creating a string that has custom kerning (letter spacing) ........................................................... 446
Section 70.2: Change the color of a word or string ............................................................................................... 446
Section 70.3: Removing all attributes ...................................................................................................................... 447
Section 70.4: Appending Attributed Strings and bold text in Swift ...................................................................... 447
Section 70.5: Create a string with strikethrough text ............................................................................................ 447
Chapter 71: Convert HTML to NSAttributed string and vice verse ................................................. 449
Section 71.1: Objective C code to convert HTML string to NSAttributedString and Vice Versa ......................... 449
Chapter 72: NSTimer ............................................................................................................................................... 450
Section 72.1: Creating a Timer ................................................................................................................................. 450
Section 72.2: Manually firing a timer ....................................................................................................................... 450
Section 72.3: Timer frequency options ................................................................................................................... 451
Section 72.4: Invalidating a timer ............................................................................................................................ 452
Section 72.5: Passing of data using Timer ............................................................................................................. 452
Chapter 73: NSDate ................................................................................................................................................. 453
Section 73.1: NSDateFormatter ................................................................................................................................ 453
Section 73.2: Date Comparison ............................................................................................................................... 454
Section 73.3: Get Historic Time from NSDate (eg: 5s ago, 2m ago, 3h ago) ...................................................... 456
Section 73.4: Get Unix Epoch time ........................................................................................................................... 456
Section 73.5: Get NSDate from JSON Date format "/Date(1268123281843)/" .................................................... 456
Section 73.6: Get time cycle type (12-hour or 24-hour) ......................................................................................... 457
Section 73.7: Get Current Date ................................................................................................................................. 457
Section 73.8: Get NSDate Object N seconds from current date .......................................................................... 458
Section 73.9: UTC Time oset from NSDate with TimeZone ................................................................................ 458
Section 73.10: Convert NSDate that is composed from hour and minute (only) to a full NSDate ................... 459
Chapter 74: NSNotificationCenter .................................................................................................................. 460
Section 74.1: Removing Observers .......................................................................................................................... 460
Section 74.2: Adding an Observer ........................................................................................................................... 460
Section 74.3: Posting a Notification with Data ....................................................................................................... 461
Section 74.4: Add and remove observer for name ............................................................................................... 461
Section 74.5: Posting a Notification ......................................................................................................................... 461
Section 74.6: Observing a Notification .................................................................................................................... 462
Section 74.7: Adding/Removing an Observer with a Block .................................................................................. 462
Chapter 75: NSURLSession .................................................................................................................................. 463
Section 75.1: Objective-C Create a Session And Data Task .................................................................................. 463
Section 75.2: Setting up background configuration .............................................................................................. 463
Section 75.3: Simple GET request ............................................................................................................................ 464
Section 75.4: Sending a POST Request with arguments using NSURLSession in Objective-C ......................... 464
Chapter 76: NSUserDefaults ............................................................................................................................... 469
Section 76.1: Setting values ...................................................................................................................................... 469
Section 76.2: UserDefaults uses in Swift 3 .............................................................................................................. 470
Section 76.3: Use Managers to Save and Read Data ............................................................................................ 471
Section 76.4: Saving Values ...................................................................................................................................... 473
Section 76.5: Clearing NSUserDefaults ................................................................................................................... 473
Section 76.6: Getting Default Values ....................................................................................................................... 473
Chapter 77: NSHTTPCookieStorage ............................................................................................................... 475
Section 77.1: Store and read the cookies from NSUserDefault ............................................................................ 475
Chapter 78: NSURLConnection .......................................................................................................................... 477
Section 78.1: Delegate methods ............................................................................................................................... 477
Section 78.2: Synchronous Request ........................................................................................................................ 477
Section 78.3: Asynchronous request ....................................................................................................................... 478
Chapter 79: NSURL .................................................................................................................................................. 479
Section 79.1: How to get last string component from NSURL String ................................................................... 479
Section 79.2: How to get last string component from URL (NSURL) in Swift ..................................................... 479
Chapter 80: NSData ................................................................................................................................................ 480
Section 80.1: Converting NSData to HEX string ..................................................................................................... 480
Section 80.2: Creating NSData objects ................................................................................................................... 480
Section 80.3: Converting NSData to other types ................................................................................................... 480
Chapter 81: NSInvocation ..................................................................................................................................... 482
Section 81.1: NSInvocation Objective-C ................................................................................................................... 482
Chapter 82: NSUserActivity ................................................................................................................................. 484
Section 82.1: Creating a NSUserActivity .................................................................................................................. 484
Chapter 83: NSPredicate ...................................................................................................................................... 485
Section 83.1: Form validation using NSPredicate ................................................................................................... 485
Section 83.2: Creating an NSPredicate Using predicateWithBlock ...................................................................... 486
Section 83.3: Creating an NSPredicate Using predicateWithFormat .................................................................. 486
Section 83.4: Creating an NSPredicate with Substitution Variables ..................................................................... 487
Section 83.5: NSPredicate with `AND`, `OR` and `NOT` condition .......................................................................... 487
Section 83.6: Using NSPredicate to Filter an Array ............................................................................................... 487
Chapter 84: NSBundle ........................................................................................................................................... 489
Section 84.1: Getting Bundle by Path ....................................................................................................................... 489
Section 84.2: Getting the Main Bundle .................................................................................................................... 489
Chapter 85: CAAnimation ..................................................................................................................................... 490
Section 85.1: Animate a view from one position to another ................................................................................. 490
Section 85.2: Animate View - Toss .......................................................................................................................... 490
Section 85.3: Push View Animation .......................................................................................................................... 490
Section 85.4: Revolve View ....................................................................................................................................... 491
Section 85.5: Shake View .......................................................................................................................................... 491
Chapter 86: Concurrency ...................................................................................................................................... 492
Section 86.1: Dispatch group - waiting for other threads completed .................................................................. 492
Section 86.2: Executing on the main thread ........................................................................................................... 493
Section 86.3: Running code concurrently -- Running code while running other code ...................................... 493
Chapter 87: CAGradientLayer ............................................................................................................................ 494
Section 87.1: Creating a CAGradientLayer .............................................................................................................. 494
Section 87.2: Animating a color change in CAGradientLayer .............................................................................. 495
Section 87.3: Creating a horizontal CAGradientLayer ........................................................................................... 496
Section 87.4: Creating a horizontal CAGradientLayer with multiple colors ........................................................ 497
Section 87.5: Creating a CGGradientLayer with multiple colors .......................................................................... 498
Chapter 88: Safari Services ................................................................................................................................ 500
Section 88.1: Open a URL with SafariViewController ............................................................................................. 500
Section 88.2: Implement SFSafariViewControllerDelegate .................................................................................. 500
Section 88.3: Add Items to Safari Reading List ...................................................................................................... 501
Chapter 89: CALayer ............................................................................................................................................... 502
Section 89.1: Adding Transforms to a CALayer (translate, rotate, scale) ........................................................... 502
Section 89.2: Shadows .............................................................................................................................................. 506
Section 89.3: Emitter View with custom image ...................................................................................................... 507
Section 89.4: Rounded corners ................................................................................................................................ 508
Section 89.5: Creating particles with CAEmitterLayer ........................................................................................... 508
Section 89.6: How to add a UIImage to a CALayer ............................................................................................... 509
Section 89.7: Disable Animations ............................................................................................................................. 512
Chapter 90: iOS - Implementation of XMPP with Robbie Hanson framework .......................... 514
Section 90.1: iOS XMPP Robbie Hanson Example with Openfire .......................................................................... 514
Chapter 91: Swift and Objective-C interoperability ................................................................................ 517
Section 91.1: Using Objective-C Classes in Swift ..................................................................................................... 517
Section 91.2: Using Swift Classes in Objective-C .................................................................................................... 519
Chapter 92: Custom fonts .................................................................................................................................... 521
Section 92.1: Embedding custom fonts ................................................................................................................... 521
Section 92.2: Applying custom fonts to controls within a Storyboard ................................................................ 521
Section 92.3: Custom Fonts with Storyboard ......................................................................................................... 524
Chapter 93: AVSpeechSynthesizer ................................................................................................................... 527
Section 93.1: Creating a basic text to speech ......................................................................................................... 527
Chapter 94: Localization ...................................................................................................................................... 528
Section 94.1: Localization in iOS ............................................................................................................................... 528
Chapter 95: Alamofire ............................................................................................................................................ 529
Section 95.1: Manual Validation ............................................................................................................................... 529
Section 95.2: Automatic Validation ......................................................................................................................... 529
Section 95.3: Chained Response Handlers ............................................................................................................. 529
Section 95.4: Making a Request ............................................................................................................................... 529
Section 95.5: Response Handling ............................................................................................................................ 529
Section 95.6: Response Handler .............................................................................................................................. 530
Chapter 96: iBeacon ................................................................................................................................................ 531
Section 96.1: iBeacon Basic Operation .................................................................................................................... 531
Section 96.2: Ranging iBeacons .............................................................................................................................. 531
Section 96.3: Scanning specific Beacons ................................................................................................................ 532
Chapter 97: CLLocation ......................................................................................................................................... 533
Section 97.1: Distance Filter using ............................................................................................................................ 533
Section 97.2: Get User Location Using CLLocationManager ................................................................................ 533
Chapter 98: Checking iOS version .................................................................................................................... 535
Section 98.1: iOS 8 and later ..................................................................................................................................... 535
Section 98.2: Swift 2.0 and later .............................................................................................................................. 535
Section 98.3: Compare versions .............................................................................................................................. 535
Section 98.4: Device iOS Version ............................................................................................................................. 535
Chapter 99: Universal Links ................................................................................................................................. 537
Section 99.1: Setup iOS Application (Enabling Universal Links) ............................................................................ 537
Section 99.2: Supporting Multiple Domains ............................................................................................................ 540
Section 99.3: Signing the App-Site-Association File ............................................................................................... 540
Section 99.4: Setup Server ........................................................................................................................................ 540
Chapter 100: PDF Creation in iOS ..................................................................................................................... 542
Section 100.1: Create PDF ......................................................................................................................................... 542
Section 100.2: Show PDF ........................................................................................................................................... 543
Section 100.3: Multiple page PDF ............................................................................................................................. 544
Section 100.4: Create PDF from any Microsoft Document loaded in UIWebview .............................................. 544
Chapter 101: In-App Purchase ............................................................................................................................. 546
Section 101.1: Single IAP in Swift 2 ............................................................................................................................ 546
Section 101.2: Most basic steps for purchasing/subscribing a user to an IAP .................................................... 548
Section 101.3: Set Up in iTunesConnect ................................................................................................................... 548
Chapter 102: CGContext Reference ................................................................................................................. 550
Section 102.1: Draw line ............................................................................................................................................. 550
Section 102.2: Draw Text .......................................................................................................................................... 550
Chapter 103: Core Location ................................................................................................................................. 552
Section 103.1: Request Permission to Use Location Services ................................................................................ 552
Section 103.2: Add own custom location using GPX file ........................................................................................ 555
Section 103.3: Link CoreLocation Framework ........................................................................................................ 555
Section 103.4: Location Services in the Background ............................................................................................. 556
Chapter 104: FacebookSDK ................................................................................................................................. 558
Section 104.1: Creating your own custom "Sign In With Facebook" button ........................................................ 558
Section 104.2: FacebookSDK Integration ................................................................................................................ 558
Section 104.3: Fetching the facebook user data .................................................................................................... 561
Chapter 105: AFNetworking ................................................................................................................................. 562
Section 105.1: Dispatching completion block on a custom thread ....................................................................... 562
Chapter 106: CTCallCenter ................................................................................................................................... 563
Section 106.1: CallKit - ios 10 ..................................................................................................................................... 563
Section 106.2: Intercepting calls from your app even from the background ..................................................... 563
Chapter 107: Push Notifications ........................................................................................................................ 565
Section 107.1: Registering device for Push Notifications ....................................................................................... 565
Section 107.2: Registering App ID for use with Push Notifications ....................................................................... 568
Section 107.3: Testing push notifications ................................................................................................................ 570
Section 107.4: Checking if your app is already registered for Push Notification ................................................ 572
Section 107.5: Generating a .pem certificate from your .cer file, to pass on to the server developer ............. 572
Section 107.6: Unregistering From Push Notifications ........................................................................................... 572
Section 107.7: Setting the application icon badge number ................................................................................... 573
Section 107.8: Registering for (Non Interactive) Push Notification ...................................................................... 573
Section 107.9: Handling Push Notification ............................................................................................................... 574
Chapter 108: Extension for rich Push Notification - iOS 10. ................................................................. 576
Section 108.1: Notification Content Extension ......................................................................................................... 576
Section 108.2: Implementation ................................................................................................................................. 576
Chapter 109: Rich Notifications ......................................................................................................................... 578
Section 109.1: Creating a simple UNNotificationContentExtension ...................................................................... 578
Chapter 110: Key Value Coding-Key Value Observation ...................................................................... 583
Section 110.1: Observing a property of a NSObject subclass ................................................................................ 583
Section 110.2: Use of context for KVO Observation ............................................................................................... 583
Chapter 111: Initialization idioms ........................................................................................................................ 584
Section 111.1: Factory method with block ................................................................................................................. 584
Section 111.2: Set to tuples to avoid code repetition .............................................................................................. 584
Section 111.3: Initialize with positional constants ..................................................................................................... 584
Section 111.4: Initialize attributes in didSet ............................................................................................................... 585
Section 111.5: Group outlets in a custom NSObject ................................................................................................ 585
Section 111.6: Initialize with then ................................................................................................................................ 585
Chapter 112: Storyboard ....................................................................................................................................... 587
Section 112.1: Initialize ................................................................................................................................................ 587
Section 112.2: Fetch Initial ViewController ............................................................................................................... 587
Section 112.3: Fetch ViewController ......................................................................................................................... 587
Chapter 113: Background Modes and Events .............................................................................................. 588
Section 113.1: Play Audio in Background .................................................................................................................. 588
Chapter 114: Fastlane ............................................................................................................................................. 590
Section 114.1: fastlane tools ....................................................................................................................................... 590
Chapter 115: CAShapeLayer ................................................................................................................................ 591
Section 115.1: Draw Rectangle .................................................................................................................................. 591
Section 115.2: Draw Circle ......................................................................................................................................... 591
Section 115.3: CAShapeLayer Animation ................................................................................................................. 592
Section 115.4: Basic CAShapeLayer Operation ....................................................................................................... 593
Chapter 116: WKWebView ..................................................................................................................................... 597
Section 116.1: Adding custom user script loaded from app bundle ...................................................................... 597
Section 116.2: Send messages from JavaScript and Handle them on the native side ....................................... 597
Section 116.3: Creating a Simple WebBrowser ....................................................................................................... 598
Chapter 117: UUID (Universally Unique Identifier) .................................................................................... 606
Section 117.1: Apple's IFA vs. IFV (Apple Identifier for Advertisers vs. Identifier for Vendors) ............................ 606
Section 117.2: Create UUID String for iOS devices .................................................................................................. 606
Section 117.3: Generating UUID ................................................................................................................................ 606
Section 117.4: Identifier for vendor ........................................................................................................................... 607
Chapter 118: Categories ......................................................................................................................................... 608
Section 118.1: Create a Category .............................................................................................................................. 608
Chapter 119: Handling URL Schemes ............................................................................................................... 611
Section 119.1: Using built-in URL scheme to open Mail app ................................................................................... 611
Section 119.2: Apple URL Schemes .......................................................................................................................... 611
Chapter 120: Realm ................................................................................................................................................. 614
Section 120.1: RLMObject Base Model Class with Primary Key - Objective-C .................................................... 614
Chapter 121: ARC (Automatic Reference Counting) ................................................................................. 615
Section 121.1: Enable/Disable ARC on a file ............................................................................................................ 615
Chapter 122: Dynamic Type ................................................................................................................................. 616
Section 122.1: Matching Dynamic Type Font Size in WKWebView ....................................................................... 616
Section 122.2: Get the Current Content Size ........................................................................................................... 617
Section 122.3: Handling Preferred Text Size Change Without Notifications on iOS 10 ....................................... 617
Section 122.4: Text Size Change Notification .......................................................................................................... 617
Chapter 123: SWRevealViewController .......................................................................................................... 618
Section 123.1: Setting up a basic app with SWRevealViewController ................................................................... 618
Chapter 124: DispatchGroup ............................................................................................................................... 621
Section 124.1: Introduction ........................................................................................................................................ 621
Chapter 125: GCD (Grand Central Dispatch) ............................................................................................... 624
Section 125.1: Dispatch Semaphore ......................................................................................................................... 624
Section 125.2: Dispatch Group ................................................................................................................................. 624
Section 125.3: Getting the Main Queue .................................................................................................................... 625
Section 125.4: Create a dispatch queue .................................................................................................................. 626
Section 125.5: Serial vs Concurrent Dispatch Queues ........................................................................................... 626
Chapter 126: Size Classes and Adaptivity ..................................................................................................... 628
Section 126.1: Trait Collections ................................................................................................................................. 628
Section 126.2: Updating Auto Layout with Trait Collection Changes ................................................................... 628
Section 126.3: Supporting iOS Multitasking on iPad ............................................................................................... 629
Chapter 127: IBOutlets ............................................................................................................................................ 631
Section 127.1: Using an IBOutlet in a UI Element .................................................................................................... 631
Chapter 128: AWS SDK ............................................................................................................................................ 632
Section 128.1: Upload an image or a video to S3 using AWS SDK ....................................................................... 632
Chapter 129: Debugging Crashes ...................................................................................................................... 635
Section 129.1: Debugging EXC_BAD_ACCESS ........................................................................................................ 635
Section 129.2: Finding information about a crash ................................................................................................. 636
Section 129.3: Debugging SIGABRT and EXC_BAD_INSTRUCTION crashes ...................................................... 637
Chapter 130: CloudKit ............................................................................................................................................. 639
Section 130.1: Registering app for use with CloudKit ............................................................................................. 639
Section 130.2: Using CloudKit Dashboard ............................................................................................................... 639
Section 130.3: Saving data to CloudKit .................................................................................................................... 640
Chapter 131: GameplayKit .................................................................................................................................... 641
Section 131.1: Generating random numbers ............................................................................................................ 641
Section 131.2: GKEntity and GKComponent ............................................................................................................ 642
Chapter 132: Xcode Build & Archive From Command Line .................................................................. 645
Section 132.1: Build & Archive ................................................................................................................................... 645
Chapter 133: XCTest framework - Unit Testing ......................................................................................... 646
Section 133.1: Adding Test Files to Xcode Project ................................................................................................... 646
Section 133.2: Adding test methods ......................................................................................................................... 647
Section 133.3: Writing a test class ............................................................................................................................ 648
Section 133.4: Adding Storyboard and View Controller as instances to test file ................................................ 649
Section 133.5: Import a module that it can be tested ............................................................................................ 649
Section 133.6: Trigger view loading and appearance ............................................................................................ 649
Section 133.7: Start Testing ....................................................................................................................................... 650
Chapter 134: AVPlayer and AVPlayerViewController ............................................................................ 651
Section 134.1: Playing Media using AVPlayer and AVPlayerLayer ....................................................................... 651
Section 134.2: Playing Media Using AVPlayerViewController ............................................................................... 651
Section 134.3: AVPlayer Example ............................................................................................................................. 651
Chapter 135: Deep Linking in iOS ...................................................................................................................... 652
Section 135.1: Adding a URL scheme to your own app .......................................................................................... 652
Section 135.2: Opening an app based on its URL scheme .................................................................................... 653
Section 135.3: Setting up deeplink for your app ..................................................................................................... 654
Chapter 136: Core Graphics ................................................................................................................................. 656
Section 136.1: Creating a Core Graphics Context ................................................................................................... 656
Section 136.2: Presenting the Drawn Canvas to User ............................................................................................ 656
Chapter 137: Segues ................................................................................................................................................ 657
Section 137.1: Using Segues to navigate backwards in the navigation stack ..................................................... 657
Section 137.2: An Overview ....................................................................................................................................... 657
Section 137.3: Preparing your view controller before a triggering a Segue ........................................................ 658
Section 137.4: Deciding if an invoked Segue should be performed ..................................................................... 658
Section 137.5: Trigger Segue Programmatically .................................................................................................... 658
Chapter 138: EventKit ............................................................................................................................................. 660
Section 138.1: Accessing dierent types of calendars ........................................................................................... 660
Section 138.2: Requesting Permission ..................................................................................................................... 660
Section 138.3: Adding an event ................................................................................................................................ 661
Chapter 139: SiriKit ................................................................................................................................................... 663
Section 139.1: Adding Siri Extension to App ............................................................................................................. 663
Chapter 140: Contacts Framework ................................................................................................................. 665
Section 140.1: Adding a Contact ............................................................................................................................... 665
Section 140.2: Authorizing Contact Access ............................................................................................................. 665
Section 140.3: Accessing Contacts ........................................................................................................................... 666
Chapter 141: iOS 10 Speech Recognition API ............................................................................................... 667
Section 141.1: Speech to text: Recognize speech from a bundle contained audio recording ............................ 667
Chapter 142: StoreKit ............................................................................................................................................. 669
Section 142.1: Get localized product information from the App Store ................................................................. 669
Chapter 143: Code signing ................................................................................................................................... 670
Section 143.1: Provisioning Profiles ........................................................................................................................... 670
Chapter 144: Create .ipa File to upload on appstore with Applicationloader .......................... 671
Section 144.1: create .ipa file to upload app to appstore with Application Loader ............................................. 671
Chapter 145: Size Classes and Adaptivity .................................................................................................... 675
Section 145.1: Size Classes and Adaptivity through Storyboard ........................................................................... 675
Chapter 146: MKDistanceFormatter ............................................................................................................... 681
Section 146.1: String from distance .......................................................................................................................... 681
Section 146.2: Distance units .................................................................................................................................... 681
Section 146.3: Unit style ............................................................................................................................................. 681
Chapter 147: 3D Touch ........................................................................................................................................... 683
Section 147.1: 3D Touch with Swift ............................................................................................................................ 683
Section 147.2: 3 D Touch Objective-C Example ...................................................................................................... 684
Chapter 148: GameCenter Leaderboards .................................................................................................... 686
Section 148.1: GameCenter Leaderboards .............................................................................................................. 686
Chapter 149: Keychain ........................................................................................................................................... 688
Section 149.1: Adding a Password to the Keychain ................................................................................................ 688
Section 149.2: Keychain Access Control (TouchID with password fallback) ....................................................... 689
Section 149.3: Finding a Password in the Keychain ............................................................................................... 690
Section 149.4: Updating a Password in the Keychain ............................................................................................ 691
Section 149.5: Removing a Password from the Keychain ..................................................................................... 691
Section 149.6: Keychain Add, Update, Remove and Find operations using one file .......................................... 692
Chapter 150: Handle Multiple Environment using Macro ..................................................................... 695
Section 150.1: Handle multiple environment using multiple target and macro .................................................. 695
Chapter 151: Set View Background .................................................................................................................. 710
Section 151.1: Fill background Image of a UIView ................................................................................................... 710
Section 151.2: Creating a gradient background view ............................................................................................. 710
Section 151.3: Set View backround with image ....................................................................................................... 710
Section 151.4: Set View background ........................................................................................................................ 710
Chapter 152: Block .................................................................................................................................................... 712
Section 152.1: Custom completion block for Custom Methods ............................................................................. 712
Section 152.2: UIView Animations ............................................................................................................................ 712
Section 152.3: Modify captured variable ................................................................................................................. 712
Chapter 153: Content Hugging/Content Compression in Autolayout ........................................... 714
Section 153.1: Definition: Intrinsic Content Size ....................................................................................................... 714
Chapter 154: iOS Google Places API ................................................................................................................ 715
Section 154.1: Getting Nearby Places from Current Location ............................................................................... 715
Chapter 155: Navigation Bar ............................................................................................................................... 717
Section 155.1: SWIFT Example .................................................................................................................................. 717
Section 155.2: Customize default navigation bar appearance ............................................................................. 717
Chapter 156: App wide operations ................................................................................................................... 718
Section 156.1: Get the top most UIViewController .................................................................................................. 718
Section 156.2: Intercept System Events ................................................................................................................... 718
Chapter 157: CoreImage Filters ......................................................................................................................... 719
Section 157.1: Core Image Filter Example ................................................................................................................ 719
Chapter 158: Face Detection Using CoreImage/OpenCV .................................................................... 725
Section 158.1: Face and Feature Detection ............................................................................................................. 725
Chapter 159: MPMediaPickerDelegate ........................................................................................................... 728
Section 159.1: Load music with MPMediaPickerControllerDelegate and play it with AVAudioPlayer ............... 728
Chapter 160: Graph (Coreplot) ........................................................................................................................... 730
Section 160.1: Making graphs with CorePlot ........................................................................................................... 730
Chapter 161: FCM Messaging in Swift .............................................................................................................. 732
Section 161.1: Initialize FCM in Swift .......................................................................................................................... 732
Chapter 162: Create a Custom framework in iOS .................................................................................... 734
Section 162.1: Create Framework in Swift ............................................................................................................... 734
Chapter 163: Custom Keyboard ......................................................................................................................... 735
Section 163.1: Custom KeyBoard Example .............................................................................................................. 735
Chapter 164: AirDrop .............................................................................................................................................. 742
Section 164.1: AirDrop ................................................................................................................................................ 742
Chapter 165: SLComposeViewController ...................................................................................................... 743
Section 165.1: SLComposeViewController for Twitter, facebook, SinaWelbo and TencentWelbo .................... 743
Chapter 166: AirPrint tutorial in iOS ................................................................................................................. 745
Section 166.1: AirPrint printing Banner Text ............................................................................................................ 745
Chapter 167: Carthage iOS Setup ..................................................................................................................... 747
Section 167.1: Carthage Installation Mac ................................................................................................................. 747
Chapter 168: Healthkit ............................................................................................................................................ 748
Section 168.1: HealthKit ............................................................................................................................................. 748
Chapter 169: Core SpotLight in iOS .................................................................................................................. 751
Section 169.1: Core-Spotlight .................................................................................................................................... 751
Chapter 170: Core Motion ..................................................................................................................................... 753
Section 170.1: Accessing Barometer to get relative altitude ................................................................................. 753
Chapter 171: QR Code Scanner ........................................................................................................................... 754
Section 171.1: Scanning QR code with AVFoudation framework ........................................................................... 754
Section 171.2: UIViewController scanning for QR and displaying video input ..................................................... 755
Chapter 172: plist iOS .............................................................................................................................................. 757
Section 172.1: Example: .............................................................................................................................................. 757
Section 172.2: Save and edit/delete data from Plist .............................................................................................. 759
Chapter 173: WCSessionDelegate ..................................................................................................................... 761
Section 173.1: Watch kit controller (WKInterfaceController) ................................................................................. 761
Chapter 174: AppDelegate ................................................................................................................................... 762
Section 174.1: All States of Application through AppDelegate methods .............................................................. 762
Section 174.2: AppDelegate Roles: ........................................................................................................................... 763
Section 174.3: Opening a URL-Specified Resource ................................................................................................ 763
Section 174.4: Handling Local and Remote Notifications ...................................................................................... 763
Chapter 175: App Submission Process ........................................................................................................... 765
Section 175.1: Setup provisioning profiles ................................................................................................................ 765
Section 175.2: Archive the code ................................................................................................................................ 765
Section 175.3: Export IPA file ..................................................................................................................................... 765
Section 175.4: Upload IPA file using Application Loader ....................................................................................... 766
Chapter 176: FileHandle ......................................................................................................................................... 768
Section 176.1: Read file from document directory in chunks ................................................................................ 768
Chapter 177: Basic text file I/O .......................................................................................................................... 770
Section 177.1: Read and write from Documents folder .......................................................................................... 770
Chapter 178: iOS TTS ............................................................................................................................................... 772
Section 178.1: Text To Speech ................................................................................................................................... 772
Chapter 179: MPVolumeView .............................................................................................................................. 773
Section 179.1: Adding a MPVolumeView .................................................................................................................. 773
Chapter 180: Objective-C Associated Objects ............................................................................................ 774
Section 180.1: Basic Associated Object Example .................................................................................................... 774
Chapter 181: Passing Data between View Controllers (with MessageBox-Concept) .............. 775
Section 181.1: Simple Example Usage ...................................................................................................................... 775
Chapter 182: MVVM .................................................................................................................................................. 776
Section 182.1: MVVM Without Reactive Programming .......................................................................................... 776
Chapter 183: Cache online images ................................................................................................................... 779
Section 183.1: AlamofireImage ................................................................................................................................. 779
Chapter 184: Chain Blocks in a Queue (with MKBlockQueue) ............................................................ 780
Section 184.1: Example Code .................................................................................................................................... 780
Chapter 185: Simulator .......................................................................................................................................... 782
Section 185.1: Launching Simulator .......................................................................................................................... 782
Section 185.2: 3D / Force Touch simulation ........................................................................................................... 782
Section 185.3: Change Device Model ....................................................................................................................... 783
Section 185.4: Navigating Simulator ........................................................................................................................ 784
Chapter 186: Background Modes ...................................................................................................................... 785
Section 186.1: Turning on the Background Modes capability ............................................................................... 785
Section 186.2: Background Fetch ............................................................................................................................. 785
Section 186.3: Testing background fetch ................................................................................................................ 786
Section 186.4: Background Audio ............................................................................................................................ 788
Chapter 187: OpenGL .............................................................................................................................................. 789
Section 187.1: Example Project ................................................................................................................................. 789
Chapter 188: MVP Architecture .......................................................................................................................... 790
Section 188.1: Dog.swift ............................................................................................................................................. 790
Section 188.2: DoggyService.swift ........................................................................................................................... 790
Section 188.3: DoggyPresenter.swift ....................................................................................................................... 790
Section 188.4: DoggyView.swift ................................................................................................................................ 791
Section 188.5: DoggyListViewController.swift ......................................................................................................... 791
Chapter 189: Configure Beacons with CoreBluetooth ............................................................................ 793
Section 189.1: Showing names of all Bluetooth Low Energy (BLE) ....................................................................... 793
Section 189.2: Connect and read major value ....................................................................................................... 794
Section 189.3: Write major value .............................................................................................................................. 795
Chapter 190: Core Data ......................................................................................................................................... 797
Section 190.1: Operations on core data ................................................................................................................... 797
Chapter 191: Profile with Instruments ............................................................................................................. 798
Section 191.1: Time Profiler ........................................................................................................................................ 798
Chapter 192: Application rating/review request ...................................................................................... 807
Section 192.1: Rate/Review iOS Application ............................................................................................................ 807
Chapter 193: MyLayout .......................................................................................................................................... 808
Section 193.1: A Simple Demo to use MyLayout ..................................................................................................... 808
Chapter 194: Simulator Builds ............................................................................................................................ 810
Section 194.1: Installing the build manually on simulator ...................................................................................... 810
Chapter 195: Simulating Location Using GPX files iOS .......................................................................... 811
Section 195.1: Your .gpx file: MPS_HQ.gpx ............................................................................................................... 811
Section 195.2: To set this location: ........................................................................................................................... 811
Chapter 196: SqlCipher integration .................................................................................................................. 813
Section 196.1: Integration of code: ........................................................................................................................... 813
Chapter 197: Security .............................................................................................................................................. 814
Section 197.1: Securing Data in iTunes Backups ..................................................................................................... 814
Section 197.2: Transport Security using SSL ........................................................................................................... 815
Chapter 198: App Transport Security (ATS) ................................................................................................ 817
Section 198.1: Load all HTTP content ....................................................................................................................... 817
Section 198.2: Selectively load HTTP content ......................................................................................................... 817
Section 198.3: Endpoints require SSL ....................................................................................................................... 818
Chapter 199: Guideline to choose best iOS Architecture Patterns .................................................. 819
Section 199.1: MVP Patterns ...................................................................................................................................... 819
Section 199.2: MVVM Pattern ................................................................................................................................... 820
Section 199.3: VIPER Pattern .................................................................................................................................... 821
Section 199.4: MVC pattern ....................................................................................................................................... 822
Chapter 200: Multicast Delegates ................................................................................................................... 823
Section 200.1: Multicast delegates for any controls .............................................................................................. 823
Chapter 201: Using Image Aseets ..................................................................................................................... 827
Section 201.1: LaunchImage using Image Assets ................................................................................................... 827
Section 201.2: App Icon using Image Assets .......................................................................................................... 830
Chapter 202: Runtime in Objective-C ............................................................................................................. 835
Section 202.1: Using Associated Objects ................................................................................................................ 835
Chapter 203: ModelPresentationStyles ......................................................................................................... 837
Section 203.1: Exploring ModalPresentationStyle using Interface Builder .......................................................... 837
Chapter 204: CydiaSubstrate tweak .............................................................................................................. 846
Section 204.1: Create new tweak using Theos ....................................................................................................... 846
Chapter 205: Create a video from images .................................................................................................. 848
Section 205.1: Create Video from UIImages ........................................................................................................... 848
Chapter 206: Codable ............................................................................................................................................. 850
Section 206.1: Use of Codable with JSONEncoder and JSONDecoder in Swift 4 ............................................... 850
Chapter 207: Load images async ..................................................................................................................... 852
Section 207.1: Easiest way ........................................................................................................................................ 852
Section 207.2: Check that the cell is still visible after download .......................................................................... 852
Chapter 208: Adding a Swift Bridging Header .......................................................................................... 853
Section 208.1: How to create a Swift Bridging Header Manually ......................................................................... 853
Section 208.2: Xcode create automatically ............................................................................................................ 853
Chapter 209: Creating an App ID ...................................................................................................................... 855
Section 209.1: Creating In-App Purchase Products ............................................................................................... 855
Section 209.2: Creating a Sandbox User ................................................................................................................ 857
Chapter 210: Swift: Changing the rootViewController in AppDelegate to present main or
login/onboarding flow ........................................................................................................................................... 858
Section 210.1: Option 1: Swap the Root View Controller (Good) ............................................................................ 858
Section 210.2: Option 2: Present Alternative Flow Modally (Better) ..................................................................... 858
Credits ............................................................................................................................................................................ 860
You may also like ...................................................................................................................................................... 867
About
Please feel free to share this PDF with anyone for free,
latest version of this book can be downloaded from:
http://GoalKicker.com/iOSBook
This iOS® Developer Notes for Professionals book is compiled from Stack Overflow
Documentation, the content is written by the beautiful people at Stack Overflow.
Text content is released under Creative Commons BY-SA, see credits at the end
of this book whom contributed to the various chapters. Images may be copyright
of their respective owners unless otherwise specified
This is an unofficial free book created for educational purposes and is not
affiliated with official iOS® Developer group(s) or company(s) nor Stack
Overflow. All trademarks and registered trademarks are the property of their
respective company owners
1. Boot up your Mac and install Xcode from the App Store if it's not already installed.
(If you prefer not to use the App Store or have problems, you can also download Xcode from the Apple
Developer website, but make sure that you select the latest release version and not a beta version.)
Getting started with a playground: This was introduced with the Swift language and Xcode 6. It's an
interactive area which can be used to write small pieces of code to check runtime changes. It's a great
way for Swift learners to be introduced to new Swift features.
Create a new Xcode project: Choose this option, which creates a new project with default
configuration.
Check out an existing project: This is used to check out a project from a repository location, for
example, check out a project from SVN.
3. Select the second option Create a new Xcode project and Xcode will ask you to do some initial project
setup:
You can see that there are many different templates for your application. These templates are helpful to
boost your development; they are pre-built with some basic project setups like UI interfaces and class files.
1. Master-Detail Application:
This template contains a combined master and detail interface: the master contains objects which are
related to the detail interface. Selecting objects in the master will change the details interface. You can
see this kind UI in the Settings, Notes and Contacts applications on the iPad.
2. Page-Based Application:
This template is used to create the page-based application. Pages are different views held by one
container.
4. Tabbed Application:
This template creates tabs at the bottom part of an application. Each tab has a different UI and a
different navigation flow. You can see this template used in apps like Clock, iTunes Store, iBooks and
App Store.
5. Game:
This is a starting point for game development. You can go further with game technologies like
SceneKit, SpriteKit, OpenGL ES and Metal.
Click on Next and it will ask you for a location where you want to create project directory.
Click on Create and you will see the Xcode UI with an already defined project setup. You can see some
classes and Storyboard files.
At the top left of the window, check that a simulator is selected (e.g. "iPhone 6" as shown here) and then
press the triangular RUN button.
5. A new application will open—Simulator (this may take some time the first time you run it and you may need
to try twice if you see an error the first time). This application provides us with device simulation for created
applications. It almost looks like a real device! It contains some applications like a real device. You can
simulate orientations, location, shake gesture, memory warnings, In-Call Status bar, finger touch, lock,
reboot, home etc.
You will see a plain white application because we have not made any changes to the template yet.
So start your own. it’s a long run and there are lots of new opportunities waiting for you!
If you are not sure where to go next, try out Apple's 'Jump Right In' tutorial. You have already performed the first
few steps so are off to a head start.
When the Xcode welcome screen comes up, choose Create a new Xcode project. Alternatively, you could do File >
Write "HelloWorld" for the Product Name (or whatever you want really) and under Language, make sure Swift is
selected.
Universal means that your app will run on both the iPhone and iPad.
Use Core Data refers to persistent data storage, which is not needed in our Hello World app.
We will not be doing Unit Tests or UI Tests in this example, but it doesn't hurt to get into the habit of adding
them.
Adding a label
Make sure the label is selected on the storyboard and then in the Attributes Inspector, change the text to "Hello,
World!" You will then have to resize and reposition the label on the storyboard since the text length is longer now.
Alternatively, double-click the label on the storyboard to edit it to be "Hello, World!". At any rate, the storyboard
should look something like this:
Adding Code
Add print("Successfully created my first iOS application.") to the viewDidLoad() method. It should look
something like this.
import UIKit
Press the Run button to build and run the app. In this example the current simulator device (referred to as a
"scheme") defaulted to the iPhone 6s Plus. Newer versions of Xcode will default to newer schemes. You can also
choose other schemes by clicking the name. We will just stick with the default.
The simulator will take some time to start on the first run. Once running, it should look like this:
In the simulator menu, you can choose Window > Scale to make it smaller, or press ?cmd + 1/2/3/4/5 for 100% /
The Xcode debug area (at the bottom) should have also printed "Successfully created my first iOS application." to
the console. "Successfully created my first iOS application." message is the string you printed programmatically in
the Add code part.
Going on
You should learn about Auto Layout constraints next. These help you to position your controls on the storyboard so
that they look good on any device size and orientation.
The workspace window always includes the editor area. When you select a file in your project, its contents appear in
the editor area, where Xcode opens the file in an appropriate editor. For example, in the image above, the editor
area MainViewController.swift, a swift code file that is selected in the Navigator area on the left of the workspace
Navigator Area
Project navigator. Add, delete, group, and otherwise manage files in your project, or choose a file to view or
edit its contents in the editor area.
Symbol navigator. Browse the symbols in your project as a list or hierarchy. Buttons on the left of the filter
bar let you limit the shown symbols to a combination of only classes and protocols, only symbols in your
project, or only containers.
Find navigator Use search options and filters to quickly find any string within your project.
Issue navigator. View issues such as diagnostics, warnings, and errors found when opening, analyzing, and
building your project.
Test navigator. Create, manage, run, and review unit tests.
Debug navigator. Examine the running threads and associated stack information at a specified point or time
during program execution.
Breakpoint navigator. Fine-tune breakpoints by specifying characteristics such as triggering conditions.
Report navigator. View the history of your build, run, debug, continuous integration, and source control
tasks.
The Editors
Most development work in Xcode occurs in the editor area, the main area that is always visible within the
workspace window. The editors you use most often are:
Standard Editor. Fills the editor area with the contents of the selected file.
Assistant Editor. Presents a separate editor pane with content logically related to content in the standard
editor pane. You can also change the content.
Version Editor. Shows the differences between the selected file in one pane and another version of that
same file in a second pane. This editor works only when your project is under source control.
The utilities area on the far right of the workspace window gives you quick access to these resources: Inspectors, for
viewing and modifying characteristics of the file open in an editor Libraries of ready-made resources for use in your
project
The top panel of the utilities area displays inspectors. The bottom pane gives you access to libraries.
File inspector. View and manage metadata for the selected file. Typically you will localize storyboards and
other media files and change settings for user interface files.
Quick Help. View details about a symbol, an interface element, or a build setting in the file. For example,
Quick Help displays a concise description of a method, where and how the method is declared, its scope, the
parameters it takes, and its platform and architecture availability.
File templates. Templates for common types of files and code constructs.
Code snippets. Short pieces of source code for use in your software, such as class declarations, control
flows, block declarations, and templates for commonly used Apple technologies.
Objects. Items for your app’s user interface.
Media. Files containing graphics, icons, sound files, and the like.
To use a library, drag it directly to the appropriate area. For example, to use a code snippet, drag it from
the library to the source editor; to create a source file from a file template, drag its template to the project
navigator.
To restrict the items displayed in a selected library, type relevant text into the text field in the Filter bar (the bottom
pane). For example, type “button” in the text field to show all the buttons in the Objects library.
The toolbar at the top of the workspace window provides quick access to frequently used commands. The Run
button builds and runs your products. The Stop button terminates your running code. The Scheme menu lets you
configure the products you want to build and run. The activity viewer shows the progress of tasks currently
executing by displaying status messages, build progress, and other information about your project.
The editor configuration buttons (the first group of three buttons) let you configure the editor area, and the
workspace configuration buttons (the second group of three buttons) hide or show the optional navigator,
debug, and utilities areas.
Xcode 8.2 has new Swift 3 language features with new iOS 10 compatible APi's.
Then choose Create new Project and after that you will see next screen
1. iOS
2. watchOS
3. macOS
4. Cross-platform
Now we are choosing iOS platform for development and creating very basic project with the single view application
option:
Application name you can change later as per your requirements. Then we need to click "Create" and
after that your screen will look like this one below:
Inside this class you can see the file name is ViewController.swift and inside the class the name is also
ViewController which is inheritance by the UIViewController super class and finally we're creating our first variable
which name is myString of the type 'String'. Add the following under 'super.viewDidLoad()'
We are going to print the content of this variable. First, select your simulator type at the top left hand side of the
screen and then click on the "Run" button.
When you know the exact dimensions you want to set for your label, you can initialize a UILabel with a CGRect
frame.
Swift
let frame = CGRect(x: 0, y: 0, width: 200, height: 21)
let label = UILabel(frame: frame)
view.addSubview(label)
Objective-C
CGRect frame = CGRectMake(0, 0, 200, 21);
UILabel *label = [[UILabel alloc] initWithFrame:frame];
[view addSubview:label];
You can add constraints on a UILabel when you want iOS to dynamically calculate its frame at runtime.
Swift
let label = UILabel()
label.backgroundColor = .red
label.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(label)
NSLayoutConstraint.activate([
//stick the top of the label to the top of its superview:
label.topAnchor.constraint(equalTo: view.topAnchor)
Objective-C
UILabel *label = [[UILabel alloc] init];
views:@{@"labelName":label}]];
// vertical constraints that will use the height of the superView with no padding on top and
bottom
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[labelName]|"
options:0
metrics:nil
views:@{@"labelName":label}]]
After the label has been created, be sure to set the dimensions via Auto Layout. Xcode will display errors if it is done
improperly.
You also use Interface Builder to add a UILabel to your Storyboard or .xib file by dragging a Label from the Object
Library panel and dropping it into a view in the canvas:
Instead of specifying a frame (position and size) for a UILabel programmatically, a Storyboard or a .xib lets you
use Auto Layout to add constraints to the control.
In order to access this label created from storyboard or xib create an IBOutlet of this label.
Once you have added a UILabel to your Storyboard or .xib the file you can link it to your code by pressing Control
? and then dragging the mouse between the UILabel to your ViewController, or you could drag to the code while
right clicking for it to have the same effect.
Swift
@IBOutlet weak var nameLabel : UILabel!
Objective-C
@property (nonatomic, weak) IBOutlet UILabel *nameLabel;
Swift
label.numberOfLines = 2
Objective-C
label.numberOfLines = 2;
Note
It is possible to set this property to 0. However, this doesn't mean that it won't accept any lines, instead it
means that the label can have as many lines as needed (aka "Infinity"):
Swift
label.numberOfLines = 0
Objective-C
label.numberOfLines = 0;
If the label has a height constraint, the constraint will be respected. In this case, label.numberOfLines =
0 may not work as expected.
Note
Instead of setting numberOfLines programmatically, you can use a Storyboard or a .xib and set the numberOfLines
property. That way, we achieve the same results as the above code.
Like as below:
Objective-C
UILabel *label = [[UILabel alloc] init];
or
UILabel *label = [UILabel new]; // convenience method for calling alloc-init
Swift 3
label.font = UIFont.systemFont(ofSize: 17)
Objective-C
label.font = [UIFont systemFontOfSize:17];
Swift3
label.font = UIFont.systemFont(ofSize: 17, weight: UIFontWeightBold)
Objective-C
Swift3
label.font = UIFont.boldSystemFont(ofSize: 17)
Objective-C
label.font = [UIFont boldSystemFontOfSize:17];
The font and point size will be based on the user's preferred reading size.
Swift
label.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody)
Swift 3
label.font = UIFont.preferredFont(forTextStyle: .body)
Objective-C
label.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
Objective-C
label.font = [UIFont fontWithName:@"Avenir" size:15];
A way to set the font size without knowing the font family is to use the font property of the UILabel.
Swift
label.font = label.font.fontWithSize(15)
Swift 3
label.font = label.font.withSize(15)
Objective-C
label.font = [label.font fontWithSize:15];
Swift
label.textColor = UIColor.redColor()
label.textColor = UIColor(red: 64.0/255.0, green: 88.0/255.0, blue: 41.0/225.0, alpha: 1)
Swift 3
label.textColor = UIColor.red
Objective-C
You can also vary the text color (or other attributes) of portions of the text by using NSAttributedString:
Objective-C
Swift
label.backgroundColor = UIColor.redColor()
label.backgroundColor = .redColor()
Swift 3
label.backgroundColor = UIColor.red
Objective-C
To make the changes easily visible, change the backgroundColor and textColor of labelOne in the viewDidLoad
method:
The function sizeToFit is used when you want to automatically resize a label based on the content stored within it.
labelOne.backgroundColor = UIColor.blueColor()
labelOne.textColor = UIColor.whiteColor()
labelOne.text = "Hello, World!"
labelOne.sizeToFit()
Swift 3
labelOne.backgroundColor = UIColor.blue
labelOne.textColor = UIColor.white
labelOne.text = "Hello, World!"
labelOne.sizeToFit()
Objective-C
As you can see, there is no change as the text is perfectly fitting in labelOne. sizeToFit only changes the label’s
frame.
// Objective-C
labelOne.numberOfLines = 0;
// Swift
labelOne.numberOfLines = 0
label.textAlignment = NSTextAlignment.left
//or the shorter
label.textAlignment = .left
Any value in the NSTextAlignment enum is valid: .left, .center, .right, .justified, .natural
Objective-C
label.textAlignment = NSTextAlignmentLeft;
Vertical alignment in UILabel is not supported out of the box: Vertically align text to top within a UILabel
attributes is an NSDictionary of attributes that effect attributed strings (full list: Apple Docs) but the factors that
effect height include:
NSFontAttributeName: Very important, the size and font family is a critical part of the label's displayed size.
NSParagraphStyleAttributeName: For customizing how the text is displayed. This includes line spacing,
text alignment, truncation style, and a few other options. If you did not explicitly change any of these values
you should not have to worry about this much, but may be important if you toggled some values on IB.
context should be nil since the primary NSStringDrawingContext use case is for allowing font to resize to fit a
specified rect, which shouldn't be the case if we're calculating a dynamic height.
Objective C
// The NSParagraphStyle, even if you did not code any changes these values may have been
altered in IB
NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
paragraphStyle.alignment = NSTextAlignmentCenter;
Swfit 3
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var cell = tableView.cellForRow(atIndexPath: indexPath)!
var labelContent = cell.theLabel.text
var labelFont = cell.theLabel.font
var paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineBreakMode = .byWordWrapping
Conversely, if you do have a set maximum number of lines you will first need calculate the height of a single line to
make sure we don't get a value taller than the allowed size:
Step 1
Select the Label and change the label type Plain to Attributed
Step 3
Then font view will show up and click underline button to make text underline or click strikethrough button to make
the text strikethrough.And select single line or double line.
Get the Font view as the above described and click the effects button.
NOTE: In most cases, it is better to use a UIButton instead of making a UILabel you can tap on. Only use
this example, if you are sure, that you don't want to use a UIButton for some reason.
1. Create label
2. Enable user interaction
3. Add UITapGestureRecognizer
Swift
let label = UILabel()
Objective-C
UILabel *label = [[UILabel alloc] init];
[label setUserInteractionEnabled:YES];
Instead of using code, you can select the UILabel inside the storyboard and check the option:
You need to set the numberOfLines to zero (0), and add a minimal height by setting up a constraints with a relation
of type .GreaterThanOrEqual on the .Height attribute
Version ≥ iOS 6
Swift
label.numberOfLines = 0
label.addConstraint(heightConstraint)
Version ≥ iOS 9
Swift
label.numberOfLines = 0
label.translatesAutoresizingMaskIntoConstraints = false
label.heightAnchor.constraintGreaterThanOrEqualToConstant(20).active = true
.ByWordWrapping
.ByCharWrapping
.ByClipping
.ByTruncatingHead
.ByTruncatingTail
.ByTruncatingMiddle
Swift 3
label.lineBreakMode = .byTruncatingTail
.byWordWrapping
.byCharWrapping
.byClipping
.byTruncatingHead
.byTruncatingTail
.byTruncatingMiddle
Objective-C
[label setLineBreakMode:NSLineBreakByTruncatingTail];
NSLineBreakByWordWrapping
NSLineBreakByCharWrapping
NSLineBreakByClipping
NSLineBreakByTruncatingHead
NSLineBreakByTruncatingTail
NSLineBreakByTruncatingMiddle
Using storyboard
Constants
Swift 3
Objective-C
Swift
Objective-C
// Dot Notation
label.text = @"the new text";
// Message Pattern
Swift
Objective-C
// Dot Notation
label.text = stringVar;
// Message Pattern
[label setText: stringVar];
Just use auto layout to add constraints to pin the left and top sides of the label.
Notes
Don't add constraints for the width and height. Labels have an intrinsic size based on their text content.
import UIKit
class ViewController: UIViewController {
This method can also be used to correctly space multiple labels horizontally as in this example.
If you want your label to line wrap then set the number of lines to 0 in IB and add
myLabel.preferredMaxLayoutWidth = 150 // or whatever in code. (The button is also pinned to the
bottom of the label so that it will move down when the label height increased.)
Section 2.16: Get UILabel's size strictly based on its text and
font
NSString provides method boundingRectWithSize which can be used to predict the resulting CGSize of a UILabel
based on its text and font without the need of creating a UILabel
Objective-C
Swift
Swift
Create Label and label Height constraint outlet. Add below code where you will asign text to label.
Swift
Swift 3
let sampleText = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in
voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
// Create label
let label = UILabel(frame: CGRectMake(0, 0, view.frame.size.width, 400))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.ByWordWrapping
Objective-C
NSString *sampleText = @"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
// Create label
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width,
400)];
label.numberOfLines = 0;
label.lineBreakMode = NSLineBreakByWordWrapping;
Objective-C
UILabel * label = [[UILabel alloc] init];
label.numberOfLines = 0;
CGSize maximumLabelSize = CGSizeMake(280, 9999); //280:max width of label and 9999-max height of
label.
Swift
var message: String = "Some dynamic text for label"
//set the text and style if any.
label.text = message
label.numberOfLines = 0
var maximumLabelSize: CGSize = CGSize(width: 280, height: 9999)
var expectedLabelSize: CGSize = label.sizeThatFits(maximumLabelSize)
// create a frame that is filled with the UILabel frame data
var newFrame: CGRect = label.frame
// resizing the frame to calculated size
newFrame.size.height = expectedLabelSize.height
// put calculated frame into UILabel frame
label.frame = newFrame
You can add HTML text in UILabel using attributedText property or customized single UILabel text with different
property
Output :
Swift
Objective C
Swift
Objective C
Objective-C
-(void) someButtonAction{
NSLog(@"Button is tapped");
Swift
func someButtonAction() {
Now to add this action method to your button, you have to write following line of code:
Objective C
Swift
Objective C
Objective C
[self.button setImage:[UIImage imageNamed:@"test-image"] forState:UIControlStateNormal];
You can also set an image for multiple UIControlStates, for example to set the same image for the Selected and
Highlighted state:
Swift
button.setImage(UIImage(named:"test-image"), forState:[.selected, .highlighted])
Objective C
[self.button setImage:[UIImage imageNamed:@"test-image"]
forState:UIControlStateSelected|UIControlStateHighlighted];
Section 5.5: Get UIButton's size strictly based on its text and
font
To get the the exact size of a UIButton's text based on its font, use the function intrinsicContentSize.
Swift
button.intrinsicContentSize.width
button.intrinsicContentSize.width;
Swift
myButton.isEnabled = false
Objective-C:
myButton.enabled = NO;
If you don't want the button appearance to change when disabled set adjustsImageWhenDisabled to false / NO
Objective C
Swift
Objective C
//Objective-C
[button setTitleColor:(nullable UIColor *) forState:(UIControlState)];
//Swift
button.setTitleColor(.blue, for: .normal)
//Objective-C
[button setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]
Objective C
Swift
Objective C
This can be used to set the font of the title label, for example
Swift
button.titleLabel?.font = UIFont.boldSystemFontOfSize(12)
Objective-C
-(void)someButtonAction:(id)sender {
// sender is the object that was tapped, in this case its the button.
NSLog(@"Button is tapped");
}
Swift
func someButtonAction() {
print("Button is tapped")
}
Now to add this action method to your button, you have to write following line of code:
Objective C
Swift
Objective-C
UIDatePicker *datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(x: 0, y: 0, width: 320,
height: 200)];
Minimum date
[datePicker setMinimumDate:[NSDate date]];
Maximum date
[datePicker setMaximumDate:[NSDate date]];
Time - The date picker displays hours, minutes, and (optionally) an AM/PM designation.
Date - The date picker displays months, days of the month, and years.
DateAndTime - The date picker displays dates (as unified day of the week, month, and day of the month
values) plus hours, minutes, and (optionally) an AM/PM designation.
CountDownTimer - The date picker displays hour and minute values, for example [ 1 | 53 ]. The application
must set a timer to fire at the proper interval and set the date picker as the seconds tick down.
Unlike remote notifications which are triggered from a server, local notifications are scheduled and triggered within
an app. Notifications in general are targeted to increase user interaction with the app, inviting or tempting the user
to open and interact with it.
UILocalNotification was deprecated in iOS 10. Use the UserNotifications framework instead.
Swift
Objective-C
To see the notification in the iOS Simulator, type ^?H (control-command-H) to go home and then type ?L (command-
L) to lock the device. Wait a few seconds, and the notification should appear (this appearance will vary depending
on notification type discussed in "Registering for local notifications"):
Swipe on the notification to get back to the app (note that if you called this in the first view controller's viewDidLoad,
viewWillAppear, viewDidAppear, etc., the notification will be scheduled again).
Swift 3
UIApplication.shared.presentLocalNotificationNow(notification)
UIApplication.sharedApplication().presentLocalNotificationNow(notification)
Objective-C
An advantage of using this is so you won't have to set the fireDate and timeZone properties of your
UILocalNotification object.
Track a notification
You can assign a UUID (universally unique identifier) to a notification, so you can track it:
Swift
Objective-C
Cancel a notification
To cancel a notification, we first get a list of all the notifications and then find the one with a matching UUID. Finally,
we cancel it.
Swift
Objective-C
You would probably want to store all of these UUID's in Core Data or Realm.
In order to present local notifications to the user, you have to register your app with the device:
Swift
Objective-C
Regardless of what the user chooses, the alert will not show up again and changes will have to be initiated by the
user in Settings.
New Features:
1. Now you can either present alert, sound or increase badge while the app is in foreground too with iOS 10
2. Now you can handle all event in one place when user tapped (or slided) the action button, even while the app
has already been killed.
3. Support 3D touch instead of sliding gesture.
4. Now you can remove specifical local notification just by one row code.
5. Support Rich Notification with custom UI.
It is really easy for us to convert UILocalNotification APIs to iOS10 User Notifications framework APIs, they are
really similar.
I write a Demo here to show how to use new and old APIs at the same time: iOS10AdaptationTips .
For example,
1. import UserNotifications
3. schedule localNotification
Objective-C implementation:
1. import UserNotifications
3. schedule localNotification
Swift
Objective-C
This method is generally overridden in the AppDelegate, which conforms to the UIApplicationDelegate protocol.
in AppDelegate
import UserNotifications
in didFinishLaunchingWithOptions method,
UNUserNotificationCenter.current().requestAuthorization(options: [.alert,.sound,.badge]) {
(granted, error) in
Where ever this part of code is triggered, If you have allowed Notification Permission, you will receive an
notification.
Objective-C
UIImage *image = [UIImage imageNamed:@"imageFromBundleOrAsset"];
Note
The method imageNamed caches the image's contents to memory. Loading many large images that way
can cause low memory warnings which can lead the app to be terminated. This can be fixed by utilising
the method imageWithContentsOfFile of UIImage, which doesn't use caching.
With NSData
Swift
let imageData = Data(base64Encoded: imageString, options:
Data.Base64DecodingOptions.ignoreUnknownCharacters)
With UIColor
Swift
let color = UIColor.red
let size = CGSize(width: 200, height: 200)
Objective-C
UIColor *color=[UIColor redColor];
CGRect frame = CGRectMake(0, 0, 80, 100);
UIGraphicsBeginImageContext(frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, frame);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Example:
Using Array:
Example:
self.myImageView.animationImages = imageArray;
The isEqual: method is the only reliable way to determine whether two images contain the same image
data. The image objects you create may be different from each other, even when you initialize them with
the same cached image data. The only way to determine their equality is to use the isEqual: method,
which compares the actual image data. Listing 1 illustrates the correct and incorrect ways to compare
images.
Swift
// Load the same image twice.
let image1 = UIImage(named: "MyImage")
let image2 = UIImage(named: "MyImage")
// The image objects may be different, but the contents are still equal
if let image1 = image1, image1.isEqual(image2) {
// Correct. This technique compares the image data correctly.
}
if image1 == image2 {
// Incorrect! Direct object comparisons may not work.
}
Objective-C
// Load the same image twice.
UIImage* image1 = [UIImage imageNamed:@"MyImage"];
UIImage* image2 = [UIImage imageNamed:@"MyImage"];
// The image objects may be different, but the contents are still equal
if ([image1 isEqual:image2]) {
// Correct. This technique compares the image data correctly.
}
if (image1 == image2) {
// Incorrect! Direct object comparisons may not work.
}
Swift:
extension UIImage {
static func gradientImageWithBounds(bounds: CGRect, colors: [CGColor]) -> UIImage {
let gradientLayer = CAGradientLayer()
gradientLayer.frame = bounds
gradientLayer.colors = colors
UIGraphicsBeginImageContext(gradientLayer.bounds.size)
gradientLayer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
}
Usage:
Objective-C:
UIGraphicsBeginImageContext(gradientLayer.bounds.size);
[gradientLayer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
Decoding
extension UIImage {
func maskWithColor(color: UIColor) -> UIImage? {
//is it nil?
if let cImage = CGBitmapContextCreateImage(bitmapContext) {
let coloredImage = UIImage(CGImage: cImage)
return coloredImage
} else {
return nil
}
}
}
my_image.maskWithColor(UIColor.blueColor())
Now lets say you want to do same with UIImageView then use following code
Example:
Using Array:
Example
// draw in context
[text drawAtPoint:CGPointMake(0.0, 0.0)];
// transfer image
UIImage *image = [UIGraphicsGetImageFromCurrentImageContext()
imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
UIGraphicsEndImageContext();
return image;
}
//Swift
class ImageUploadViewController: UIViewController, UIImagePickerControllerDelegate,
UINavigationControllerDelegate {
//Objective-C
@interface ImageUploadViewController : UIViewController
<UIImagePickerControllerDelegate,UINavigationControllerDelegate> {
UIImagePickerController *imagePickerController;
@end
@implementation ImageUploadViewController
- (void)viewDidLoad {
[super viewDidLoad];
imagePickerController.delegate = self;
@end
//Swift
self.imagePickerController.sourceType = .Camera // options: .Camera , .PhotoLibrary ,
.SavedPhotosAlbum
self.presentViewController(self.imagePickerController, animated: true, completion: nil)
//Swift
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info:
[String : AnyObject]) {
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
// Your have pickedImage now, do your logic here
}
self.dismissViewControllerAnimated(true, completion: nil)
}
//Objective-C
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info {
if (pickedImage) {
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
Objective-C
self.maskImage.layer.mask = self.maskLabel.layer;
self.maskImage.layer.masksToBounds = YES;
Swift 3
maskImageView.mask = maskLabel
maskImageView.masksToBounds = true
Swift
someImageView.layer.cornerRadius = someImageView.frame.height/2
// this should alleviate the performance hit that adding transparency may cause - see
http://stackoverflow.com/a/6254531/189804
// Be sure to check scrolling performance with Instruments if you take this approach.
someImageView.layer.shouldRasterize = true
someImageView.clipsToBounds = true // All parts of the image that are outside its bounds (the
frame) are cut out (makes the rounded corners visible)
It is suggested that if you use autolayout that you put the someImageView.layer.cornerRadius code in
viewDidLayoutSubviews. This will allow the image's cornerRadius to update if the image changes size.
Let's use two image views to see how the various modes work.
The image heights and widths are stretched to match the size of the UIImageView.
Aspect Fit
The longest side (either height or width) of the image is stretched to match the view. This makes the image as big as
possible while still showing the entire image and not distorting the height or width. (I set the UIImageView
background to blue so that its size is clear.)
Aspect Fill
Redraw
Redraw is only for custom views that need to do their own scaling and resizing. We aren't using a custom view, so
we shouldn't use Redraw. Notice that here UIImageView just gives us the same result as Scale to Fill, but it is doing
more work behind the scenes.
Content modes are good for recycling the contents of your view, but you can also set the content mode to
the UIViewContentModeRedraw value when you specifically want your custom views to redraw themselves
during scaling and resizing operations. Setting your view’s content mode to this value forces the system
to call your view’s drawRect: method in response to geometry changes. In general, you should avoid
using this value whenever possible, and you should certainly not use it with the standard system views.
Center
Top
The top edge of the image is centered horizontally at the top of the view, and the length and width of the image are
not stretched.
Bottom
The bottom edge of the image is centered horizontally at the bottom of the view, and the length and width of the
image are not stretched.
Left
Right
The right edge of the image is centered vertically at the right of the view, and the length and width of the image are
not stretched.
Top Left
The top left corner of the image is placed at the top left corner of the view. The length and width of the image are
not stretched.
Top Right
Bottom Left
The bottom left corner of the image is placed at the bottom left corner of the view. The length and width of the
image are not stretched.
Bottom Right
The bottom right corner of the image is placed at the bottom right corner of the view. The length and width of the
image are not stretched.
Notes
See this and this question for a discussion about content modes for views other than UIImageView.
In Swift, to set to set the content mode programmatically you do the following:
imageView.contentMode = UIViewContentMode.scaleToFill
imageView.contentMode = UIViewContentMode.scaleAspectFit
imageView.contentMode = UIViewContentMode.scaleAspectFill
imageView.contentMode = UIViewContentMode.redraw
imageView.contentMode = UIViewContentMode.center
imageView.contentMode = UIViewContentMode.top
imageView.contentMode = UIViewContentMode.bottom
imageView.contentMode = UIViewContentMode.left
imageView.contentMode = UIViewContentMode.right
imageView.contentMode = UIViewContentMode.topLeft
imageView.contentMode = UIViewContentMode.topRight
imageView.contentMode = UIViewContentMode.bottomLeft
imageView.contentMode = UIViewContentMode.bottomRight
The animationImages property is an Array of UIImages that is run through from top to bottom when the animation
is triggered.
The animationDuration property is a Double saying how many seconds the animation will run for.
The animationRepeatCount property is an Int that says how many times the animation will run.
To start and stop the animation, you can call the appropriate methods to do so:
imageView.startAnimating()
imageView.stopAnimating()
There is method isAnimating() which returns a Boolean value indicating whether the animation is running at a
moment or not.
Please note that this's not a very efficient way to create animations: it's quite slow and resource-consuming.
Consider using Layers or Sprites for better results
//Swift
let imageView = UIImageView()
//Objective-C
UIImageView *imageView = [[UIImageView alloc] init];
You can set the size and position of the UIImageView with a CGRect:
//Swift
imageView.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
//Objective-C
imageView.frame = CGRectMake(0,0,200,200);
//Swift
UIImageView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
//Objective-C
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,200,200);
//Swift 3
imageView.tintColor = UIColor.red
imageView.image = imageView.image?.withRenderingMode(.alwaysTemplate)
//Objective-C
imageView.tintColor = [UIColor redColor];
imageView.image = [imageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]
//Swift
//Objective-C
[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"image1"];
The code in the viewDidLoad or loadView should look something look something like this
- (void)loadView
{
[super loadView];
UIImageView *imageView=[[UIImageView alloc]initWithFrame:CGRectMake(0, 50, 320, 320)];
[self.view addSubview:imageView];
UIImage *image=[UIImage imageNamed:@"Dubai-Photos-Images-Travel-Tourist-Images-
Pictures-800x600.jpg"];
imageView.image=[self circularScaleAndCropImage:[UIImage imageNamed:@"Dubai-Photos-Images-Travel-
Tourist-Images-Pictures-800x600.jpg"] frame:CGRectMake(0, 0, 320, 320)];
}
Finally the function which does the heavy lifting circularScaleAndCropImage is as defined below
- (UIImage*)circularScaleAndCropImage:(UIImage*)image frame:(CGRect)frame {
// This function returns a newImage, based on image, that has been:
// - scaled to fit in (CGRect) rect
// - and cropped within a circle of radius: rectWidth/2
return newImage;
}
Finally the function which does the heavy lifting circularScaleAndCropImage is as defined below
When you create a self-sizing table view cell, you need to set this property and use constraints to define
the cell’s size.
self.tableView.estimatedRowHeight = 44.0
Note that the tableView's delegate's heightForRowAtIndexPath is unnecessary if you want to have a dynamic height
for all cells. Simply set the above property when necessary and before reloading or loading the table view. However,
you can set specific cells' height while having others dynamic via the following function:
Swift
Objective-C
This section covers the basics, and hopefully will be expanded to detail more complex processes like those
described above.
First, create a new subclass of UITableViewCell (create a new Cocoa Touch Class in Xcode and set
UITableViewCell as the superclass). Below is what your code may look like after subclassing.
Swift
Optionally, check 'Also create a XIB file' when creating your new file to customize using Interface Builder. In the case
that you do, connect customLabel as an @IBOutlet
In a UIViewController containing the tableView, register the new custom cell's class (see below). Note, this is only
necessary if you do not design the cell with a Storyboard in your table view's interface.
Swift
Swift
// Register Nib
tableView.register(UINib(nibName: CustomTableViewCell.identifier, bundle: nil),
forCellReuseIdentifier: CustomTableViewCell.identifier)
Swift
// This is where the magic happens - setting a custom property on your very own cell
cell.customLabel.text = "My Custom Cell"
return cell
}
You can set make your table view's separator lines extend the to various widths across the table by changing the
layoutMargins: property on your cell(s). This can be achieved in a number of ways.
In either your table view data source's cellForRowAtIndexPath: method or the willDisplayCell: method, set the
cell's layoutMargins: property to UIEdgeInsetsZero (extends to full width of the table), or to whatever you may
desire here.
Objective-C
[cell setLayoutMargins:UIEdgeInsetsZero];
Swift
The thin gray lines between each cell may not be exactly the look you're going for. It's fairly straightforward to hide
them from view.
In your encompassing UIViewController's viewDidLoad: method add the following code. You may also set this
Swift:
tableView.separatorStyle = .None
Objective-C:
tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
Alternatively, the property can be changed in your Storyboard or XIB by selecting your tableView and setting
separator (under the attributes inspector) to None.
You can hide the UITableViewCell separator lines for empty cells by setting an empty footer view at the bottom of
a UITableView:
Swift
tableView.tableFooterView = UIView()
Objective-C
UITableViewDataSource
Required Methods
numberOfRowsInSection: This method defines how many cells will be displayed in each section of the
tableview.
Objective-C
Swift 3
cellForRowAtIndexPath: This method is where the UITableView's cells are created and configured.
Should return either a UITableViewCell or a custom subclass.
Note: Using dequeueReusableCellWithIdentifier:forIndexPath: requires that the class or nib has been
registered for that identifier using the UITableView's registerClass:forCellReuseIdentifier: or
registerNib:forCellReuseIdentifier: methods. Usually, this will be done in the UIViewController's
viewDidLoad method.
Objective-C
return cell;
}
Swift 3
return cell
}
Optional Methods
titleForHeaderInSection: Defines a string as the title for each section header in the table view. This
method only allows for changing the title, further customization can be done by defining the view for the
header.
Objective-C
case 1:
return @"Title 2";
break;
default:
return nil;
break;
}
}
Swift 3
titleForFooterInSection: Defines a string as the title for each section header in the table view.
Objective-C
Swift 3
canEditRowAtIndexPath: Used to determine if the editing UI should be displayed for the specified row.
Should return YES if the specified row can be deleted or added.
Objective-C
Swift 3
Objective-C
- (void)tableView:(UITableView *)tableView
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath
*)indexPath {
switch (editingStyle) {
case UITableViewCellEditingStyleInsert:
// Insert new data into the backing data model here
[self insertNewDataIntoDataModel];
[tableView insertRowsAtIndexPaths:@[indexPath]
withRowAnimation:UITableViewRowAnimationAutomatic];
break;
case UITableViewCellEditingStyleDelete:
[self removeDataFromDataModelAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:@[indexPath]
withRowAnimation:UITableViewRowAnimationAutomatic];
break;
default:
// Nothing to perform if the editingStyle was neither Insert or Delete
break;
}
}
Swift 3
editActions:forRowAt Allows ability to add aditional actions or buttons to the edit mode of a row inside
a UITableview. For example if you wanted two buttons, an edit and delete button when user swipes to
edit the row, then you would use this method.
Swift 3
UITableViewDelegate
All methods in UITableViewDelegate are optional, but a delegate that implements them will enable extra features
for the UITableView.
Objective-C
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.numSections;
}
Swift 3
viewForHeaderInSection Allows the configuration of a custom view as the header for the section.
Objective-C
switch (section) {
case 1: {
label.text = @"Title";
label.frame = labelFrame;
default:
label.frame = CGRectMake(0, 0, 0, 0);
break;
}
[view addSubview:label];
return view;
}
Swift 3
switch section {
case 1:
label.text = "Title"
label.frame = labelFrame
default:
label.frame = CGRect.zero
}
view.addSubview(label)
return view;
}
Objective-C
Swift 3
Objective-C
Swift 3
Although there are a number of ways to create a UITableView, one of the easiest is to add one to a Storyboard.
Open your Storyboard and drag a UITableView onto your UIViewController. Make sure to use Auto Layout to
correctly align the table (pin all four sides).
In order to display content dynamically (i.e. load it from a data source like an array, a Core Data model, a networked
server, etc.) in your table view you need to setup the data source.
A data source could, as stated above, be anything with data. Its entirely up to you how to format it and whats in it.
The only requirement is that you must be able to read it later so that you can populate each row of your table with
data when needed.
In this example, we'll just set an array with some strings (text) as our data source:
let myDataArray: [String] = ["Row one", "Row two", "Row three", "Row four", "Row five"]
Objective-C
// You'll need to define this variable as a global variable (like an @property) so that you can
access it later when needed.
NSArray *myDataArray = @[@"Row one", @"Row two", @"Row three", @"Row four", @"Row five"];
Swift
Objective-C
As soon as your view controller has declared it will conform to the UITableViewDataSource (that's what we've just
done above), you are required to implement at least the following methods in your view controller class:
tableView:numberOfRowsInSection, this asks you how many rows your table view should have.
// Swift
tableView:cellForRowAtIndexPath, requests that you create and return a cell for each row you specified in
tableView:numberOfRowsInSection. So, if you said you needed 10 rows, this method will be called ten times
for each row, and you need to create a cell for each of those rows.
// Swift
// Set the label on your cell to the text from your data array
cell.textLabel?.text = self.myDataArray[indexPath.row]
return cell
}
WARNING: You may NOT return nil for any cells in cellForRowAtIndexPath:. This will cause your app to
crash, and you will see the following error in the console:
You can either do this via code by setting your table's dataSource property to self on your view controller. Or you
may select your table view in your storyboard, open the Attributes Inspector, select the "Outlets" panel, and drag
from dataSource to your view controller (NOTE: make sure you connect to the UIViewCONTROLLER, not a UIView
or another object in your UIViewController).
When a user taps on a row in your table view, generally, you'll want to do something - to respond. In many apps,
when you tap on a row, more information about that item you tapped upon is displayed. Think of the Messages
app: when you tap on the row showing one of your contacts, the conversation with that person is then displayed on
screen.
In orer to do that, you must conform to the UITableViewDelegate protocol. Doing so is similar to conforming to the
data source protocol. This time however, you'll just add it next to UITableViewDataSource and separate it with a
comma. So it should look like this:
Swift
Objective-C
There are no required methods to implement for the table view's delegate. However, to handle row selections you'll
need to use the following method:
// Swift
// Objective-C
See below for the full setup with just code, no explanation.
Swift
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
// This view controller itself will provide the delegate methods and row data for the table
view.
myTableView.delegate = self
myTableView.dataSource = self
}
return cell
}
Objective-C
ViewController.h
#import <UIKit/UIKit.h>
@end
ViewController.m
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Data model: These strings will be the data for the table view cells
myDataArray = @[@"Row one", @"Row two", @"Row three", @"Row four", @"Row five"];
// This view controller itself will provide the delegate methods and row data for the table
view.
myTableView.delegate = self;
myTableView.dataSource = self;
}
return cell;
}
@end
Create a new project and replace the ViewController.swift code with the following.
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
// These strings will be the data for the table view cells
var animals: [String] = ["Horse", "Cow", "Camel", "Pig", "Sheep", "Goat"]
let cell:UITableViewCell =
self.tableView.dequeueReusableCellWithIdentifier(cellReuseIdentifier) as UITableViewCell!
cell.textLabel?.text = self.animals[indexPath.row]
return cell
}
if editingStyle == .Delete {
The single key method in the code above that enables row deletion is the last one. Here it is again for emphasis:
if editingStyle == .Delete {
Storyboard
Add a UITableView to the View Controller in the storyboard. Use auto layout to pin the four sides of the table view
to the edges of the View Controller. Control drag from the table view in the storyboard to the @IBOutlet var
tableView: UITableView! line in the code.
Finished
That's all. You should be able to run your app now and delete rows by swiping left and tapping "Delete".
Notes
This is only available from iOS 8. See this answer for more details.
If you need to change the number of buttons displayed or the button text then see this answer for more
details.
Further reading
How To Make A Swipeable Table View Cell With Actions – Without Going Nuts With Scroll Views
Apple Documentation
Objective-C
In your .h file
NSMutableArray *arrayForBool;
NSMutableArray *sectionTitleArray;
In your .m file
- (void)viewDidLoad {
[super viewDidLoad];
_tableView.dataSource = self;
_tableView.delegate = self;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [sectionTitleArray count];
}
return sectionView;
- (void)sectionHeaderTapped:(UITapGestureRecognizer *)gestureRecognizer{
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// return the number of rows inside the tableview.
return 3
}
return cell
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// return the number of rows inside the tableview.
return 3
return cell
}
- (void)pullToRefresh:(UIRefreshControl*) sender{
//Do work off the main thread
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Simulate network traffic (sleep for 2 seconds)
[NSThread sleepForTimeInterval:2];
//Update data
//Call complete on the main thread
dispatch_sync(dispatch_get_main_queue(), ^{
//Update network activity UI
NSLog(@"COMPLETE");
[sender endRefreshing];
});
});
UITableViewCell+RRCell.h file
#import <UIKit/UIKit.h>
-(id)initWithOwner:(id)owner;
@end
UITableViewCell+RRCell.m file
#import "UITableViewCell+RRCell.h"
-(id)initWithOwner:(id)owner {
@end
Import cell category class to use this method into the cellForRowAtIndexPath method
return cell;
}
This also applies any class which inherits from UIView, such as UIImageView.
Programmatically
Swift Code
someImageView.layoutIfNeeded()
someImageView.clipsToBounds = true
someImageView.layer.cornerRadius = 10
Objective-C Code
[someImageView layoutIfNeeded];
someImageView.clipsToBounds = YES;
someImageView.layer.cornerRadius = 10;
Example
//Swift code
topImageView.layoutIfNeeded()
bottomImageView.layoutIfNeeded()
topImageView.clipsToBounds = true
topImageView.layer.cornerRadius = 10
bottomImageView.clipsToBounds = true
bottomImageView.layer.cornerRadius = bottomImageView.frame.width / 2
//Objective-C code
[topImageView layoutIfNeeded]
[bottomImageView layoutIfNeeded];
topImageView.clipsToBounds = YES;
topImageView.layer.cornerRadius = 10;
bottomImageView.clipsToBounds = YES;
bottomImageView.cornerRadius = CGRectGetWidth(bottomImageView.frame) / 2;
Here is the result, showing the rounded view effect using the specified corner radius:
#import <QuartzCore/QuartzCore.h>
Storyboard Configuration
A rounded view effect can also be achieved non-programmatically by setting the corresponding properties in
Storyboard.
Since layer properties aren't exposed in Storyboard, you have to modify the cornerRadius attribute via the User Defined
Runtime Attributes section.
You can use this handy extension to apply rounded view as long as it has same width and height.
extension UIView {
@discardableResult
public func setAsCircle() -> Self {
self.clipsToBounds = true
let frameSize = self.frame.size
self.layer.cornerRadius = min(frameSize.width, frameSize.height) / 2.0
return self
}
}
To use it:
yourView.setAsCircle()
if showText {
if let text = text {
let s = NSString(string: text)
s.drawInRect(rect,
withAttributes: [
NSForegroundColorAttributeName: textColor,
NSFontAttributeName: UIFont(name: "Helvetica Neue", size: 18)!
])
}
}
Assuming that the text property is set, this will draw a string in the upper left hand corner of the view when the
application is run. The problem is we won't know what it looks like without running the application. This is where
IBInspectable and IBDesignable come in. IBInspectable allows us to visually set property values of the view in
Xcode, just like with the built in controls. IBDesignable will show us a visual preview in the storyboard. Here is how
the class should look:
@IBDesignable
class CustomView: UIView {
@IBInspectable var textColor: UIColor = UIColor.blackColor()
@IBInspectable var text: String?
@IBInspectable var showText: Bool = true
Or in Objective C:
IB_DESIGNABLE
@interface CustomView: UIView
@end
@implementation CustomView
- (instancetype)init {
if(self = [super init]) {
self.textColor = [UIColor blackColor];
self.showText = YES;
}
return self;
}
- (void)drawRect:(CGRect)rect {
//...
}
@end
The next screenshots show what happens in Xcode. The first one is what happens after adding the revised class.
Notice that there are three new UI elements for the three properties. The Text Color will display a color picker, Text is
just an input box and Show Text will give us the options for Off and On which are false and true respectively.
The next is after changing the Text Color to red using the color picker. Also, some text has been provided to make
the drawRect function display it. Notice that the view in Interface Builder has been updated as well.
However, We all come up situation when we need to create rounded UIView at multiple views in your
Storyboard.Instead of declaring IBDesignable to every views of Storyboard, its better to create an Extension of
UIView and get a user interface built just for your every UIView through out the project to create rounded view by
setting corner radius.A configurable border radius on any UIView you create in storyboard.
extension UIView {
Swift
Objective-C
Swift
This function can be used to draw attention to a specific view by shaking it a bit.
If you only want to provide one size intrinsically, you can provide the value UIViewNoIntrinsicMetric for the value
that you wish to ignore.
One could take this ImageView (or UIImageView) and set the horizontal alignment to superview center X and the
vertical alignment to superview center Y.
Going into the Size inspector panel, and down to the Intrinsic Size dropdown, you can switch this value from Default
to Placeholder.
Objective-C
[parentView addSubview:subView];
Swift
parentView.addSubview(subView)
You can also add the subView below another subView2, which is already a sub view of parentView using the
following code:
Objective-C
Swift
Swift
If somewhere in your code you need to bring a certain subView to front, so above all the others parentView's
subviews, you can do it like this:
Objective-C
[parentView bringSubviewToFront:subView];
Swift
parentView.bringSubviewToFront(subView)
Finally, if you want to remove subView from parentView, you can do as below:
Objective-C
[subView removeFromSuperview];
Swift
subView.removeFromSuperview()
[self.view addSubview:view];
//Use this function if you want to add view with respect to parent and should resize with it
[self addFullResizeConstraintForSubview:view addedOnParentView:self.view];
Functions
subView.translatesAutoresizingMaskIntoConstraints = NO;
[subView addConstraint:heightConstraint];
-(void)addFullResizeConstraintForSubview:(UIView*)subView addedOnParentView:(UIView*)parentView{
subView.translatesAutoresizingMaskIntoConstraints = NO;
view.frame.origin.x
view.frame.size.width
But if we add a simple extension to an UIView, we can get all the attributes very simply, like:
view.x
view.y
view.width
view.height
extension UIView {
var x: CGFloat {
get {
return self.frame.origin.x
}
set {
self.frame = CGRect(x: newValue, y: self.frame.origin.y, width: self.frame.size.width,
height: self.frame.size.height)
}
}
var y: CGFloat {
get {
return self.frame.origin.y
}
set {
self.frame = CGRect(x: self.frame.origin.x, y: newValue, width: self.frame.size.width,
height: self.frame.size.height)
}
}
We need to add this class file in a project and it'll be available to use throughout the project!
Swift
{
CGSize fullSize = getImageForEdit.size;
CGSize sizeInView = AVMakeRectWithAspectRatioInsideRect(imgViewFake.image.size,
imgViewFake.bounds).size;
CGFloat orgScale = orgScale = fullSize.width/sizeInView.width;
CGSize newSize = CGSizeMake(orgScale * img.image.size.width, orgScale * img.image.size.height);
if(newSize.width <= fullSize.width && newSize.height <= fullSize.height){
newSize = fullSize;
}
CGRect offsetRect;
if (getImageForEdit.size.height > getImageForEdit.size.width){
CGFloat scale = newSize.height/fullSize.height;
CGFloat offset = (newSize.width - fullSize.width*scale)/2;
offsetRect = CGRectMake(offset, 0, newSize.width-offset*2, newSize.height);
}
else{
CGFloat scale = newSize.width/fullSize.width;
CGFloat offset = (newSize.height - fullSize.height*scale)/2;
offsetRect = CGRectMake(0, offset, newSize.width, newSize.height-offset*2);
}
UIGraphicsBeginImageContextWithOptions(newSize, NO, getImageForEdit.scale);
[getImageForEdit drawAtPoint:offsetRect.origin];
// [img.image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
Simple AlertView
Swift:
let alert = UIAlertController(title: "Simple", message: "Simple alertView demo with Cancel and
OK.", preferredStyle: .alert)
Objective-C:
[alertController addAction:cancelAction];
[alertController addAction:okAction];
[self presentViewController:alertController animated: YES completion: nil];
Destructive AlertView
Swift:
Objective-C:
[alertController addAction:destructiveAction];
[alertController addAction:okAction];
[self presentViewController:alertController animated: YES completion: nil];
Objective-C
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Demo"
message:@"A demo with two buttons" preferredStyle:UIAlertControllerStyleActionSheet];
Swift
Objective-C
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel"
style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) {
//action when pressed button
}];
Swift
alertController.addAction(cancelAction)
alertController.addAction(okAction)
Objective-C
[alertController addAction:cancelAction];
[alertController addAction:okAction];
Swift
self.present(alertController, animated: true, completion: nil)
Objective-C
[self presentViewController:alertController animated: YES completion: nil];
Using the UIAlertActionStyle .destructive for an UIAlertAction will create a button with red tint color.
For this example, the okAction from above was replaced by this UIAlertAction:
Swift
let destructiveAction = UIAlertAction(title: "Delete", style: .destructive) { (result :
UIAlertAction) -> Void in
//action when pressed button
}
Objective-C
UIAlertAction * destructiveAction = [UIAlertAction actionWithTitle:@"Delete"
style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) {
//action when pressed button
}];
}
defaultAction.isEnabled = false
alert.addAction(defaultAction)
alert.addTextFieldWithConfigurationHandler { (textField) in
textField.delegate = self
}
Objective-C
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Hello"
preferredStyle:UIAlertControllerStyleAlert];
defaultAction.enabled = NO;
[alert addAction:defaultAction];
An action which is already added in alert controller can be assigned to this property.The Alert Controller will
highlight this action.
[alertController addAction:cancel];
[alertController addAction:no];
Alert Controller with preferred action not set.The NO button is not highlighted.
Swift
class ViewController: UIViewController {
Two Buttons
Swift
class ViewController: UIViewController {
Three Buttons
The handler was nil in the above examples. You can replace nil with a closure to do something when the user
taps a button, like the example below:
Swift
alert.addAction(UIAlertAction(title: "Launch the Missile", style: UIAlertActionStyle.Destructive,
handler: { action in
// do something like...
self.launchMissile()
}))
Multiple buttons do not necessarily need to use different UIAlertActionStyle types. They could all be
.Default.
For more than three buttons consider using an Action Sheet. The setup is very similar. Here is an example.
Swift
If the compiler already knows that the variable is an instance of UIColor you can skip the type all together:
Objective-C
Swift
Int Value
extension UIColor {
convenience init(hex: Int, alpha: CGFloat = 1.0) {
let r = CGFloat((hex >> 16) & 0xff) / 255
let g = CGFloat((hex >> 08) & 0xff) / 255
let b = CGFloat((hex >> 00) & 0xff) / 255
self.init(red: r, green: g, blue: b, alpha: alpha)
}
}
Example:
Note that for alpha the default value of 1.0 is provided, so it can be used as follows:
String Value
switch hex.characters.count {
case 3:
(a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
case 6:
(a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
case 8:
(a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
default:
(a, r, g, b) = (1, 1, 1, 0)
}
self.init(red: CGFloat(r) / 255, green: CGFloat(g) / 255, blue: CGFloat(b) / 255, alpha:
CGFloat(a) / 255)
}
}
Example Usage:
Objective-C
Int Value
Example:
String Value
unsigned hex;
if (![scanner scanHexInt:&hex]) return nil;
int a;
int r;
int g;
int b;
switch (noHashString.length) {
case 3:
a = 255;
r = (hex >> 8) * 17;
g = ((hex >> 4) & 0xF) * 17;
b = ((hex >> 0) & 0xF) * 17;
break;
case 6:
a = 255;
r = (hex >> 16);
g = (hex >> 8) & 0xFF;
b = (hex) & 0xFF;
break;
case 8:
a = (hex >> 24);
r = (hex >> 16) & 0xFF;
g = (hex >> 8) & 0xFF;
b = (hex) & 0xFF;
break;
default:
a = 255.0;
r = 255.0;
b = 255.0;
g = 255.0;
break;
}
return [UIColor colorWithRed:r / 255.0f green:g / 255.0f blue:b / 255.0f alpha:a / 255];
}
Example usage:
Swift 3
//In Swift Latest Version
_ colorWithAlpha = UIColor.red.withAlphaComponent(0.1)
Objective-C
UIColor * colorWithAlpha = [[UIColor redColor] colorWithAlphaComponent:0.1];
styleString
Since iOS 2.0 there is a private instance method on UIColor called styleString which returns an RGB or RGBA
string representation of the color, even for colors like whiteColor outside the RGB space.
Objective-C:
- (NSString *)styleString;
@end
// ...
In Swift you could use a bridging header to expose the interface. With pure Swift, you will need to create an @objc
protocol with the private method, and unsafeBitCast UIColor with the protocol:
whitePrivate.styleString() // rgb(255,255,255)
redPrivate.styleString() // rgb(255,0,0)
lightTextColorPrivate.styleString() // rgba(255,255,255,0.600000)
_systemDestructiveTintColor()
There is an undocumented class method on UIColor called _systemDestructiveTintColor which will return the
red color used by destructive system buttons:
It returns an unmanaged object, which you must call .takeUnretainedValue() on, since the color ownership has
not been transferred to our own object.
As with any undocumented API, you should take caution when trying to use this method:
if UIColor.respondsToSelector("_systemDestructiveTintColor") {
if let red = UIColor.performSelector("_systemDestructiveTintColor").takeUnretainedValue() as?
UIColor {
// use the color
}
}
or by using a protocol:
Swift Extension :
extension CALayer {
func borderUIColor() -> UIColor? {
return borderColor != nil ? UIColor(CGColor: borderColor!) : nil
}
The new user defined attribute (borderUIColor) will be recognized and applied without problems.
// Add tint.
attributedText.addAttribute(NSForegroundColorAttributeName, value: UIColor.blue, range:
tintedRange)
// Add highlight.
attributedText.addAttribute(NSBackgroundColorAttributeName, value: UIColor.yellow, range:
highlightedRange)
textView.attributedText = attributedText
//System Font
textView.font = UIFont.systemFont(ofSize: 12)
Objective-C
//System Font
textView.font = [UIFont systemFontOfSize:12];
enum {
UIDataDetectorTypePhoneNumber = 1 << 0,
UIDataDetectorTypeLink = 1 << 1,
UIDataDetectorTypeAddress = 1 << 2,
UIDataDetectorTypeCalendarEvent = 1 << 3,
UIDataDetectorTypeNone = 0,
UIDataDetectorTypeAll = NSUIntegerMax
};
Enabling auto-detection
Clickable data
To allow the link to be clicked (which will result in different actions depending on the data type) you must ensure
that the UITextView is selectable but not editable and that user interaction is enabled
textView.editable = NO;
textView.selectable = YES;
textView.userInteractionEnabled = YES; // YES by default
Objective-C:
textView.textAlignment = .left
Objective-C
textView.textAlignment = NSTextAlignmentLeft;
textViewShouldBeginEditing(_:)
textViewDidBeginEditing(_:)
textViewShouldEndEditing(_:)
textViewDidEndEditing(_:)
textView(_:shouldChangeTextIn:replacementText:)
textViewDidChange(_:)
Responding to URL
textView.textColor = UIColor.red
Objective-C
messageTextView.textContainerInset = UIEdgeInsetsZero
messageTextView.textContainer.lineFragmentPadding = 0
Now you can measure text size using NSAttributedString.boundingRectWithSize(...), and resize a UITextView
just to fit it to the text.
print("\(cursorPosition)")
}
To the beginning
To the end
To an arbitrary position
Related
textView.selectedTextRange = textView.textRangeFromPosition(textView.beginningOfDocument,
toPosition: textView.endOfDocument)
// Range: 3 to 7
let startPosition = textView.positionFromPosition(textView.beginningOfDocument, inDirection:
UITextLayoutDirection.Right, offset: 3)
let endPosition = textView.positionFromPosition(textView.beginningOfDocument, inDirection:
UITextLayoutDirection.Right, offset: 7)
textView.insertText("Hello")
Notes
This example originally comes from an adaptation of this Stack Overflow answer.
This answer uses a text field, but the same concepts apply to UITextView.
Use textView.becomeFirstResponder() to give focus to the text field and make the keyboard appear.
See this answer for how to get the text at some range.
Related
How to Create a Range in Swift (Deals indirectly with the issue of why we have to use selectedTextRange
here rather than just selectedRange)
Objective-C
In the first example one can see how you would intercept the user interacting with a textfield while writing.
Similarly, there are methods in the UITextFieldDelegate that are called when a user has started and ended his
interaction with a TextField.
To be able to access these methods, you need to conform to the UITextFieldDelegate protocol, and for each
textfield you want to be notified about, assign the parent class as the delegate:
To be notified when a user has started editing a textfield, you can implement textFieldDidBeginEditing(_:) method
like so:
Similarly, being notified if a user has ended interaction with a textfield, you can use the textFieldDidEndEditing(_:)
method like so:
// MARK: - UITextFieldDelegate
let allowedCharacters =
CharacterSet(charactersIn:"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvxyz").inverted
if string == filtered {
return true
} else {
return false
}
}
Objective-C
In addition you can also use character sets provided by apple to perform validation:
//Swift
let viewController = UIViewController()
let navigationController = UINavigationController(rootViewController: viewController)
//Objective-C
UIViewController *viewController = [[UIViewController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc]
initWithRootViewController:viewController];
Swift
navigationController?.popViewControllerAnimated(true)
Objective-C
[self.navigationController popViewControllerAnimated:YES];
Swift
navigationController?.popToRootViewControllerAnimated(true)
Objective C
[self.navigationController popToRootViewControllerAnimated:YES];
You can connect independently made controller and get all the benefits of a free hierarchy manager and common
UI presenter gratis. UINavigationController animates the transition to new controllers and provides the back
functionality for you automatically. UINavigationControlleralso gives access to all the other controllers in the
navigation stack which can help access to some functionality or data.
UINavigationController helps to remember where user is at the moment (navigation bar title) and how he can go
back (embedded back button) to one of the previous screens.
//Objective-C
UIViewController *fooViewController = [[UIViewController alloc] init];
[navigationController pushViewController:fooViewController animated:YES];
After initialization, add it to the view that it should recognize taps in.
Swift
Objective-C
- (void)viewDidLoad {
[super viewDidLoad];
UITapGestureRecognizer *recognizer =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(handleTap:)];
[self.view addGestureRecognizer:recognizer];
}
- (void)handleTap:(UITapGestureRecognizer *)recognizer {
func dismissKeyboard() {
view.endEditing(true)
}
Then, you add a tap gesture recognizer in your view controller, calling the method we just made
Swift
// Double Tap
let doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap))
doubleTapGesture.numberOfTapsRequired = 2
doubleTapView.addGestureRecognizer(doubleTapGesture)
}
Notes
Notes
This example comes from this fuller sample project demonstrating gesture recognizers.
Swift
// Long Press
let longPressGesture = UILongPressGestureRecognizer(target: self, action:
#selector(handleLongPress(_:)))
longPressView.addGestureRecognizer(longPressGesture)
}
Notes
Swift
// Swipe action
func handleSwipe(gesture: UISwipeGestureRecognizer) {
label.text = "Swipe recognized"
Objective-C
- (void)viewDidLoad
{
[super viewDidLoad];
}
//Handling Swipe Gesture Events
- (void)handleSwipe:(UISwipeGestureRecognizer *)swipe {
if (swipe.direction == UISwipeGestureRecognizerDirectionLeft) {
NSLog(@"Left Swipe");
}
if (swipe.direction == UISwipeGestureRecognizerDirectionRight) {
NSLog(@"Right Swipe");
}
Notes
Swift
// Pinch
let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(handlePinch(_:)))
pinchView.addGestureRecognizer(pinchGesture)
}
// Pinch action
func handlePinch(gesture: UIPinchGestureRecognizer) {
label.text = "Pinch recognized"
if gesture.state == UIGestureRecognizerState.Changed {
let transform = CGAffineTransformMakeScale(gesture.scale, gesture.scale)
pinchView.transform = transform
}
}
Notes
Swift
// Rotate
let rotateGesture = UIRotationGestureRecognizer(target: self, action:
#selector(handleRotate(_:)))
rotateView.addGestureRecognizer(rotateGesture)
}
// Rotate action
func handleRotate(gesture: UIRotationGestureRecognizer) {
label.text = "Rotate recognized"
if gesture.state == UIGestureRecognizerState.Changed {
let transform = CGAffineTransformMakeRotation(gesture.rotation)
rotateView.transform = transform
}
}
Notes
Select your View Controller and then in the Xcode menu choose Editor > Embed In > Navigation Controller.
Drag a UIBarButtonItem from the Object Library to the top navigation bar.
You could double-click "Item" to change the text to something like "Refresh", but there is an actual icon for Refresh
that you can use. Just select the Attributes Inspector for the UIBarButtonItem and for System Item choose
Refresh.
Add an IB Action
Control drag from the UIBarButtonItem to the View Controller to add an @IBAction.
print("How refreshing!")
}
That's it.
//Objective-C
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Greetings!"
style:UIBarButtonItemStylePlain target:self action:@selector(barButtonTaped)];
self.navigationItem.rightBarButtonItem = barButtonItem;
Objective-C
barButtonItem.image = [barButtonItem.image
imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
Here I just use UIViews but they can represent whatever view you like (ie, button, label, etc). I also chose horizontal
scrolling because the storyboard screenshots are more compact for this format. The principles are the same for
vertical scrolling, though.
Key concepts
The UIScrollView should only use one subview. This is a 'UIView' that serves as the content view to hold
everything you wish to scroll.
Make the content view and the scroll view's parent have equal heights for horizontal scrolling. (Equal widths
for vertical scrolling)
Make sure that all of the scrollable content has a set width and is pinned on all sides.
Storyboard
In this example, we will make a horizontal scroll view. Select the View Controller and then choose Freeform in the
Add a UIScrollView and pin all four sides to the root view of the view controller.
Add a UIView as a subview to the scroll view. This is key. Don't try to add lots of subviews to the scroll view. Just add
a single UIView. This will be your content view for the other views you want to scroll. Pin the content view to the
scroll view on all four sides.
Equal Heights
Now in the Document Outline, Command click both the content view and the scroll view's parent view in order to
select them both. Then set the heights to be equal (Control</kbd drag from the Content View to the Scroll View>).
This is also key. Because we are scrolling horizontally, the scroll view's content view won't know how high it should
be unless we set it in this way.
If we were making the content scroll vertically, then we would set the content view's width to be equal to the
scroll view's parent's width.
Add content
Add three UIViews and give them all constraints. I used 8 point margins for everything.
Constraints:
Green view: pin the top, left, and bottom edges. Make the width 400.
Red view: pin the top, left, and bottom edges. Make the width 300.
Purple view: pin all four edges. Make the width whatever the remaining space is (268 in this case).
Setting the width constraints is also key so that the scroll view knows how wide its content view will be.
Finished
That's all. You can run your project now. It should behave like the scrolling image at the top of this answer.
Further Study
Swift
Objective-C
What this will do is,simply stick every edge of scrollview to viewcontroller's view
Scenario 1:
Now lets say our content is huge,and we want it to scroll horizontally as well as vertically.
For this,
Add a UIView to the scrollview of frame(0,0,700,700).Lets give it orange background color to identify it
differently.
Scenario 2: Lets consider a scenario where we know that content width is going to be same as scroll width
width,but height is larger than scrollview.
Scenario 3:
Undo all the changes to achieve constraints as below(i.e restore original constraints which achieved
vertical and horizontal scroll)
Objective C:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
[self stoppedScrolling];
}
- (void)stoppedScrolling {
// done, do whatever
}
Swift:
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if !decelerate {
stoppedScrolling()
}
}
func stoppedScrolling() {
// done, do whatever
}
scrollview.isScrollEnabled = true
Objective-C
scrollview.scrollEnabled = YES;
scrollView.minimumZoomScale = 0.1
scrollView.maximumZoomScale = 4.0
scrollView.zoomScale = 1.0
scrollview.delegate = self as? UIScrollViewDelegate
To zoom in and out image we must specify the amount the user can zoom in and out. We do this by setting values
of the scroll view’s minimumZoomScale and maximumZoomScale properties. Both of these are set to 1.0 by default.
And zoomScale to 1.0 which specify the zoom factor for the minimum and maximum zooming.
To support zooming, we must set a delegate for your scroll view. The delegate object must conform to the
UIScrollViewDelegate protocol. That delegate class must implement the viewForZoomingInScrollView() method
and return the view to zoom.
scrollView?.addSubview(imageView)
Reference
With Autolayout:
When the scroll view's content is set up using autolayout, it must be explicitly sized both vertically and horizontally
and have all 4 edges pinned to the containing scroll view. That way, the contentSize is calculated automatically
based on the scroll view's contents and also gets updated when the content's layout is changed.
Manually:
Swift
Objective-C
Every time the user scrolls on the x-axis, the scrollView's content offset is set back to 0.
You can obviously change the xs to ys and therefor lock the direction to be horizontal-only.
You also need to make sure you put this code into the scrollViewDidScroll(_ scrollView: UIScrollView)
delegate method. Otherwise, you won't get it to work.
Also, be sure to have imported the UIScrollViewDelegate in your class declaration, like so:
...and set the scrollView's delegate to self in some method like viewDidLoad(_:)
scrollView.delegate = self
Step 6: Set Distribution = Fill equally Spacing =5 in main stackview (set According to your requirement)
Swift
Objective-C
Objective-C
The updateConstraintForAxis function just sets the axis of the stack view containing the two image views:
The animated gif below gives you an idea of how this appears:
If you try to get the position of Textfield.frame.minY can be 0, because the minY frame is only considering the
distance between the element and the top of the StackView. So you have to consider all other parent
stackviews/views.
extension UIScrollView {
This will consider all parent view and sum the necessary offset for the scrollview present the necessary view on
screen (for example a Textfield which cannot stay behind the user keyboard)
Usage example:
In order to get a UIScrollView to automatically scroll when its contents become too large to fit in the visible area,
we need to add a ContentView and some constraints that allow the UIScrollView to determine the size of its
contents AND its width and height in its parent view.
import Foundation
import UIKit
//Setup
self.initControls()
self.setTheme()
self.layoutScrollView()
self.layoutContentView()
func initControls() {
self.scrollView = UIScrollView()
self.contentView = UIView()
}
func setTheme() {
self.scrollView.backgroundColor = UIColor.blue()
self.contentView.backgroundColor = UIColor.orange()
}
func layoutScrollView() {
self.view.addSubview(self.scrollView)
self.scrollView.translatesAutoresizingMaskIntoConstraints = false
}
//Disable Horizontal Scrolling by making the contentView EqualWidth with our controller's
self.view (ScrollView's parentView).
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat:
"H:[contentView(==view)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views
as! [String : AnyObject]))
self.contentView.translatesAutoresizingMaskIntoConstraints = false
}
func addChildViews() {
//Init
let greenView = UIView()
let whiteView = UIView()
//Theme
greenView.backgroundColor = UIColor.green()
whiteView.backgroundColor = UIColor.orange()
//Constrain the greenView to the contentView with a height of 400 and 15 spacing all
around.
constraints.append("H:|-15-[greenView]-15-|")
constraints.append("V:|-15-[greenView(400)]")
//Constrain the whiteView below the greenView with 15 spacing all around and a height of
500.
constraints.append("H:|-15-[whiteView]-15-|")
constraints.append("V:[greenView]-15-[whiteView(500)]-15-|")
greenView.translatesAutoresizingMaskIntoConstraints = false
whiteView.translatesAutoresizingMaskIntoConstraints = false
}
}
We disabled horizontal scrolling using the EqualWidth constraint on the contentView and self.view
Step 1 :
Add Scrollview to view in storyboard and add leading, trailing, top and bottom constraints (All values are zero).
Step 2 :
Don't add directly views which you need on directly scrollview, First add one view to scrollview (that will be our
content view for all UI elements). Add below constraints to this view.
1. Leading, trailing, top and bottom constraints (All values are zero).
2. Add equal height, equal width to Main view (i.e. which contains scrollview). For equal height set priority to
low. (This is the important step for setting content size).
3. Height of this content view will be according to the number of views added to the view. let say if you added
last view is one label and his Y position is 420 and height is 20 then your content view will be 440.
Step 3 : Add constraints to all of views which you added within content view as per your requirement.
Swift
textField.becomeFirstResponder()
Objective-C
[textField becomeFirstResponder];
Resign
Swift
textField.resignFirstResponder()
Objective-C
[textField resignFirstResponder];
override viewDidLoad() {
super.viewDidLoad()
textField.delegate = self
}
textFieldShouldReturn is called every time the return button on the keyboard is pressed.
Swift:
Objective-C:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return true;
}
Swift 3
override func caretRect(for position: UITextPosition) -> CGRect {
return CGRect.zero
}
Objective-C
- (CGRect) caretRectForPosition:(UITextPosition*) position{
return CGRectZero;
}
Swift
let textField = UITextField() // initialized however
textField.inputAccessoryView = toolbar
Objective-C
UITextField *textField = [[UITextField alloc] init];
[toolbar setItems:items];
[toolbar sizeToFit];
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect keyboardFrameInWindow;
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardFrameInWindow];
// the keyboard frame is specified in window-level coordinates. this calculates the frame as if
it were a subview of our view, making it a sibling of the scroll view
CGRect keyboardFrameInView = [self.view convertRect:keyboardFrameInWindow fromView:nil];
// this is an old animation method, but the only one that retains compaitiblity between
parameters (duration, curve) and the values contained in the userInfo-Dictionary.
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey]
doubleValue]];
[UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey]
intValue]];
_scrollView.contentInset = newContentInsets;
_scrollView.scrollIndicatorInsets = newContentInsets;
/*
* Depending on visual layout, _focusedControl should either be the input field
(UITextField,..) or another element
// this is the visible part of the scroll view that is not hidden by the keyboard
CGFloat scrollViewVisibleHeight = _scrollView.frame.size.height -
scrollViewKeyboardIntersection.size.height;
// make sure we don't set an impossible offset caused by the "nice visual offset"
// if a control is at the bottom of the scroll view, it will end up just above the
keyboard to eliminate scrolling inconsistencies
newContentOffset.y = MIN(newContentOffset.y, _scrollView.contentSize.height -
scrollViewVisibleHeight);
[UIView commitAnimations];
}
[UIView commitAnimations];
}
In this example we change only the color and font. You could change other properties such as underline or
strikethrough style. Refer to NSAttributedString for the properties that can be changed.
At first, you need a custom wrapper-class for UIPickerView conforming to the protocols UIPickerViewDataSource
and UIPickerViewDelegate.
You need to implement the following methods for the DataSource and Delegate:
public func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if data != nil {
return data!.count
} else {
return 0
}
}
public func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component:
Int) -> String? {
if data != nil {
return data![row]
} else {
return ""
}
}
To handle the data, MyPickerView needs the properties data, selectedValue and textFieldBeingEdited:
/**
The data for the `UIPickerViewDelegate`
Always needs to be an array of `String`! The `UIPickerView` can ONLY display Strings
*/
public var data: [String]? {
didSet {
super.delegate = self
super.dataSource = self
self.reloadAllComponents()
}
}
/**
Stores the UITextField that is being edited at the moment
*/
public var textFieldBeingEdited: UITextField?
/**
Get the selected Value of the picker
*/
public var selectedValue: String {
The ViewController that contains your textField, needs to have a property for your custom UIPickerView.
(Assuming, that you already have another property or @IBOutlet containing your textField)
/**
The picker view to present as keyboard
*/
var picker: MyPickerView?
picker = MyPickerView()
picker?.autoresizingMask = [.flexibleHeight, .flexibleWidth]
picker?.backgroundColor = UIColor.white()
picker?.data = ["One", "Two", "Three", "Four", "Five"] //The data shown in the picker
textField.inputView = picker
Now, you have replaced the keyboard by an UIPickerView, but there is no possibility to dismiss it. This can be done
with a custom .inputAccessoryView:
/**
A toolbar to add to the keyboard when the `picker` is presented.
*/
var pickerAccessory: UIToolbar?
pickerAccessory = UIToolbar()
pickerAccessory?.autoresizingMask = .flexibleHeight
You should set the frame of your toolbar. To fit in the design of iOS, it's recommended to use a height of 44.0:
For a good user experience, you should add two buttons ("Done" and "Cancel"), but it would also work with only
one that dismisses the keyboard.
textField.inputAccessoryView = pickerAccessory
Before you can build your project, you need to implement the methods, the buttons are calling:
/**
Called when the cancel button of the `pickerAccessory` was clicked. Dismsses the picker
*/
func cancelBtnClicked(_ button: UIBarButtonItem?) {
textField?.resignFirstResponder()
}
/**
Called when the done button of the `pickerAccessory` was clicked. Dismisses the picker and puts
the selected value into the textField
*/
func doneBtnClicked(_ button: UIBarButtonItem?) {
textField?.resignFirstResponder()
textField.text = picker?.selectedValue
}
Run your project, tap the textField and you should see a picker like this instead of the keyboard:
If you don't want to have the first row selected automatically, you can set the selected row as in UIPickerView:
Swift
let textfield = UITextField(frame: CGRect(x: 0, y: 0, width: 200, height: 21))
Objective-C
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 200, 21)];
print("\(cursorPosition)")
}
In order to set the position, all of these methods are actually setting a range with the same start and end values.
To the beginning
To the end
To an arbitrary position
Related
textField.selectedTextRange = textField.textRangeFromPosition(textField.beginningOfDocument,
toPosition: textField.endOfDocument)
// Range: 3 to 7
let startPosition = textField.positionFromPosition(textField.beginningOfDocument, inDirection:
UITextLayoutDirection.Right, offset: 3)
let endPosition = textField.positionFromPosition(textField.beginningOfDocument, inDirection:
UITextLayoutDirection.Right, offset: 7)
textField.insertText("Hello")
Notes
This answer uses a text field, but the same concepts apply to UITextView.
Use textField.becomeFirstResponder() to give focus to the text field and make the keyboard appear.
See this answer for how to get the text at some range.
Related
How to Create a Range in Swift (Deals indirectly with the issue of why we have to use selectedTextRange
here rather than just selectedRange)
Ctrl + Drag from the UItextfield in MainStoryboard to the ViewController Class and create a UITextField Outlet
in the action you just created type the name of your UItextField .resignFirstResponder()
This will take care of hiding the keyboard when pressing the return key on keyboard.
Objective-C
[textField resignFirstResponder];
Objective-C
CGRect *frame = CGRectMake(0, 0, 100, 100);
UITextField *textField = [[UITextField alloc] initWithFrame:frame];
Interface Builder
You can also add a UITextField to a storyboard by dragging it from Object Library.
Objective-C
textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
All options:
Objective-C
[textField setTextAlignment: NSTextAlignmentCenter];
In the example, we have set the NSTextAlignment to center. You can also set to .Left, .Right, .Justified and
.Natural.
.Natural is the default alignment for the current localization. That means for left-to-right languages (eg. English),
the alignment is .Left; for right-to-left languages, it is .Right.
NOTE: For iPhone it is easy to do this using Number type keyboard, but for iPad there is no keyboard with Numbers
only
deinit {
NotificationCenter.default.removeObserver(self)
}
func textDidChange() {
text = filteredText()
}
private func filteredText() -> String {
let inverseSet = CharacterSet(charactersIn:"0123456789").inverted
let components = text!.components(separatedBy: inverseSet)
return components.joined(separator: "")
}
}
So, wherever we want text field which would take only numbers as input text, then we can use this custom
UITextField
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return enableLongPressActions
}
}
Using enableLongPressActions property, we can enable all actions any time later, if needed.
beginTrackingWithTouch is called when the finger first touches down within the control's bounds.
continueTrackingWithTouch is called repeatedly as the finger slides across the control and even outside of
the control's bounds.
endTrackingWithTouch is called when the finger lifts off the screen.
MyCustomControl.swift
import UIKit
// These are out self-defined rules for how we will communicate with other classes
protocol ViewControllerCommunicationDelegate: class {
func myTrackingBegan()
func myTrackingContinuing(location: CGPoint)
func myTrackingEnded()
}
// whichever class wants to be notified of the touch events must set the delegate to itself
weak var delegate: ViewControllerCommunicationDelegate?
// get the touch location in our custom control's own coordinate system
let point = touch.locationInView(self)
// Update the delegate (i.e. the view controller) with the new coordinate point
delegate?.myTrackingContinuing(point)
ViewController.swift
import UIKit
class ViewController: UIViewController, ViewControllerCommunicationDelegate {
func myTrackingBegan() {
trackingBeganLabel.text = "Tracking began"
}
func myTrackingEnded() {
trackingEndedLabel.text = "Tracking ended"
}
}
Notes
Alternate methods of achieving the same result without subclassing include adding a target or using a
gesture recognizer.
It is not necessary to use a delegate with these methods if they are only being used within the custom control
itself. We could have just added a print statement to show how the events are being called. In that case, the
code would be simplified to
import UIKit
class MyCustomControl: UIControl {
Swift
Objective-C
When the view controller is part on an navigation stack, you can access the navigation controller like this:
Swift
Objective-C
With an Identifier:
Give the scene a Storyboard ID within the identity inspector of the storyboard.
Within the storyboard select the view controller, then select the attribute inspector, check the "Is Initial View
Controller" box.
Objective-C
- (void)displayContentController:(UIViewController *)vc {
[self addChildViewController:vc];
vc.view.frame = self.view.frame;
[self.view addSubview:vc.view];
[vc didMoveToParentViewController:self];
}
- (void)hideContentController:(UIViewController *)vc {
[vc willMoveToParentViewController:nil];
[vc.view removeFromSuperview];
[vc removeFromParentViewController];
}
//set off-image
mySwitch.offImage = [UIImage imageNamed:@"off_image"];
[mySwitch setOffImage:[UIImage imageNamed:@"off_image"]];
//set on-image
mySwitch.onImage = [UIImage imageNamed:@"on_image"];
[mySwitch setOnImage:[UIImage imageNamed:@"on_image"]];
Swift
//set off-image
mySwitch.offImage = UIImage(named: "off_image")
//set on-image
mySwitch.onImage = UIImage(named: "on_image")
[mySwitch setOn:YES];
//or
[mySwitch setOn:YES animated:YES];
Swift
mySwitch.setOn(false)
//or
mySwitch.setOn(false, animated: false)
Swift
mySwitch.backgroundColor = UIColor.yellow
mySwitch.backgroundColor = UIColor(red: 255.0/255, green: 0.0/255, blue: 0.0/255, alpha: 1.0)
mySwitch.backgroundColor = UIColor(white: 0.5, alpha: 1.0)
mySwitch.backgroundColor = UIColor(hue: 0.4,saturation: 0.3,brightness: 0.7,alpha: 1.0)
//for off-state
mySwitch.tintColor = [UIColor blueColor];
[mySwitch setTintColor: [UIColor blueColor]];
//for on-state
mySwitch.onTintColor = [UIColor cyanColor];
[mySwitch setOnTintColor: [UIColor cyanColor]];
Swift
//for off-state
mySwitch.tintColor = UIColor.blueColor()
//for on-state
mySwitch.onTintColor = UIColor.cyanColor()
Swift:
Objective C:
Required Methods
Swift
Objective C
- (NSInteger)collectionView:(UICollectionView*)collectionView
numberOfItemsInSection:(NSInteger)section {
// Return how many items in section
NSArray *sectionArray = [_data objectAtIndex:section];
return [sectionArray count];
}
forIndexPath:indexPath];
//Customize your cell here, default UICollectionViewCells do not contain any inherent
//text or image views (like UITableView), but some could be added,
//or a custom UICollectionViewCell sub-class could be used
return newCell;
}
Create a new Cocoa Touch Class file (File > New > File... > iOS > Cocoa Touch Class). Name it MyCollectionViewCell.
This class will hold the outlets for the views that you add to your cell in the storyboard.
import UIKit
class MyCollectionViewCell: UICollectionViewCell {
Open ViewController.swift and make sure you have the following content:
import UIKit
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
let reuseIdentifier = "cell" // also enter this string as the cell identifier in the storyboard
var items = ["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", "44", "45", "46", "47",
"48"]
// Use the outlet in our custom class to get a reference to the UILabel in the cell
cell.myLabel.text = self.items[indexPath.item]
cell.backgroundColor = UIColor.yellowColor() // make cell more visible in our example
project
return cell
}
Notes
UICollectionViewDataSource and UICollectionViewDelegate are the protocols that the collection view
follows. You could also add the UICollectionViewDelegateFlowLayout protocol to change the size of the
views programmatically, but it isn't necessary.
We are just putting simple strings in our grid, but you could certainly do images later.
Drag a Collection View to the View Controller in your storyboard. You can add constraints to make it fill the parent
view if you like.
Items: 1
Layout: Flow
The little box in the top left of the Collection View is a Collection View Cell. We will use it as our prototype cell. Drag
a Label into the cell and center it. You can resize the cell borders and add constraints to center the Label if you like.
Write "cell" (without quotes) in the Identifier box of the Attributes Inspector for the Collection View Cell. Note that
this is the same value as let reuseIdentifier = "cell" in ViewController.swift.
And in the Identity Inspector for the cell, set the class name to MyCollectionViewCell, our custom class that we
made.
Hook the Label in the collection cell to myLabel in the MyCollectionViewCell class. (You can Control-drag.)
Hook the Collection View delegate and dataSource to the View Controller. (Right click Collection View in the
Document Outline. Then click and drag the plus arrow up to the View Controller.)
Finished
Here is what it looks like after adding constraints to center the Label in the cell and pinning the Collection View to
the walls of the parent.
If you want to make improvements on the appearance, see the original post that this example comes from.
// MARK: - UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section:
Int) -> Int {
guard collectionView == collectionCategory else {
return arrOfProducts.count
}
return arrOfCategory.count
}
return cell
}
// MARK: - UICollectionViewDelegateFlowLayout
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout:
if(UI_USER_INTERFACE_IDIOM() == .pad) {
itemWidth = collectionWidth / 4 - 1;
}
return CGSize(width: itemWidth, height: 50)
}
Objective-C
Swift
Objective-C
Swift
As just an example we can set the background color of selected cell to green.
Objective-C
Swift
func createCollectionView() {
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
let collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: view.frame.width,
height: view.frame.height), collectionViewLayout: layout)
collectionView.dataSource = self
collectionView.delegate = self
view.addSubview(collectionView)
}
Objective-C
collecitonView.performBatchUpdates({
// Perform updates
}, nil)
Inside the update block, you can perform insertions, deletions, moves, and reloads. Here is how to determine which
indexPath to use:
Type NSIndexPath
Insertion Index in new array
Deletion Index in old array
Move from: old array, to: new array
Reload either new or old array (it shouldn't matter)
You should only call reload on cells that have not moved, but their content has changed. It is important to note that
a move will not refresh the content of a cell, but only move its location.
To verify that your batch update will be performed correctly, make sure the set of indexPaths for deletion, move-
from, and reload are unique, and the set of indexPaths for insertion, move-to, and reload are unique.
collecitonView.performBatchUpdates({
collectionView.insertItemsAtIndexPaths([NSIndexPath(forItem: 2, inSection: 0)])
collectionView.deleteItemsAtIndexPaths([NSIndexPath(forItem: 1, inSection: 0)])
collectionView.moveItemAtIndexPath(NSIndexPath(forItem: 2, inSection: 0),
toIndexPath: NSIndexPath(forItem: 1, inSection:0))
}, nil)
searchController.searchResultsUpdater = self
self.definesPresentationContext = true
// Don't hide the navigation bar because the search bar is in it.
searchController.hidesNavigationBarDuringPresentation = false
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// If the search bar is active, use the searchResults data.
return searchController.isActive ? searchResults.count : entries.count
}
searchController.searchResultsUpdater = self
self.definesPresentationContext = true
// Set the content offset to the height of the search bar's height
// to hide it when the view is first presented.
self.tableView.contentOffset = CGPoint(x: 0, y: searchController.searchBar.frame.height)
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// If the search bar is active, use the searchResults data.
return searchController.isActive ? searchResults.count : entries.count
}
searchController.searchResultsUpdater = self
searchController.hidesNavigationBarDuringPresentation = false
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.sizeToFit()
self.tableView.tableHeaderView = searchController.searchBar
}
And finally, implement the updateSearchResultsForSearchController method that comes from the
UISearchResultsUpdating protocol:
- (void)searchBarConfiguration
{
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchBar.delegate = self;
self.searchController.hidesNavigationBarDuringPresentation = NO;
// Hides search bar initially. When the user pulls down on the list, the search bar is
revealed.
[self.tableView setContentOffset:CGPointMake(0,
self.searchController.searchBar.frame.size.height)];
self.tableView.contentOffset = CGPointMake(0,
CGRectGetHeight(_searchController.searchBar.frame));
self.tableView.tableHeaderView = _searchController.searchBar;
_searchController.searchBar.delegate = self;
_searchController.searchBar.showsCancelButton = YES;
self.tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(resetSearchbarAndTableView)];
[self.view addGestureRecognizer:self.tapGestureRecognizer];
- (void)resetSearchbarAndTableView{
// Reload your tableview and resign keyboard.
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar{
// Search cancelled
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{
// Implement filtration of your data as per your need using NSPredicate or else.
// then reload your data control like Tableview.
}
To create a tab bar controller using the interface builder, drag a tab bar Controller from the Object Library into the
canvas.
By default a tab bar controller comes with two views. To add additional views, control drag from the tab bar
controller to the new view and select 'view controllers' in the segue-drop down.
To add a Navigation Controller to a View Controller connecting from Tab Bar Controller, here are the flow
Select the view controller for which we need to add navigation controller. Here let it be the Search View
Controller as the selection display.
From the Editor menu of the Xcode, select Embed In -> Navigation Controller option
Select the tab bar item from the corresponding view controller and go to the attributes inspector
If you want a built-in icon and title, set the 'System Item' to the corresponding value.
For a custom icon, add the required images to the assets folder and set the 'System Item' from earlier to 'custom'.
Now, set the icon to be shown when the tab is selected from the 'selected image' drop down and the default tab
icon from the 'image' drop down. Add the corresponding title in the 'title' field.
In the viewDidLoad() method of the view controller, add the following code:
Objective-C:
self.title = @"item";
Swift:
self.title = "item"
self.tabBarItem.image = UIImage(named: "item")
self.tabBarItem.selectedImage = UIImage(named: "item_selected")
window?.backgroundColor = UIColor.black
tabBarController.viewControllers = [firstTabNavigationController,
secondTabNavigationControoller, thirdTabNavigationController, fourthTabNavigationControoller,
fifthTabNavigationController]
firstTabNavigationController.tabBarItem = item1
secondTabNavigationControoller.tabBarItem = item2
thirdTabNavigationController.tabBarItem = item3
fourthTabNavigationControoller.tabBarItem = item4
fifthTabNavigationController.tabBarItem = item5
self.window?.rootViewController = tabBarController
window?.makeKeyAndVisible()
return true
}
import UIKit
self.navigationController?.isNavigationBarHidden = true
UITabBar.appearance().tintColor = UIColor.purple
extension UIImage {
class func imageWithColor(_ color: UIColor, size: CGSize) -> UIImage {
let rect: CGRect = CGRect(origin: CGPoint(x: 0,y :0), size: CGSize(width: size.width,
height: size.height))
UIGraphicsBeginImageContextWithOptions(size, false, 0)
color.setFill()
UIRectFill(rect)
let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return image
}
Choosing image for tab bar and set the tab title here
Objective-C
The code employs an additional trick of shortly setting the height of the web view to 1 prior to measuring the fitting
size. Otherwise it would simply report the current frame size. After measuring we immediately set the height to the
actual content height.
Source
Swift
In this case, style.css is loaded locally from the app's resource directory. Of course it's also possible to specify a
remote URL.
Swift
Objective-C
Swift
webview.stringByEvaluatingJavaScriptFromString("alert('This is JavaScript!');")
Objective-C
Swift
webview.stopLoading()
Objective-C
[webview stopLoading];
webview.reload()
Objective-C
[webview reload];
Section 41.8: Load Document files like .pdf, .txt, .doc etc
Instead of web pages, we can also load the document files into iOS WebView like .pdf, .txt, .doc etc.. loadData
method is used to load NSData into webview.
Swift
Objective-C
The following line of code loads the content of the HTML file into the webView
webView.loadRequest(NSURLRequest(URL: NSURL(fileURLWithPath:
NSBundle.mainBundle().pathForResource("YOUR HTML FILE", ofType: "html")!})
If your HTML file is called index.html replace YOUR HTML FILE with index
You can use this code either in viewDidLoad() or viewDidAppear() or any other function
In vc.h
@interface vc : UIViewController<UIWebViewDelegate>
in vc.m
if (navigationType == UIWebViewNavigationTypeLinkClicked){
//open it on browser if you want to open it in same web view remove return NO;
NSURL *url = request.URL;
if ([[UIApplication sharedApplication] canOpenURL:url]) {
[[UIApplication sharedApplication] openURL:url];
}
return NO;
return YES;
Swift
let textToShare = "StackOverflow Documentation!! Together, we can do for Documentation what we did
for Q&A."
let documentationURL = NSURL(string:"http://stackoverflow.com/tour/documentation")
import UIKit
When it comes to selector, the compiler only needs to know that it exists.. This can be done through a protocol
and not be implemented.
import UIKit
@objc
protocol ButtonEvent {
@objc optional func onButtonPress(_ button: UIButton)
}
This is because your application does NOT implement the onButtonPress function.
Now what if you could do all of this alongside the initialization of the button? What if you didn't have to specify
callbacks and could instead specify blocks that can be added and removed at any time? Why worry about
implementing selectors?
Solution
import Foundation
import UIKit
protocol RemovableTarget {
func enable();
func disable();
}
extension UIControl {
func addEventHandler(event: UIControlEvents, runnable: (control: UIControl) -> Void) ->
RemovableTarget {
@objc
private func run(_ control: UIControl) {
runnable(control: control)
}
The above is a simple extension on UIControl. It adds an inner private class that has a callback func run(_
Next we use object association to add and remove the target because it will not be retained by the UIControl.
The event handler function returns a Protocol in order to hide the inner workings of the Target class but also to
allow you to enable and disable the target at any given time.
Usage Example:
import Foundation
import UIKit
//Create a button.
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 44))
self.view.addSubview(button)
DispatchQueue.main.after(when: DispatchTime.now() + 5) {
target.enable() //Enable the listener.
}
}
}
AppDelegate.m
Just create an object for the UISplitViewController and set that viewcontroller as the rootviewcontroller for your
application.
SplitViewController.h
#import <UIKit/UIKit.h>
#import "MasterViewController.h"
#import "DetailViewController.h"
@interface ViewController : UISplitViewController
{
DetailViewController *detailVC;
MasterViewController *masterVC;
NSMutableArray *array;
}
@end
MasterViewController is always on the left side of the device you can set the width in UISplitViewCOntroller
delegate methods and DetailViewController is on the Right side of the application
SplitViewController.m
#import "ViewController.h"
#define ANIMATION_LENGTH 0.3
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
masterVC = [[MasterViewController alloc]init];
detailVC = [[DetailViewController alloc]init];
[masterVC setDetailDelegate:(id)detailVC];
NSArray *vcArray = [NSArray arrayWithObjects:masterVC, detailVC, nil];
Created master and detail ViewControllers are added to an array which is set to self.viewControllers in
UISplitViewController. self.preferredDisplayMode is is the mode set for displaying of master and
DetailViewController Apple Documentation for DisplayMode . self.presentsWithGesture enables swipe gesture
for displaying MasterViewcontroller
MasterViewController.h
#import <UIKit/UIKit.h>
MasterViewController.m
#import "MasterViewController.h"
@implementation MasterViewController
@synthesize detailDelegate;
-(void)viewDidLoad
{
[super viewDidLoad];
- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 100;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section
{
return [viewControllerArray count];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1; //count of section
}
if (cell == nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:cellId];
}
[cell.contentView setBackgroundColor:[UIColor redColor]];
cell.textLabel.text =[NSString stringWithFormat:@"My VC at index %ld",(long)indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[detailDelegate sendSelectedNavController:[viewControllerArray objectAtIndex:indexPath.row]];
}
@end
Create some UIViewControllers and added it to an array. The Table view is initialized then on
didSelectRowAtIndexPath method I send a UIViewController to the DetailViewController using detailDelegate
with the corresponding UIViewController in array as parameter
DetailViewController.h
#import <UIKit/UIKit.h>
#import "DetailViewController.h"
@implementation DetailViewController
-(void)viewDidLoad
{
[super viewDidLoad];
[self.view setBackgroundColor:[UIColor whiteColor]];
}
-(void)sendSelectedNavController:(UIViewController *)navController
{
NSArray *viewsToRemove = [self.view subviews];
for (UIView *v in viewsToRemove) {
[v removeFromSuperview];
}
tempNav = navController;
[self.view addSubview:tempNav.view];
}
@end
sendSelectedNavController is declared here with removing all the views in the DetailViewController and adding
the passed UIViewController from the MasterViewController
- (IBAction)sliderAction:(id)sender {
NSLog(@"Slider Value %f", sender.value);
}
func sliderAction(sender:UISlider!)
{
print("value--\(sender.value)")
}
SWIFT:
where:
For example, you can use the instance created above to access a certain UIViewController instantiated within that
storyboard:
OBJECTIVE-C:
navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal
options:nil];
pageViewController.dataSource = self;
4. setViewControllers will add only first view controller, next will be added to the stack using data source
methods
if (viewControllers.count) {
[pageViewController setViewControllers:@[[viewControllers objectAtIndex:0]]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:nil];
}
5. Add UIPageViewController as a child view controller so it will receive from it's parent view controller
appearance and rotation events.
[self addChildViewController:pageViewController];
pageViewController.view.frame = self.view.frame;
[self.view addSubview:pageViewController.view];
[pageViewController didMoveToParentViewController:self];
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController
{
return [viewControllers count];
}
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController
{
return index;
}
7. Utility method which returns a view controller using an index, if index is out of bounds it returns nil.
- (UIViewController *)childViewControllerAtIndex:(NSInteger)index
{
if (index <= ([viewControllers count] - 1)) {
return [viewControllers objectAtIndex:index];
} else {
return nil;
}
}
4. Paste this code into your UIPageViewController class, you should get a colorful infinite paged app :)
This is what the final project looks like, you get a view controller with different color with every scroll:
AppDelegate.m
Just create an object for your UISplitVIewController and set it as the rootViewController for your application.
SplitViewController.h
#import <UIKit/UIKit.h>
#import "MasterViewController.h"
#import "DetailViewController.h"
@interface ViewController : UISplitViewController
{
DetailViewController *detailVC;
MasterViewController *masterVC;
NSMutableArray *array;
}
@end
MasterViewController is a UIViewController that is set on the left side of the device you can set the width in
UISplitViewController using maximumPrimaryColumnWidth and DetailViewController is on the Right side
SplitViewController.m
#import "ViewController.h"
#define ANIMATION_LENGTH 0.3
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
masterVC = [[MasterViewController alloc]init];
detailVC = [[DetailViewController alloc]init];
[masterVC setDetailDelegate:(id)detailVC];
NSArray *vcArray = [NSArray arrayWithObjects:masterVC, detailVC, nil];
self.preferredDisplayMode = UISplitViewControllerDisplayModeAutomatic;
self.viewControllers = vcArray;
self.delegate = (id)self;
The master and detail UIViewController's are added to an NSArray which is set to self.viewControllers.
self.preferredDisplayMode is is the mode set for displaying of MasterViewController and DetailViewController
. self.presentsWithGesture enables swipe gesture for displaying MasterViewController
MasterViewController.h
#import <UIKit/UIKit.h>
MasterViewController.m
#import "MasterViewController.h"
@implementation MasterViewController
@synthesize detailDelegate;
-(void)viewDidLoad
{
[super viewDidLoad];
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1; //count of section
}
if (cell == nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:cellId];
}
[cell.contentView setBackgroundColor:[UIColor redColor]];
cell.textLabel.text =[NSString stringWithFormat:@"My VC at index %ld",(long)indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[detailDelegate sendSelectedNavController:[viewControllerArray objectAtIndex:indexPath.row]];
}
@end
Created some UIViewController and added it to an NSMutableArray. The UITableView is initialized then on
didselectrowatindexpath method I send a UIViewController to the DetailViewController using detailDelegate
delegate with the corresponding UIViewController in the NSMutableArray as a parameter
DetailViewController.h
#import <UIKit/UIKit.h>
DetailViewController.m
#import "DetailViewController.h"
@implementation DetailViewController
-(void)viewDidLoad
The sendSelectedNavController is declared here with removing all the UIView's in the DetailViewController and
adding the passed UIViewController from the MasterViewController.
The code above will change the font of the label to Helvetica Neue, size 15. Beware that you must spell the font
name correctly, otherwise it will throw this error, because the initialized value above is an Optional, and thus can be
nil:
import UIKit
extension UIDevice {
switch identifier {
case "iPod5,1": return "iPod Touch 5"
case "iPod7,1": return "iPod Touch 6"
case "iPhone3,1", "iPhone3,2", "iPhone3,3": return "iPhone 4"
case "iPhone4,1": return "iPhone 4s"
case "iPhone5,1", "iPhone5,2": return "iPhone 5"
case "iPhone5,3", "iPhone5,4": return "iPhone 5c"
case "iPhone6,1", "iPhone6,2": return "iPhone 5s"
case "iPhone7,2": return "iPhone 6"
case "iPhone7,1": return "iPhone 6 Plus"
case "iPhone8,1": return "iPhone 6s"
case "iPhone8,2": return "iPhone 6s Plus"
case "iPhone9,1", "iPhone9,3": return "iPhone 7"
case "iPhone9,2", "iPhone9,4": return "iPhone 7 Plus"
case "iPhone8,4": return "iPhone SE"
case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4":return "iPad 2"
case "iPad3,1", "iPad3,2", "iPad3,3": return "iPad 3"
case "iPad3,4", "iPad3,5", "iPad3,6": return "iPad 4"
case "iPad4,1", "iPad4,2", "iPad4,3": return "iPad Air"
case "iPad5,3", "iPad5,4": return "iPad Air 2"
case "iPad2,5", "iPad2,6", "iPad2,7": return "iPad Mini"
case "iPad4,4", "iPad4,5", "iPad4,6": return "iPad Mini 2"
case "iPad4,7", "iPad4,8", "iPad4,9": return "iPad Mini 3"
case "iPad5,1", "iPad5,2": return "iPad Mini 4"
case "iPad6,3", "iPad6,4", "iPad6,7", "iPad6,8":return "iPad Pro"
case "AppleTV5,3": return "Apple TV"
case "i386", "x86_64": return "Simulator"
default: return identifier
}
}
}
Swift 3
import UIKit
switch identifier {
case "iPod5,1": return "iPod Touch 5"
case "iPod7,1": return "iPod Touch 6"
case "iPhone3,1", "iPhone3,2", "iPhone3,3": return "iPhone 4"
case "iPhone4,1": return "iPhone 4s"
case "iPhone5,1", "iPhone5,2": return "iPhone 5"
case "iPhone5,3", "iPhone5,4": return "iPhone 5c"
case "iPhone6,1", "iPhone6,2": return "iPhone 5s"
case "iPhone7,2": return "iPhone 6"
case "iPhone7,1": return "iPhone 6 Plus"
case "iPhone8,1": return "iPhone 6s"
case "iPhone8,2": return "iPhone 6s Plus"
case "iPhone9,1", "iPhone9,3": return "iPhone 7"
case "iPhone9,2", "iPhone9,4": return "iPhone 7 Plus"
case "iPhone8,4": return "iPhone SE"
case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4":return "iPad 2"
case "iPad3,1", "iPad3,2", "iPad3,3": return "iPad 3"
case "iPad3,4", "iPad3,5", "iPad3,6": return "iPad 4"
case "iPad4,1", "iPad4,2", "iPad4,3": return "iPad Air"
case "iPad5,3", "iPad5,4": return "iPad Air 2"
case "iPad2,5", "iPad2,6", "iPad2,7": return "iPad Mini"
case "iPad4,4", "iPad4,5", "iPad4,6": return "iPad Mini 2"
case "iPad4,7", "iPad4,8", "iPad4,9": return "iPad Mini 3"
case "iPad5,1", "iPad5,2": return "iPad Mini 4"
case "iPad6,3", "iPad6,4", "iPad6,7", "iPad6,8":return "iPad Pro"
case "AppleTV5,3": return "Apple TV"
case "i386", "x86_64": return "Simulator"
default: return identifier
}
}
}
UIDeviceOrientationUnknown 0
UIDeviceOrientationPortrait 1
UIDeviceOrientationPortraitUpsideDown 2
UIDeviceOrientationLandscapeLeft 3
UIDeviceOrientationLandscapeRight 4
UIDeviceOrientationFaceUp 5
UIDeviceOrientationFaceDown 6
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(deviceOrientationDidChange)
name:UIDeviceOrientationDidChangeNotification
object:nil];
}
-(void)deviceOrientationDidChange
{
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation == UIDeviceOrientationPortrait || orientation ==
UIDeviceOrientationPortraitUpsideDown) {
[self changedToPortrait];
} else if (orientation == UIDeviceOrientationLandscapeLeft || orientation ==
UIDeviceOrientationLandscapeRight) {
[self changedToLandscape];
}
-(void)changedToPortrait
{
// Function Body
}
-(void)changedToLandscape
{
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
}
[myDevice setBatteryMonitoringEnabled:YES];
double batLeft = (float)[myDevice batteryLevel] * 100;
NSLog(@"%.f",batLeft);
int d = myDevice.batteryState;
//Returns an Integer Value
//UIDeviceBatteryStateUnknown 0
//UIDeviceBatteryStateUnplugged 1
//UIDeviceBatteryStateCharging 2
//UIDeviceBatteryStateFull 3
[super viewWillAppear:animated];
[[UIDevice currentDevice] setProximityMonitoringEnabled:YES];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sensorStateMonitor:)
name:@"UIDeviceProximityStateDidChangeNotification" object:nil];
}
- (void)sensorStateMonitor:(NSNotificationCenter *)notification
{
if ([[UIDevice currentDevice] proximityState] == YES)
{
NSLog(@"Device is close to user.");
}
else
{
NSLog(@"Device is not closer to user.");
}
}
// Stuff...
}
Here is the function which does the heavy lifting and rounds off the selected edges which is the Bottom Right and
the Top Right edge in our case
- (void)setMaskTo:(UIView*)view byRoundingCorners:(UIRectCorner)corners
{
UIBezierPath *rounded = [UIBezierPath bezierPathWithRoundedRect:view.bounds
byRoundingCorners:corners
cornerRadii:CGSizeMake(20.0, 20.0)];
CAShapeLayer *shape = [[CAShapeLayer alloc] init];
[shape setPath:rounded.CGPath];
view.layer.mask = shape;
}
Give your XIB a name (yes, we are doing a Pokemon example ????).
Remember to check your target and hit "Create".
Size: Freeform
Status Bar: None
Top Bar: None
Bottom Bar: None
Drop some elements into your XIB file like shown below.
Here we'll be adding an Image View (256x256) and a Switch.
Preview the changes you made by clicking on "Show the Assistant Editor" (top-right), then "Preview".
You can add iPhone screens by clicking on the "Plus" button.
The preview should look like this:
POKEMONS!!!
Yes! Drag and drop some Pokemons into your project to finish up our "infrastructure".
Here we are adding two PGN files, 256x256, transparent.
import UIKit
// MARK: - Initializers
// Auto-layout stuff.
view.autoresizingMask = [
UIViewAutoresizing.flexibleWidth,
UIViewAutoresizing.flexibleHeight
]
return view
}
}
By adding @IBDesignable to your class, you make possible for it to live-render in Interface Builder.
By adding @IBInspectable to the properties of your class, you can see your custom views changing in Interface
Builder as soon as you modify those properties.
First, hook up the Image View from the Pokemon.xib file to the Pokemon.swift class.
Call the outlet imageView and then add the following code (notice the @IBDesignable before the class name):
// MARK: - Initializers
...
To select a Pokemon, go to the Attribute Inspector (top-right) and select one of the Pokemon images you previously
added using the awesome @IBInspectable image property.
Now we are going to add more logic to that self-containing custom UI element.
The button will allow Pokemons to be enabled/disabled.
// MARK: - Actions
// MARK: - Initializers
...
Final result:
This is not a complex operation but exact steps need to be followed in order to do it right way first time, avoiding
exceptions.
1. Create XIB
2. Create class .h and .m
3. Define outlets in .h
4. Connect outlets between .h and XIB
5. Invoke loadNibNamed inside initWithCoder function of .m file. This is needed to ensure you can directly place
UIView object into storyboard / Parent UIView XIB file and define it as your custom view. No other
initialization code is needed once you load the storyboard / parent XIB. Your custom view can be added to
other views just like other built-in Objective C view objects given in XCode.
You could do anything, but as an example I have chosen the shape below. It could be a popup key on a keyboard.
Look back at your shape design and break it down into simpler elements of lines (for straight lines), arcs (for circles
and round corners), and curves (for anything else).
We'll arbitrarily start in the bottom left corner and work clockwise. I'll use the grid in the image to get the x and y
values for the points. I'll hardcode everything here, but of course you wouldn't do that in a real project.
line: addLineToPoint
arc: addArcWithCenter
curve: addCurveToPoint
// *********************
// ***** Left side *****
// *********************
// segment 1: line
path.addLineToPoint(CGPoint(x: 2, y: 15))
// segment 2: curve
path.addCurveToPoint(CGPoint(x: 0, y: 12), // ending point
controlPoint1: CGPoint(x: 2, y: 14),
controlPoint2: CGPoint(x: 0, y: 14))
// segment 3: line
path.addLineToPoint(CGPoint(x: 0, y: 2))
// *********************
// ****** Top side *****
// *********************
// segment 4: arc
path.addArcWithCenter(CGPoint(x: 2, y: 2), // center point of circle
radius: 2, // this will make it meet our path line
startAngle: CGFloat(M_PI), // ? radians = 180 degrees = straight left
endAngle: CGFloat(3*M_PI_2), // 3?/2 radians = 270 degrees = straight up
clockwise: true) // startAngle to endAngle goes in a clockwise direction
// segment 5: line
path.addLineToPoint(CGPoint(x: 8, y: 0))
// segment 6: arc
path.addArcWithCenter(CGPoint(x: 8, y: 2),
radius: 2,
startAngle: CGFloat(3*M_PI_2), // straight up
endAngle: CGFloat(0), // 0 radians = straight right
clockwise: true)
// *********************
// ***** Right side ****
// *********************
// segment 7: line
path.addLineToPoint(CGPoint(x: 10, y: 12))
// segment 8: curve
path.addCurveToPoint(CGPoint(x: 8, y: 15), // ending point
controlPoint1: CGPoint(x: 10, y: 14),
controlPoint2: CGPoint(x: 8, y: 14))
// segment 9: line
path.addLineToPoint(CGPoint(x: 8, y: 26))
// *********************
// **** Bottom side ****
// *********************
Note: Some of the above code can be reduced by adding a line and an arc in a single command (since the arc has
an implied starting point). See here for more details.
Our custom class looks like this. We add our Bezier path to a new CAShapeLayer when the view is initialized.
import UIKit
class MyCustomView: UIView {
func setup() {
// Create a CAShapeLayer
let shapeLayer = CAShapeLayer()
We get...
Hmm, that's a little small because I hardcoded all the numbers in. I can scale the path size up, though, like this:
Using drawRect is slower than drawing to the layer, so this is not the recommended method if you don't need it.
import UIKit
class MyCustomView: UIView {
// fill
let fillColor = UIColor.whiteColor()
fillColor.setFill()
// stroke
path.lineWidth = 1.0
let strokeColor = UIColor.blueColor()
Further study
Thinking like a Bézier path (Everything I've ever read from this author is good and the inspiration for my
example above came from here.)
Coding Math: Episode 19 - Bezier Curves (entertaining and good visual illustrations)
Bezier Curves (how they are used in graphics applications)
Bezier Curves (good description of how the mathematical formulas are derived)
Notes
CGContextSaveGState(context);
UIRectClip(rectanglePath.bounds);
CGContextSetShadowWithColor(context, CGSizeZero, 0, NULL);
[opaqueShadow setFill];
[rectanglePath fill];
CGContextEndTransparencyLayer(context);
}
CGContextEndTransparencyLayer(context);
CGContextRestoreGState(context);
Swift:
Swift:
Swift:
[UIColor.grayColor setFill];
[ovalPath fill];
Swift:
UIColor.grayColor().setFill()
ovalPath.fill()
Swift:
- (void)drawRect:(CGRect)frame
{
UIBezierPath* rectanglePath = [UIBezierPath bezierPathWithRect:
CGRectMake(CGRectGetMinX(frame), CGRectGetMinY(frame), CGRectGetWidth(frame),
CGRectGetHeight(frame))];
- (void)drawRect:(CGRect)rect {
// 1. context
CGContextRef cxtRef = UIGraphicsGetCurrentContext();
// 2. create path
CGFloat endAngle = obj.floatValue / 100 * M_PI * 2 + startAngle;
UIBezierPath *circlePath = [UIBezierPath bezierPathWithArcCenter:center radius:radius
startAngle:startAngle endAngle:endAngle clockwise:YES];
[circlePath addLineToPoint:center];
// 3. add path
CGContextAddPath(cxtRef, circlePath.CGPath);
// set color
[[UIColor colorWithRed:((float)arc4random_uniform(256) / 255.0)
green:((float)arc4random_uniform(256) / 255.0) blue:((float)arc4random_uniform(256) / 255.0)
alpha:1.0] setFill];
// 4. render
CGContextDrawPath(cxtRef, kCGPathFill);
// reset angle
startAngle = endAngle;
}];
}
column view
- (void)drawRect:(CGRect)rect {
// 1.
CGContextRef cxtRef = UIGraphicsGetCurrentContext();
NSInteger columnCount = 7;
CGFloat width = self.bounds.size.width / (columnCount + columnCount - 1);
for (NSInteger i = 0; i < columnCount; i++) {
// 2.
CGFloat height = [data[i] floatValue] / 1000 * self.bounds.size.height; // floatValue
CGFloat x = 0 + width * (2 * i);
CGFloat y = self.bounds.size.height - height;
UIBezierPath *rectPath = [UIBezierPath bezierPathWithRect:CGRectMake(x, y, width, height)];
// 3.
[[UIColor colorWithRed:((float)arc4random_uniform(256) / 255.0)
green:((float)arc4random_uniform(256) / 255.0) blue:((float)arc4random_uniform(256) / 255.0)
alpha:1.0] setFill];
CGContextDrawPath(cxtRef, kCGPathFill);
}
}
//MARK: UIPickerViewDelegate
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) ->
String? {
return self.pickerViewRows[row]
}
//MARK: UIPickerViewDataSource
Objective-C
@property (nonatomic,strong) UIPickerView *countryPicker;
@property (nonatomic,strong) NSArray *countryNames;
- (void)viewDidLoad {
[super viewDidLoad];
_countryNames = @[@"Australia (AUD)", @"China (CNY)",
@"France (EUR)", @"Great Britain (GBP)", @"Japan (JPY)",@"INDIA
(IN)",@"AUSTRALIA (AUS)",@"NEW YORK (NW)"];
[self pickcountry];
}
-(void)pickcountry {
_countryPicker = [[UIPickerView alloc]init];
_countryPicker.delegate = self;
_countryPicker.dataSource = self;
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 1;
}
//Displays the country pickerView with black background and white text
[self. countryPicker setValue:[UIColor whiteColor] forKey:@"textColor"];
[self. countryPicker setValue:[UIColor blackColor] forKey:@"backgroundColor"];
Swift
Swift
class ViewController: UIViewController
{
lazy var button: UIButton =
{
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(button)
button.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
button.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
button.setTitle("Impact", for: .normal)
button.setTitleColor(UIColor.gray, for: .normal)
return button
}()
Objective-C
@interface ViewController ()
@property (nonatomic, strong) UIImpactFeedbackGenerator *impactFeedbackGenerator;
@property (nonatomic, strong) UIButton *button;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self.button addTarget:self action:@selector(didPressButton:)
- (void)didPressButton:(UIButton *)sender
{
// Triggers haptic
[self.impactFeedbackGenerator impactOccurred];
}
@end
Swift:
UIButton.appearance().tintColor = UIColor.greenColor()
Objective-C:
Swift:
UIButton.appearance().backgroundColor = UIColor.blueColor()
Objective-C:
Swift:
UILabel.appearance().textColor = UIColor.redColor()
Objective-C:
Swift:
UILabel.appearance().backgroundColor = UIColor.greenColor()
Objective-C:
Swift:
UINavigationBar.appearance().tintColor = UIColor.cyanColor()
Objective-C:
Swift:
UINavigationBar.appearance().backgroundColor = UIColor.redColor()
Objective-C:
Swift:
UILabel.appearanceWhenContainedInInstancesOfClasses([ViewController.self]).textColor =
UIColor.whiteColor()
Objective-C:
Swift:
UILabel.appearanceWhenContainedInInstancesOfClasses([ViewController.self]).backgroundColor =
UIColor.blueColor()
Objective-C:
Swift
final class RectangleAttachmentBehavior: UIDynamicBehavior
{
init(item: UIDynamicItem, point: CGPoint)
{
// Higher frequency more "ridged" formation
let frequency: CGFloat = 8.0
super.init()
attachmentBehaviors.forEach
{
addChildBehavior($0)
}
}
Objective-C
- (instancetype)initWithItem:(id<UIDynamicItem>)item point:(CGPoint)point
{
CGFloat frequency = 8.0f;
CGFloat damping = 0.6f;
self = [super init];
if (self)
{
NSArray <NSValue *> *pointValues = [self attachmentPointValuesForPoint:point];
for (NSValue *value in pointValues)
{
UIAttachmentBehavior *attachment = [[UIAttachmentBehavior alloc]initWithItem:item
attachedToAnchor:[value CGPointValue]];
attachment.frequency = frequency;
attachment.damping = damping;
[self addChildBehavior:attachment];
}
}
return self;
}
- (void)updateAttachmentLocationWithPoint:(CGPoint)point
{
NSArray <NSValue *> *pointValues = [self attachmentPointValuesForPoint:point];
for (NSInteger i = 0; i < pointValues.count; i++)
{
NSValue *pointValue = pointValues[i];
UIAttachmentBehavior *attachment = self.childBehaviors[i];
attachment.anchorPoint = [pointValue CGPointValue];
}
}
@end
Next we can create the high-level behavior that will combine a number of RectangleAttachmentBehavior.
Swift
final class DragBehavior: UIDynamicBehavior
{
init(items: [UIDynamicItem], point: CGPoint)
{
super.init()
items.forEach
{
Objective-C
@implementation DragBehavior
- (void)updateDragLocationWithPoint:(CGPoint)point
{
for (RectangleAttachmentBehavior *rectAttachment in self.childBehaviors)
{
[rectAttachment updateAttachmentLocationWithPoint:point];
}
}
@end
Now with our behaviors in place, the next step is to add them to our collection view when. Because normally we
want a standard grid layout we can subclass UICollectionViewFlowLayout and only change attributes when
dragging. We do this mainly through overriding layoutAttributesForElementsInRect and using the
UIDynamicAnimator's convenience method itemsInRect.
Swift
final class DraggableLayout: UICollectionViewFlowLayout
{
// Array that holds dragged index paths
var indexPathsForDraggingElements: [IndexPath]?
// Get all of the draggable attributes but change zIndex so above other cells
let draggableAttributes: [UICollectionViewLayoutAttributes] = selectedIndexPaths.flatMap {
let attribute = super.layoutAttributesForItem(at: $0)
attribute?.zIndex = 1
return attribute
}
startDragPoint = point
func endDragging()
{
isFinishedDragging = true
func clearDraggedIndexPaths()
{
// Reset state for next drag event
animator = nil
indexPathsForDraggingElements = nil
isFinishedDragging = false
}
Objective-C
@interface DraggableLayout () <UIDynamicAnimatorDelegate>
@property (nonatomic, strong) NSArray <NSIndexPath *> *indexPathsForDraggingElements;
@property (nonatomic, strong) UIDynamicAnimator *animator;
@property (nonatomic, assign) CGPoint startDragPoint;
@property (nonatomic, assign) BOOL finishedDragging;
@property (nonatomic, strong) DragBehavior *dragBehavior;
@end
@implementation DraggableLayout
- (void)updateDragLoactionWithPoint:(CGPoint)point
{
[self.dragBehavior updateDragLocationWithPoint:point];
}
- (void)endDragging
{
self.finishedDragging = YES;
- (void)clearDraggedIndexPath
{
self.animator = nil;
self.indexPathsForDraggingElements = nil;
self.finishedDragging = NO;
}
- (void)dynamicAnimatorDidPause:(UIDynamicAnimator *)animator
{
if (self.finishedDragging)
{
[self clearDraggedIndexPath];
}
}
@end
Finally, we'll create a view controller that will create our UICollectionView and handle our long press gesture.
Swift
final class ViewController: UIViewController
{
// Collection view that displays cells
lazy var collectionView: UICollectionView =
{
let collectionView = UICollectionView(frame: .zero, collectionViewLayout:
DraggableLayout())
collectionView.backgroundColor = .white
collectionView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(collectionView)
collectionView.topAnchor.constraint(equalTo: self.topLayoutGuide.bottomAnchor).isActive =
true
collectionView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
collectionView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
collectionView.bottomAnchor.constraint(equalTo: self.bottomLayoutGuide.topAnchor).isActive
= true
return collectionView
}()
Objective-C
@interface ViewController () <UICollectionViewDelegate, UICollectionViewDataSource>
@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, strong) UILongPressGestureRecognizer *longPress;
@property (nonatomic, strong) NSMutableArray <NSIndexPath *> *selectedIndexPaths;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.collectionView.delegate = self;
self.collectionView.dataSource = self;
[self.collectionView registerClass:[UICollectionViewCell class]
forCellWithReuseIdentifier:@"Cell"];
[self.collectionView addGestureRecognizer:self.longPress];
self.selectedIndexPaths = [[NSMutableArray alloc]init];
}
- (UICollectionView *)collectionView
{
if (!_collectionView)
{
_collectionView = [[UICollectionView alloc]initWithFrame:CGRectZero
collectionViewLayout:[[DraggableLayout alloc]init]];
_collectionView.backgroundColor = [UIColor whiteColor];
_collectionView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:_collectionView];
[_collectionView.topAnchor constraintEqualToAnchor:self.topLayoutGuide.bottomAnchor].active
= YES;
[_collectionView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active =
YES;
[_collectionView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active =
YES;
[_collectionView.bottomAnchor
constraintEqualToAnchor:self.bottomLayoutGuide.topAnchor].active = YES;
}
return _collectionView;
}
- (UILongPressGestureRecognizer *)longPress
{
if (!_longPress)
{
_longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self
action:@selector(handleLongPress:)];
}
return _longPress;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView
numberOfItemsInSection:(NSInteger)section
{
return 1000;
}
@end
For more information 2013 WWDC Session "Advanced Techniques with UIKit Dynamics"
https://github.com/MKGitHub/UIPheonix
// connect model-view
mUIPheonix.setModelViewRelationships([MyModel.nameOfClass:MyView.nameOfClass])
// render, update UI
mUIPheonix.setDisplayModels(models)
Swift
class ViewController: UIViewController
{
// Adjust to change speed of view from flick
let magnitudeMultiplier: CGFloat = 0.0008
Objective-C
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self.dynamicAnimator addBehavior:self.gravity];
[self.dynamicAnimator addBehavior:self.collision];
[self.orangeView addGestureRecognizer:self.panGesture];
// Adjust to change speed of view from flick
self.magnitudeMultiplier = 0.0008f;
}
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
self.orangeView.center = self.view.center;
[self.dynamicAnimator updateItemUsingCurrentState:self.orangeView];
}
- (void)handlePan:(UIPanGestureRecognizer *)sender
{
CGPoint location = [sender locationInView:self.view];
CGPoint velocity = [sender velocityInView:self.view];
CGFloat magnitude = sqrt((velocity.x * velocity.x) + (velocity.y * velocity.y));
if (sender.state == UIGestureRecognizerStateBegan)
{
self.attachment.anchorPoint = location;
[self.dynamicAnimator addBehavior:self.attachment];
}
else if (sender.state == UIGestureRecognizerStateChanged)
{
self.attachment.anchorPoint = location;
}
else if (sender.state == UIGestureRecognizerStateCancelled ||
sender.state == UIGestureRecognizerStateEnded ||
sender.state == UIGestureRecognizerStateFailed ||
sender.state == UIGestureRecognizerStatePossible)
{
UIPushBehavior *push = [[UIPushBehavior alloc] initWithItems:@[self.orangeView]
mode:UIPushBehaviorModeInstantaneous];
push.pushDirection = CGVectorMake(velocity.x, velocity.y);
push.magnitude = magnitude * self.magnitudeMultiplier;
[self.dynamicAnimator removeBehavior:self.attachment];
[self.dynamicAnimator addBehavior:push];
}
}
- (UICollisionBehavior *)collision
{
if (!_collision)
{
_collision = [[UICollisionBehavior alloc]initWithItems:@[self.orangeView]];
_collision.translatesReferenceBoundsIntoBoundary = YES;
}
return _collision;
}
- (UIView *)orangeView
{
if (!_orangeView)
{
CGFloat widthHeight = 40.0f;
_orangeView = [[UIView alloc]initWithFrame:CGRectMake(0.0, 0.0, widthHeight, widthHeight)];
_orangeView.backgroundColor = [UIColor orangeColor];
[self.view addSubview:_orangeView];
}
return _orangeView;
}
- (UIPanGestureRecognizer *)panGesture
{
if (!_panGesture)
{
_panGesture = [[UIPanGestureRecognizer alloc]initWithTarget:self
action:@selector(handlePan:)];
}
return _panGesture;
}
- (UIAttachmentBehavior *)attachment
{
if (!_attachment)
{
_attachment = [[UIAttachmentBehavior alloc]initWithItem:self.orangeView
attachedToAnchor:CGPointZero];
}
return _attachment;
}
@end
orangeView.addGestureRecognizer(panGesture)
}
orangeView.center = view.center
dynamicAnimator.updateItem(usingCurrentState: orangeView)
Objective-C
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self.dynamicAnimator addBehavior:self.collision];
[self.dynamicAnimator addBehavior:self.itemBehavior];
for (UIFieldBehavior *field in self.fieldBehaviors)
{
[self.dynamicAnimator addBehavior:field];
}
[self.orangeView addGestureRecognizer:self.panGesture];
}
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
self.orangeView.center = self.view.center;
[self.dynamicAnimator updateItemUsingCurrentState:self.orangeView];
- (void)handlePan:(UIPanGestureRecognizer *)sender
{
CGPoint location = [sender locationInView:self.view];
CGPoint velocity = [sender velocityInView:self.view];
if (sender.state == UIGestureRecognizerStateBegan)
{
self.attachment.anchorPoint = location;
[self.dynamicAnimator addBehavior:self.attachment];
}
else if (sender.state == UIGestureRecognizerStateChanged)
{
self.attachment.anchorPoint = location;
}
else if (sender.state == UIGestureRecognizerStateCancelled ||
- (UICollisionBehavior *)collision
{
if (!_collision)
{
_collision = [[UICollisionBehavior alloc]initWithItems:@[self.orangeView]];
_collision.translatesReferenceBoundsIntoBoundary = YES;
}
return _collision;
}
- (UIDynamicItemBehavior *)itemBehavior
{
if (!_itemBehavior)
{
_itemBehavior = [[UIDynamicItemBehavior alloc]initWithItems:@[self.orangeView]];
// Adjust these values to change the "stickiness" of the view
_itemBehavior.density = 0.01;
_itemBehavior.resistance = 10;
_itemBehavior.friction = 0.0;
_itemBehavior.allowsRotation = NO;
}
return _itemBehavior;
}
- (UIView *)orangeView
{
if (!_orangeView)
- (UIPanGestureRecognizer *)panGesture
{
if (!_panGesture)
{
_panGesture = [[UIPanGestureRecognizer alloc]initWithTarget:self
action:@selector(handlePan:)];
}
return _panGesture;
}
- (UIAttachmentBehavior *)attachment
{
if (!_attachment)
{
_attachment = [[UIAttachmentBehavior alloc]initWithItem:self.orangeView
attachedToAnchor:CGPointZero];
}
return _attachment;
}
@end
For more information about UIFieldBehaviors you can see the 2015 WWDC Session "What's New in UIKit
Dynamics and Visual Effects" and accompanying sample code.
This example shows how to create a custom presentation transition that is driven by a composite
UIDynamicBehavior. We can start by creating a presenting view controller that will present a modal.
Swift
class PresentingViewController: UIViewController
{
return button
}()
func didPressPresent()
{
let modal = ModalViewController()
modal.view.frame = CGRect(x: 0.0, y: 0.0, width: 200.0, height: 200.0)
modal.modalPresentationStyle = .custom
modal.transitioningDelegate = modal
self.present(modal, animated: true)
}
}
Objective-C
@interface PresentingViewController ()
@property (nonatomic, strong) UIButton *button;
@end
@implementation PresentingViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self.button addTarget:self action:@selector(didPressPresent)
forControlEvents:UIControlEventTouchUpInside];
}
- (void)didPressPresent
{
ModalViewController *modal = [[ModalViewController alloc] init];
modal.view.frame = CGRectMake(0.0, 0.0, 200.0, 200.0);
modal.modalPresentationStyle = UIModalPresentationCustom;
modal.transitioningDelegate = modal;
[self presentViewController:modal animated:YES completion:nil];
}
- (UIButton *)button
{
if (!_button)
{
_button = [[UIButton alloc] init];
_button.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:_button];
[_button.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor].active = YES;
[_button.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor].active = YES;
@end
When the present button is tapped, we create a ModalViewController and set its presentation style to .custom and
set its transitionDelegate to itself. This will allow us to vend an animator that will drive its modal transition. We
also set modal's view's frame so it will be smaller than the full screen.
Swift
class ModalViewController: UIViewController
{
lazy var button: UIButton =
{
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(button)
button.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive
= true
button.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
button.setTitle("Dismiss", for: .normal)
button.setTitleColor(.white, for: .normal)
return button
}()
func didPressDismiss()
{
dismiss(animated: true)
}
}
Objective-C
@implementation ModalViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self.button addTarget:self action:@selector(didPressPresent)
forControlEvents:UIControlEventTouchUpInside];
self.view.backgroundColor = [UIColor redColor];
self.view.layer.cornerRadius = 15.0f;
}
- (void)didPressPresent
{
[self dismissViewControllerAnimated:YES completion:nil];
}
- (UIButton *)button
{
if (!_button)
{
_button = [[UIButton alloc] init];
_button.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:_button];
[_button.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor].active = YES;
[_button.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor].active = YES;
[_button setTitle:@"Dismiss" forState:UIControlStateNormal];
[_button setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
}
return _button;
}
-
(id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewControl
ler *)presented presentingController:(UIViewController *)presenting
sourceController:(UIViewController *)source
{
return [[DropOutAnimator alloc]initWithDuration: 1.5 appearing:YES];
}
-
(id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewControl
ler *)dismissed
{
return [[DropOutAnimator alloc] initWithDuration:4.0 appearing:NO];
}
@end
Here we create the view controller that is presented. Also because ModalViewController is it's own
transitioningDelegate it is also responsible for vending an object that will manage its transition animation. For us
that means passing on an instance of our composite UIDynamicBehavior subclass.
Our animator will have two different transitions: one for presenting and one for dismissing. For presenting, the
presenting view controller's view will drop in from above. And for dismissing, the view will seem to swing from a
rope and then drop out. Because DropOutAnimator conforms to UIViewControllerAnimatedTransitioning most of
this work will be done in its implementation of func animateTransition(using transitionContext:
Swift
class DropOutAnimator: UIDynamicBehavior
{
let duration: TimeInterval
let isAppearing: Bool
// Presenting Animation
if self.isAppearing
{
fromView.isUserInteractionEnabled = false
containerView.addSubview(toView)
// Set collision bounds to include off-screen view and have collision in center
// where our final view should come to rest
let collisionBehavior = UICollisionBehavior(items: [toView])
let insets = UIEdgeInsets(top: toViewInitialFrame.minY, left: 0.0, bottom:
fromViewInitialFrame.height * 0.5 - toViewInitialFrame.height * 0.5, right: 0.0)
collisionBehavior.setTranslatesReferenceBoundsIntoBoundary(with: insets)
self.collisionBehavior = collisionBehavior
// Keep track of finish time in case we need to end the animator befor the animator
pauses
self.finishTime = duration + (self.animator?.elapsedTime ?? 0.0)
// Collision boundary is set to have a floor just below the bottom of the screen
let collisionBehavior = UICollisionBehavior(items: [fromView])
let insets = UIEdgeInsets(top: 0.0, left: -1000, bottom: -225, right: -1000)
collisionBehavior.setTranslatesReferenceBoundsIntoBoundary(with: insets)
self.collisionBehavior = collisionBehavior
self.transitionContext?.completeTransition(!(self.transitionContext?.transitionWasCancelled ??
false))
self.childBehaviors.forEach { self.removeChildBehavior($0) }
self.transitionContext?.completeTransition(!(self.transitionContext?.transitionWasCancelled ??
false))
self.childBehaviors.forEach { self.removeChildBehavior($0) }
animator.removeAllBehaviors()
self.transitionContext = nil
}
}
}
}
Objective-C
@interface ObjcDropOutAnimator() <UIDynamicAnimatorDelegate, UIViewControllerAnimatedTransitioning>
@property (nonatomic, strong) id<UIViewControllerContextTransitioning> transitionContext;
@property (nonatomic, strong) UIDynamicAnimator *animator;
@property (nonatomic, assign) NSTimeInterval finishTime;
@property (nonatomic, assign) BOOL elapsedTimeExceededDuration;
@property (nonatomic, assign, getter=isAppearing) BOOL appearing;
@property (nonatomic, assign) NSTimeInterval duration;
@property (nonatomic, strong) UIAttachmentBehavior *attachBehavior;
@property (nonatomic, strong) UICollisionBehavior * collisionBehavior;
@end
@implementation ObjcDropOutAnimator
- (instancetype)initWithDuration:(NSTimeInterval)duration appearing:(BOOL)appearing
{
self = [super init];
if (self)
{
_duration = duration;
_appearing = appearing;
}
return self;
}
- (void) animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
// Get relevant views and view controllers from transitionContext
UIViewController *fromVC = [transitionContext
// Presenting Animation
if (self.isAppearing)
{
fromView.userInteractionEnabled = NO;
[containerView addSubview:toView];
// Set collision bounds to include off-screen view and have collision floor in center
// where our final view should come to rest
UICollisionBehavior *collisionBehavior = [[UICollisionBehavior
alloc]initWithItems:@[toView]];
UIEdgeInsets insets = UIEdgeInsetsMake(CGRectGetMinY(toViewInitialFrame), 0.0,
CGRectGetHeight(fromViewInitialFrame) * 0.5 - CGRectGetHeight(toViewInitialFrame) * 0.5, 0.0);
[collisionBehavior setTranslatesReferenceBoundsIntoBoundaryWithInsets:insets];
self.collisionBehavior = collisionBehavior;
// Keep track of finish time in case we need to end the animator befor the animator pauses
self.finishTime = duration + self.animator.elapsedTime;
// Collision boundary is set to have a floor just below the bottom of the screen
UICollisionBehavior *collisionBehavior = [[UICollisionBehavior alloc]
initWithItems:@[fromView]];
UIEdgeInsets insets = UIEdgeInsetsMake(0, -1000, -225, -1000);
[collisionBehavior setTranslatesReferenceBoundsIntoBoundaryWithInsets:insets];
self.collisionBehavior = collisionBehavior;
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
return self.duration;
}
- (void)dynamicAnimatorDidPause:(UIDynamicAnimator *)animator
{
// Animator has reached stasis
if (self.isAppearing)
{
// Check if we are out of time
if (self.elapsedTimeExceededDuration)
{
// Move to final positions
UIView *toView = [self.transitionContext
viewControllerForKey:UITransitionContextToViewControllerKey].view;
UIView *containerView = [self.transitionContext containerView];
toView.center = containerView.center;
self.elapsedTimeExceededDuration = NO;
}
[self.transitionContext completeTransition:![self.transitionContext
transitionWasCancelled]];
for (UIDynamicBehavior *behavior in self.childBehaviors)
{
[self removeChildBehavior:behavior];
}
[animator removeAllBehaviors];
self.transitionContext = nil;
}
}
}
As composite behavior, DropOutAnimator, can combine a number of different behaviors to perform its presenting
and dismissing animations. DropOutAnimator also demonstrates how to use the action block of a behavior to
inspect the locations of its items as well as the time elapsed a technique that can be used to remove views that
move offscreen or truncate animations that have yet to reach stasis.
For more information 2013 WWDC Session "Advanced Techniques with UIKit Dynamics" as well as
SOLPresentingFun
To start with, we need a presenting view controller that the shade will appear over. This view controller will also act
as our UIViewControllerTransitioningDelegate for our presented view controller and will vend animators for our
Swift
class ViewController: UIViewController
{
var presentingAnimator: ShadeAnimator!
var dismissingAnimator: ShadeAnimator!
let shadeVC = ShadeViewController()
Objective-C
@implementation ObjCViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.label.text = @"Swipe Down From Top";
self.shadeVC = [[ShadeViewController alloc] init];
self.presentingAnimator = [[ShadeAnimator alloc] initWithIsAppearing:YES presentingVC:self
presentedVC:self.shadeVC transitionDelegate:self];
self.dismissingAnimator = [[ShadeAnimator alloc] initWithIsAppearing:NO presentingVC:self
presentedVC:self.shadeVC transitionDelegate:self];
}
- (UILabel *)label
{
if (!_label)
{
_label = [[UILabel alloc] init];
_label.textColor = [UIColor blueColor];
_label.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:_label];
[_label.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor].active = YES;
[_label.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor].active = YES;
}
return _label;
}
-
(id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewControl
ler *)presented presentingController:(UIViewController *)presenting
sourceController:(UIViewController *)source
{
return [[EmptyAnimator alloc] init];
}
-
(id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewControl
ler *)dismissed
{
return [[EmptyAnimator alloc] init];
}
-
(id<UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id<UIViewContro
llerAnimatedTransitioning>)animator
{
return self.presentingAnimator;
}
-
(id<UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id<UIViewControlle
rAnimatedTransitioning>)animator
{
@end
We want really only ever want to present our shade through an interactive transition but because of how
UIViewControllerTransitioningDelegate works if we don't return a regular animation controller our interactive
controller will never be used. Because of that we create an EmptyAnimator class that conforms to
UIViewControllerAnimatedTransitioning.
Swift
class EmptyAnimator: NSObject
{
Objective-C
@implementation EmptyAnimator
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
return 0.0;
}
@end
Finally we need to actually create the ShadeAnimator which is a subclass of UIDynamicBehavior which conforms to
UIViewControllerInteractiveTransitioning.
Swift
class ShadeAnimator: UIDynamicBehavior
{
// Whether we are presenting or dismissing
let isAppearing: Bool
// The Pan Gesture that drives the transition. Not using EdgePan because triggers Notifications
screen
lazy var pan: UIPanGestureRecognizer =
{
let pan = UIPanGestureRecognizer(target: self, action: #selector(self.handlePan(sender:)))
return pan
}()
if isAppearing
{
self.presentingVC?.view.addGestureRecognizer(pan)
}
else
{
self.presentedVC?.view.addGestureRecognizer(pan)
}
// Setup and moves shade view controller to just above screen if appearing
func setupViewsForTransition(with transitionContext: UIViewControllerContextTransitioning)
{
// Get relevant views and view controllers from transitionContext
guard let fromVC = transitionContext.viewController(forKey: .from),
let toVC = transitionContext.viewController(forKey: .to),
let toView = toVC.view else { return }
containerView.addSubview(toView)
}
else
{
fromVC.view.addGestureRecognizer(pan)
}
}
switch sender.state
{
case .began:
let beginLocation = sender.location(in: sender.view)
if isAppearing
{
guard beginLocation.y <= touchStartHeight,
let presentedVC = self.presentedVC else { break }
presentedVC.modalPresentationStyle = .custom
presentedVC.transitioningDelegate = transitionDelegate
presentingVC?.present(presentedVC, animated: true)
}
else
{
guard beginLocation.y >= (sender.view?.frame.height ?? 0.0) - touchStartHeight else
{ break }
presentedVC?.dismiss(animated: true)
}
case .changed:
guard let view = isAppearing ? toVC?.view : fromVC?.view else { return }
UIView.animate(withDuration: 0.2)
{
view.frame.origin.y = location.y - view.bounds.height + touchLocationFromBottom
}
transitionContext?.updateInteractiveTransition(view.frame.maxY / view.frame.height
)
case .ended, .cancelled:
guard let view = isAppearing ? toVC?.view : fromVC?.view else { return }
let isCancelled = isAppearing ? (velocity.y < 0.5 || view.center.y < 0.0) : (velocity.y
> 0.5 || view.center.y > 0.0)
addAttachmentBehavior(with: view, isCancelled: isCancelled)
addCollisionBehavior(with: view)
addItemBehavior(with: view)
self.action =
{ [weak self] in
guard let strongSelf = self else { return }
if strongSelf.animator.elapsedTime > strongSelf.finishTime
{
strongSelf.animator.removeAllBehaviors()
}
else
{
strongSelf.transitionContext?.updateInteractiveTransition(view.frame.maxY /
view.frame.height
)
}
}
default:
break
}
}
}
extension ShadeAnimator: UIDynamicAnimatorDelegate
Objective-C
@interface ShadeAnimator() <UIDynamicAnimatorDelegate, UICollisionBehaviorDelegate>
@property (nonatomic, assign) BOOL isAppearing;
@property (nonatomic, weak) UIViewController *presentingVC;
@property (nonatomic, weak) UIViewController *presentedVC;
@property (nonatomic, weak) NSObject<UIViewControllerTransitioningDelegate> *transitionDelegate;
@property (nonatomic, strong) UIImpactFeedbackGenerator *impactFeedbackGenerator;
@property (nonatomic, strong) id<UIViewControllerContextTransitioning> transitionContext;
@property (nonatomic, assign) NSTimeInterval finishTime;
@property (nonatomic, strong) UIPanGestureRecognizer *pan;
@property (nonatomic, strong) UIDynamicAnimator *animator;
@end
@implementation ShadeAnimator
- (UIDynamicAnimator *)animator
{
if (!_animator)
{
_animator = [[UIDynamicAnimator
alloc]initWithReferenceView:self.transitionContext.containerView];
}
return _animator;
}
[containerView addSubview:toView];
}
else
{
[fromVC.view addGestureRecognizer:self.pan];
}
}
if (sender.state == UIGestureRecognizerStateBegan)
{
CGPoint beginLocation = [sender locationInView:sender.view];
if (self.isAppearing)
{
if (beginLocation.y <= touchStartHeight)
{
self.presentedVC.modalPresentationStyle = UIModalPresentationCustom;
self.presentedVC.transitioningDelegate = self.transitionDelegate;
[self.presentingVC presentViewController:self.presentedVC animated:YES
completion:nil];
}
}
else
{
if (beginLocation.y >= [sender locationInView:sender.view].y - touchStartHeight)
{
[self.presentedVC dismissViewControllerAnimated:true completion:nil];
}
}
}
else if (sender.state == UIGestureRecognizerStateChanged)
{
UIView *view = self.isAppearing ? toVC.view : fromVC.view;
[UIView animateWithDuration:0.2 animations:^{
CGRect frame = view.frame;
frame.origin.y = location.y - CGRectGetHeight(view.bounds) + touchLocationFromBottom;
view.frame = frame;
}];
[self.transitionContext updateInteractiveTransition:CGRectGetMaxY(view.frame) /
CGRectGetHeight(view.frame)];
}
else if (sender.state == UIGestureRecognizerStateEnded || sender.state ==
UIGestureRecognizerStateCancelled)
{
UIView *view = self.isAppearing ? toVC.view : fromVC.view;
BOOL isCancelled = self.isAppearing ? (velocity.y < 0.5 || view.center.y < 0.0) :
(velocity.y > 0.5 || view.center.y > 0.0);
[self.animator addBehavior:self];
self.animator.delegate = self;
- (void)addItemBehaviorWithView:(UIView *)view
{
UIDynamicItemBehavior *itemBehavior = [[UIDynamicItemBehavior alloc]initWithItems:@[view]];
itemBehavior.allowsRotation = NO;
itemBehavior.elasticity = 0.6;
[self addChildBehavior:itemBehavior];
}
@end
The animator triggers the start of the transition when the pan gesture begins. And simply moves the view as the
gesture changes. But when the gesture ends that is when UIDynamicBehaviors determines if the transition should
be completed or cancelled. To do so it uses an attachment and collision behavior. For more information see the
2013 WWDC Session "Advanced Techniques with UIKit Dynamics.
To start we need to create a new protocol that implements UIDynamicItem but that also has a settable and gettable
bounds property.
Swift
protocol ResizableDynamicItem: UIDynamicItem
{
var bounds: CGRect { set get }
}
extension UIView: ResizableDynamicItem {}
Objective-C
We'll then create a wrapper object that will wrap a UIDynamicItem but will map center changes to the item's width
and height. We will also provide passthroughs for bounds and transform of the underlying item. This will cause any
changes the dynamic animator makes to the center x and y values of the underlying item will be applied to the
items width and height.
Swift
final class PositionToBoundsMapping: NSObject, UIDynamicItem
{
var target: ResizableDynamicItem
init(target: ResizableDynamicItem)
{
self.target = target
super.init()
}
set
{
self.target.bounds = CGRect(x: 0.0, y: 0.0, width: newValue.x, height: newValue.y)
}
}
set
{
self.target.transform = newValue
}
}
}
Objective-C
@interface PositionToBoundsMapping ()
@property (nonatomic, strong) id<ResizableDynamicItem> target;
@end
- (instancetype)initWithTarget:(id<ResizableDynamicItem>)target
{
self = [super init];
if (self)
{
_target = target;
}
return self;
}
- (CGRect)bounds
{
return self.target.bounds;
}
- (CGPoint)center
{
return CGPointMake(self.target.bounds.size.width, self.target.bounds.size.height);
}
- (void)setCenter:(CGPoint)center
{
self.target.bounds = CGRectMake(0, 0, center.x, center.y);
}
- (CGAffineTransform)transform
{
return self.target.transform;
}
- (void)setTransform:(CGAffineTransform)transform
{
self.target.transform = transform;
}
@end
Finally, we'll create a UIViewController that will have a button. When the button is pressed we will create
PositionToBoundsMapping with the button as the wrapped dynamic item. We create a UIAttachmentBehavior to it's
current position then add an instantaneous UIPushBehavior to it. However because we have mapped changes its
bounds, the button does not move but rather grows and shrinks.
Swift
final class ViewController: UIViewController
{
lazy var button: UIButton =
{
let button = UIButton(frame: CGRect(x: 0.0, y: 0.0, width: 300.0, height: 200.0))
button.backgroundColor = .red
button.layer.cornerRadius = 15.0
button.setTitle("Tap Me", for: .normal)
self.view.addSubview(button)
return button
}()
// Create mapping
let buttonBoundsDynamicItem = PositionToBoundsMapping(target: button)
// Change angle to determine how much height/ width should change 45° means heigh:width is
1:1
pushBehavior.angle = .pi / 4.0
Objective-C
@interface ViewController ()
@property (nonatomic, strong) UIButton *button;
@property (nonatomic, assign) CGRect buttonBounds;
@property (nonatomic, strong) UIDynamicAnimator *animator;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
self.button.center = self.view.center;
}
- (UIButton *)button
{
if (!_button)
{
_button = [[UIButton alloc]initWithFrame:CGRectMake(0.0, 0.0, 200.0, 200.0)];
_button.backgroundColor = [UIColor redColor];
_button.layer.cornerRadius = 15.0;
[_button setTitle:@"Tap Me" forState:UIControlStateNormal];
[self.view addSubview:_button];
}
return _button;
}
- (void)didTapButton:(id)sender
{
self.button.bounds = self.buttonBounds;
UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
PositionToBoundsMapping *buttonBoundsDynamicItem = [[PositionToBoundsMapping
alloc]initWithTarget:sender];
UIAttachmentBehavior *attachmentBehavior = [[UIAttachmentBehavior
alloc]initWithItem:buttonBoundsDynamicItem attachedToAnchor:buttonBoundsDynamicItem.center];
[attachmentBehavior setFrequency:2.0];
[attachmentBehavior setDamping:0.3];
[animator addBehavior:attachmentBehavior];
[pushBehavior setActive:TRUE];
self.animator = animator;
}
@end
Select storyboard.
Expand the Utilities
Select Identity Inspector
Select your element on storyboard
Add new Accessibility Identifier (in example addButton)
Select storyboard.
Expand the Utilities
Select Identity Inspector
Select your element on storyboard
Add attribute in User Defined Runtime Attributes
For Key Path type - accessibilityIdentifier
For Type - `String
For Value - new accessibility identifier for your element (in example view)
//Views
//Buttons
app.launch()
//Views
view = app.otherElements["view"]
//Buttons
addButton = app.buttons["addButton"]
}
func testMyApp() {
addButton.tap()
view.tap()
}
}
UILabel
let label = app.staticTexts["label"]
UIStackView
let stackView = app.otherElements["stackView"]
UITableView
let tableView = app.tables["tableView"]
UITableViewCell elements
let tableViewCellButton = tableView.cells.element(boundBy: 0).buttons["button"]
UICollectionView
let collectionView = app.collectionViews["collectionView"]
UIButton, UIBarButtonItem
let button = app.buttons["button"]
let barButtonItem = app.buttons["barButtonItem"]
UITextField
normal UITextField
password UITextField
UITextView
let textView = app.textViews["textView"]
UISwitch
let switch = app.switches["switch"]
Alerts
let alert = app.alerts["About yourself"] // Title of presented alert
If you missed checking UI target while creating project, you could always add test target later.
Setps:
app.launch()
}
Terminating application
func testStacOverFlowApp() {
app.terminate()
}
XCUIDevice.shared().orientation = .landscapeLeft
XCUIDevice.shared().orientation = .portrait
In Objective-C:
- (UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
In Swift:
In Objective-C:
- (UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
In Swift:
Objective C:
Swift
UIBarStyle options are default, black, blackOpaque, blackTranslucent. The latter 3 should all give you a status
bar with white text, just the last two specify the opacity of the bar.
Note: you can still change the appearance of your navigation bar as you like.
When you want a child viewController to control the presentation of the status bar (i.e. if the child is positioned at
the top of the screen
in Swift
setNeedsStatusBarAppearanceUpdate()
}
}
Section 61.5: Changing the status bar style for the entire
application
SWIFT:
Step 1:
NO
Step 2:
UIApplication.shared.statusBarStyle = .lightContent
or
UIApplication.shared.statusBarStyle = .default
The .lightContent option will set the colour of the statusBar to white, for the entire app.
The .default option will set the colour of the statusBar to the original black colour, for the entire app.
OBJECTIVE-C:
Follow the first step from the SWIFT Section. Then add this code to the AppDelegate.m file:
or
2. Setup frame;
mySegmentedControl.selectedSegmentIndex = 0
4. Configure target:
yourView.addSubview(mySegmentedControl)
This example assumes that you have made a segue in the Interface Builder and that you set the segue identifier to
showSecondViewController. The outlets and actions must also be hooked up to the names in the following code.
Swift
class FirstViewController: UIViewController, DataEnteredDelegate {
Objective-C
@implementation FirstViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
SecondViewController *secondViewController = segue.destinationViewController;
secondViewController.delegate = self;
}
-(void)userDidEnterInformation:(NSString *)info {
_label.text = info
[self.navigationController popViewControllerAnimated:YES];
}
@end
Swift
// protocol used for sending data back
protocol DataEnteredDelegate: class {
func userDidEnterInformation(info: String)
}
// making this a weak variable so that it won't create a strong reference cycle
weak var delegate: DataEnteredDelegate?
// call this method on whichever class implements our delegate protocol (the first view
controller)
delegate?.userDidEnterInformation(textField.text ?? "")
}
}
Objective-C
@protocol DataEnteredDelegate <NSObject>
-(void)userDidEnterInformation:(NSString *)info;
@end
@implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
Segues can be performed programatically or using button action event set in the storyboard by ctrl+drag to
destination view controller. You can call for a segue programatically, when needed, using segue identifier in the
view controller:
Objective-C
- (void)showDetail {
[self performSegueWithIdentifier:@"showDetailingSegue" sender:self];
}
Swift
func showDetail() {
self.performSegue(withIdentifier: "showDetailingSegue", sender: self)
}
You can configure segue payload in the overrided version of prepareForSegue method. You can set required
properties before destination view controller is loaded.
Objective-C
Swift
DetailViewController is the name of the second view controller and isDetailingEnabled is a public variable in
that view controller.
To expand on this pattern, you can treat a public method on DetailViewController as a pseudo initializer, to help
initialize any required variables. This will self document variables that need to be set on DetailViewController
without having to read through it's source code. It's also a handy place to put defaults.
Objective-C
- (void)initVC:(BOOL *)isDetailingEnabled {
self.isDetailingEnabled = isDetailingEnabled
}
Swift
Using "unwind" you can do the opposite, pass data from the destination or current view controller to its presenting
view controller:
NOTE: Pay attention that using unwind lets you pass the data first and afterwards the current view controller (VC2)
will get deallocated.
First, you will need to add the following declaration at the presenting view controller (VC1) which is the view
controller that we want to pass the data to:
The important thing is to use the prefix unwind, this "informs" Xcode that this is an unwind method giving you the
option to use it in storyboard as well.
Afterwards you will need to implement the method, it looks almost the same as an actual segue:
Release and you will have the option to choose your custom unwind method:
destinationController.onCompletion = { success in
// this will be executed when `someButtonTapped(_:)` will be called
This is an example of use and it's better to use on Swift, Objective-C block's syntax is not so easy to make the code
more readable
one thing this method is superior to delegate pattern is instead of split the setting up code in two different place(
look at delegate example on this page, prepareForSegue ,userDidEnterInformation ) rather gathering them
together( only in prepareForSegue, I'll show it )
we must figure out how to use callback, then can we write it, this is why we start from second view controller since
it's where we use callback: when we got the new text input, we call our callback, using callback's parameter as a
medium to passing data back to first ViewController, notice that I said using callback's parameter, this is very
important, novices(as I was) always overlook this and don't know where to start to write callback closure properly
so in this case, we know that our callback only take one parameter: text and its type is String, let's declare it and
make it property since we need populate from our first view controller
I just comment all the delegate part and keep it for comparing
//delegate?.userDidEnterInformation(textField.text!)
callback?(input.text)
self.navigationController?.popViewControllerAnimated(true)
}
}
all you have to do is passing callback closure, and we are done, closure will do the future work for us since we
already set it up in second view controller
look how it make our code shorter compared to the delegate pattern
and in the last, maybe someone of you will confused by the looking that we only passing the data(closure in this
case) only in one way, from first view controller to second, no directly coming back from second view controller,
how can we consider it as a communicating tool? maybe you really should run it and prove it yourself, all I will say
it's parameter, it's callback closure's parameter that passing data back!
func openSecondViewController() {
// Here we unwrapped the id and will get the data from the previous view controller.
if let id = id {
print("Id was set: \(id)")
}
}
}
This is a basic in-app keyboard. The same method could be used to make just about any keyboard layout. Here are
the main things that need to be done:
Create the keyboard layout in an .xib file, whose owner is a Swift or Objective-C class that is a UIView
subclass.
Tell the UITextField to use the custom keyboard.
Use a delegate to communicate between the keyboard and the main view controller.
In Xcode go to File > New > File... > iOS > User Interface > View to create the .xib file.
I called mine Keyboard.xib
Add the buttons that you need.
Use auto layout constraints so that no matter what size the keyboard is, the buttons will resize accordingly.
Set the File's Owner (not the root view) to be the Keyboard class. This is a common source of error. You'll
create this class in the next step. See the note at the end.
In Xcode go to File > New > File... > iOS > Source > Cocoa Touch Class to create the Swift or Objective-C
class. Choose UIView as a superclass for newly created class
import UIKit
func initializeSubviews() {
let xibFileName = "Keyboard" // xib extention not included
let view = NSBundle.mainBundle().loadNibNamed(xibFileName, owner: self, options:
nil)[0] as! UIView
self.addSubview(view)
view.frame = self.bounds
}
Keyboard.h File
#import <UIKit/UIKit.h>
Keyboard.m File
#import "Keyboard.h"
@implementation Keyboard
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
[self initializeSubviews];
return self;
}
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
[self initializeSubviews];
return self;
}
- (void)initializeSubviews {
NSString *xibFileName = @"Keyboard"; // xib extention not included
UIView *view = [[[NSBundle mainBundle] loadNibNamed:xibFileName owner:self options:nil]
firstObject];
[self addSubview:view];
view.frame = self.bounds;
}
-(IBAction)keyTapped:(UIButton *)sender {
// When a button is tapped, send that information to the
// delegate (ie, the view controller)
[self.delegate keyWasTapped:sender.titleLabel.text]; // could alternatively send a tag
value
}
@end
Control drag actions from the buttons to button callback in the .xib file to the @IBAction method in the Swift
or Objective-C owner to hook them all up.
Note that the protocol and delegate code. See this answer for a simple explanation about how delegates
work.
Add a UITextField to your main storyboard and connect it to your view controller with an IBOutlet. Call it
textField.
import UIKit
.h File
#import <UIKit/UIKit.h>
@end
.m File
#import "ViewController.h"
#import "Keyboard.h"
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
- (void)keyWasTapped:(NSString *)character {
[self.textField insertText:character];
}
@end
Common error
If you are getting an EXC_BAD_ACCESS error, it is probably because you set the view's custom class as Keyboard
rather than do this for the nib File's Owner.
Make sure that the custom class for the root view is blank.
Notes
- (void)viewDidLoad {
[super viewDidLoad];
txtSomeField.delegate = self
}
}
My problem was that I found myself writing this code again and again for every single ViewController. After
experimenting a bit I found using a Singleton + Delegate pattern allowed me to reuse a bunch of code and organize
all of the Keyboard Management in a single place!
class KeyboardManager {
init() {
NSNotificationCenter.defaultCenter().addObserver(self, selector:
#selector(KeyboardManager.keyboardWillChangeFrameNotification(_:)), name:
UIKeyboardWillChangeFrameNotification, object: nil)
}
Now when I want to manage the keyboard from a ViewController all I need to do is set the delegate to that
ViewController and implement any delegate methods.
This method is very customizable too! Say we want to add functionality for UIKeyboardWillHideNotification. This
is as easy as adding a method to our KeyboardManagerDelegate.
class KeyboardManager {
init() {
NSNotificationCenter.defaultCenter().addObserver(self, selector:
#selector(KeyboardManager.keyboardWillChangeFrameNotification(_:)), name:
UIKeyboardWillChangeFrameNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector:
#selector(KeyboardManager.keyboardWillHide(_:)), name: UIKeyboardWillHideNotification, object: nil)
}
*Note this pattern helps avoid overuse of @objc. See http://www.jessesquires.com/avoiding-objc-in-swift/ for more
details!
In summary, I've found using a Singleton + Delegate to manage the keyboard is both more efficient and easier to
use than using Notifications
In order for the view of a UIViewController to increase the origin of the frame when it is presented and decrease it
when it is hidden, add the following functions to your class:
And in the viewDidLoad() method of your class, add the following observers:
And this will work for any screen size, using the height property of the keyboard.
OBJECTIVE-C:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification
object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification
-(void)keyboardWillHide:(NSNotification *)notification
{
[UIView animateWithDuration:0.3 animations:^{
CGRect f = self.view.frame;
f.origin.y = 0.0f;
self.view.frame = f;
}];
}
1. You can subscribe for keyboard appearance events notifications and change offset manually:
//Swift 2.0+
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector:
#selector(YourVCClassName.keyboardWillShow(_:)), name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector:
#selector(YourVCClassName.keyboardWillHide(_:)), name: UIKeyboardWillHideNotification, object: nil)
}
//Objective-C
- (void)viewDidLoad {
[super viewDidLoad];
if (userInfo) {
CGRect keyboardEndFrame;
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardEndFrame.size.height, 0);
- (void)keyboardWillHide:(NSNotification *)notification {
if (netStatus == NotReachable) {
NSLog(@"Network unavailable");
}
}
switch (netStatus) {
case NotReachable:
NSLog(@"Network unavailable");
break;
case ReachableViaWWAN:
NSLog(@"Network is cellular");
break;
case ReachableViaWiFi:
NSLog(@"Network is WIFI");
break;
}
}
import SystemConfiguration
/**
Verify if the device is connected to internet network.
- returns: true if is connected to any internet network, false if is not
connected to any internet network.
*/
class func isConnectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
if !SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) {
return false
}
if NetworkHelper.isConnectedToNetwork() {
// Is connected to network
}
Objective-C:
-(BOOL)isConntectedToNetwork
{
Reachability *networkReachability = [Reachability reachabilityForInternetConnection];
NetworkStatus networkStatus = [networkReachability currentReachabilityStatus];
if (networkStatus == NotReachable)
{
NSLog(@"There IS NO internet connection");
return false;
} else
{
NSLog(@"There IS internet connection");
return true;
}
myView.isAccessibilityElement = YES;
Ensure that the view speaks a meaningful label, value, and hint. Apple provides more details on how to choose
good descriptions in the Accessibility Programming Guide.
myElement.accessibilityFrame = frameInScreenCoordinates;
If your elements or screen layouts change often, consider overriding -accessibilityFrame to always provide an up-
to-date rect. Calculating the screen-relative frame of scroll view subviews can be error-prone and tedious. iOS 10
introduces a new API to make this easier: accessibilityFrameInContainerSpace.
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, firstElement);
Each object in the array can be an instance of UIAccessibilityElement or any other class that adheres to
UIAccessibilityProtocol. The child elements should be returned in the order the user should navigate them. As
an application author, you can use accessibility containers to override the default top-left to bottom-right ordering
of VoiceOver swipe navigation. Given that UIView implements UIAccessibilityProtocol, you can combine
instances of UIAccessibilityElement and UIView in the same array of child accessibility elements. Note that if you
assign elements manually, you do not need to implement any dynamic accessibility protocol methods, though you
myViewFullofButtons.hidden = YES;
Alternatively, you can leave the parent view visible and simply hide its children from the accessibility hierarchy:
myViewFullofButtons.accessibilityElementsHidden = YES;
Temporary views are a another place you’ll want to hide elements from the accessibility hierarchy while leaving
them visible to users. For example, the view that pops up when you hit the volume button is visible to sighted users
but doesn’t demand attention the way a normal alert does. You wouldn’t want VoiceOver to interrupt the user and
move the cursor from away from whatever they were doing to announce the new volume, especially given that
adjusting volume already provides auditory feedback through the clicking sound it makes. In cases like this, you’ll
want to hide the view using accessibilityElementsHidden.
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, firstElement);
When this notification is posted, a short series of tones notify users of the change. The second parameter can be
either the next element to focus or a string announcing the change. Only post a screen change notification if the
VoiceOver experience is poor without it and no other workaround exists. Moving the VoiceOver cursor is like poking
at a sighted user’s screen. It can be annoying and disorienting to be led around that way.
If VoiceOver should read a view’s subviews one after the next but is not, you may need to hint to VoiceOver that the
elements contained within a single view are related. You can do this by setting shouldGroupAccessibiltyChildren:
myView.shouldGroupAccessibilityChildren = YES;
To support complex navigation structures that span multiple containers or include interfaces rendered without
UIKit, consider implementing the container protocol on the parent view.
myModalView.accessibilityViewIsModal = YES;
Tagging a view as modal encourages VoiceOver to ignore sibling views. If, after setting this property, you find that
VoiceOver still navigates other elements in your app, try hiding problem views until the modal dismisses.
It is common to want two views to be side by side, centered in their superview. The common answer given on Stack
Overflow is to embed these two views in a UIView and center the UIView. This is not necessary or recommended.
From the UILayoutGuide docs:
There are a number of costs associated with adding dummy views to your view hierarchy. First, there is
the cost of creating and maintaining the view itself. Second, the dummy view is a full member of the view
hierarchy, which means that it adds overhead to every task the hierarchy performs. Worst of all, the
invisible dummy view can intercept messages that are intended for other views, causing problems that
are very difficult to find.
You can use UILayoutGuide to do this, instead of adding the buttons into an unnecessary UIView. A UILayoutGuide
is essentially a rectangular space that can interact with Auto Layout. You put a UILayoutGuide on the left and right
sides of the buttons and set their widths to be equal. This will center the buttons. Here is how to do it in code:
view.addSubview(button1)
view.addSubview(button2)
let views = [
"leftSpace" : leftSpace,
"button1" : button1,
"button2" : button2,
"rightSpace" : rightSpace
]
// Now set the layout guides widths equal, so that the space on the
// left and the right of the buttons will be equal
leftSpace.widthAnchor.constraintEqualToAnchor(rightSpace.widthAnchor).active = true
leadingSpace.widthAnchor.constraintEqualToAnchor(trailingSpace.widthAnchor).active = true
leadingSpace.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor).active = true
leadingSpace.trailingAnchor.constraintEqualToAnchor(button1.leadingAnchor).active = true
trailingSpace.leadingAnchor.constraintEqualToAnchor(button2.trailingAnchor).active = true
trailingSpace.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor).active = true
You will need to add vertical constraints to this as well, but this will center the buttons in the view without adding
any "dummy" views! This will save the system from wasting CPU time on displaying those "dummy" views. This
example uses buttons, but you can swap buttons out for any view you want to put constraints on.
If you are supporting iOS 8 or earlier the easiest way to create this layout is to add hidden dummy views. With iOS 9
you can replace dummy views with layout guides.
Note: Interface Builder does not support layout guides yet (Xcode 7.2.1). So if you want to use them you must
create your constraints in code. Source.
If it wasn't perfectly centered already, you may need to do one more thing. Click the "Update Frames" button that is
two to the left of the "Embed In Stack" button on the bottom bar.
Now when you run your app it should be centered, no matter what device size you are using.
Another way to center views using Interface Builder is by control-click-dragging. Say you want to center a UILabel in
a view. Open the Document Outline in your storyboard by clicking the sidebar button at the bottom left. Click and
drag from the label to the view while holding ctrl (control), and a blue line should appear:
Select "Center Horizontally in Container" and "Center Vertically in Container". Update frames as necessary, and
voila! A centered label.
Alternatively, you can add the constraints programmatically. Create the constraints and add them to the desired UI
elements and views as the following example describes, where we create a button and align it in the center,
horizontally and vertically to its superview:
Objective-C
- (void)viewDidLoad
{
[super viewDidLoad];
UIButton *yourButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 100, 18)];
[yourButton setTitle:@"Button" forState:UIControlStateNormal];
Swift
In the examples below the Anchor Style is the preferred method over NSLayoutConstraint Style, however it is only
available from iOS 9, so if you are supporting iOS 8 then you should still use NSLayoutConstraint Style.
Pinning
Anchor Style
NSLayoutConstraint Style
Anchor Style
Center in container
Anchor Style
myView.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor).active = true
myView.centerYAnchor.constraintEqualToAnchor(view.centerYAnchor).active = true
NSLayoutConstraint Style
NSLayoutConstraint.constraintsWithVisualFormat("V:[viewKey]-(<=0)-[myViewKey]", options:
NSLayoutFormatOptions.AlignAllCenterX, metrics: nil, views: ["myViewKey": myView, "viewKey": view])
NSLayoutConstraint.constraintsWithVisualFormat("H:[viewKey]-(<=0)-[myViewKey]", options:
NSLayoutFormatOptions.AlignAllCenterY, metrics: nil, views: ["myViewKey": myView, "viewKey": view])
Missing Constraints : Need constraints for : X position: As discussed above we have given the view a width and a
height so its “BOUNDS” is defined but we have not given its origin so its “FRAME” is not defined. Autolayout is not
able to determine what will be the X position of our yellow view
Missing Constraints : Need constraints for : Y position: As discussed above we have given the view a width and a
height so its “BOUNDS” is defined but we have not given its origin so its “FRAME” is not defined. Autolayout is not
able to determine what will be the Y position of our yellow view To solve this we have to give autolayout some thing
to resole X and Y. Since we cannot set frames we will do it autolayout way.Add following constraints as per the
image given below I will explain it later
Step 3: By now our base yellow view is ready. We will add the prefix image as subview of our yellow view with
following constraints.You can choose any image of your choice.
Step4: Add a UILabel as the sub view of our yellow view and add following constraints
Q: Why we are not getting any errors now , we have not given any width and height? Ans: We get error or warning
only when auto layout is not able to resolve any thing which is must to render a view on screen.Be it height width or
origin.Since our label is relative to yellow view and prefix image and their frames is well defined autolayout is able
to calculate the frame of our Label.
Step 5: Now if we recall we will realize that we have given fixed view to out yellow view but we want it to be
dynamic dependent upon the text of our label.So We will modify our Width Constraint of yellow view.Width of
yellow view is necessary to resolve ambiguity but we want it to be overruled at runtime based upon the content of
UILabel. So we will select our yellow view and go to Size inspector and reduce the priority of width constraint to 1 so
that it will be over ruled. Follow the image given below.
Now build and run you will see some thing as following.
"H:|[bgView][aGradeView(40)][bGradeView(40)]|"
There are two axes in which we can constrain UI Objects to, Horizontally and Vertically.
Each line of VFL always begins with H: or V:. If neither are present, the default option is H:
Moving on, we have a pipeline. | This symbol, or the pipe, refers to the superview. If you take a closer look at the
snippet of VFL code above, you'd notice two of these pipelines.
This signifies the two horizontal ends of the superview, the outerleft and outerright boundaries.
Next up you'll see some square brackets, within the first set of square brackets, we have bgView. When we've got
square brackets, it's referring to a UI element, now you might wonder how we establish a link between the name
and the actual UI element, an outlet perhaps?
If you take a look at the second pair of square brackets [aGradeView(50)], we have some parentheses
encapsulated within as well, when that is present, it defines the width/height depending on the axes, which in this
case is 50 pixels in width.
The first square brackets [bgView] did not have a width explicitly defined, meaning that it'll span out as far as
possible.
Alright, that's it for the basics, more on the advanced stuff in another example.
for example:
// 1. create views
UIView *blueView = [[UIView alloc] init];
blueView.backgroundColor = [UIColor blueColor];
[self.view addSubview:blueView];
// 3. make contraints
// horizontal
NSArray *blueH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[blueView]-20-|"
options:NSLayoutFormatAlignAllLeft metrics:nil views:@{@"blueView" : blueView}];
[self.view addConstraints:blueH];
// vertical
NSArray *blueVandRedV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-20-
[blueView(50)]-20-[redView(==blueView)]" options:NSLayoutFormatAlignAllTrailing metrics:nil
views:@{@"blueView" : blueView, @"redView" : redView}];
[self.view addConstraints:blueVandRedV];
I set the highest priority for 1st label and the lowest for 4th label.
1. Change the constant of the constraint after creation using periodic calls (CADisplayLink,
dispatch_source_t, dispatch_after, NSTimer). Then call layoutIfNeeded to update the constraint. Example:
Objective-C:
self.someConstraint.constant = 10.0;
[UIView animateWithDuration:0.25 animations:^{
[self.view layoutIfNeeded];
}];
Swift:
self.someConstraint.constant = 10.0
UIView.animate(withDuration: 0.25, animations: self.view.layoutIfNeeded)
2. Change the constraints and call [view layoutIfNeeded] inside an animation block. This interpolates
between the two positions ignoring constraints during the animation.
3. Change the priority of the constraints. This is less CPU intensive than adding and removing constraints.
4. Remove all constraints and use autosizing masks. For the later, you have to set
view.translatesAutoresizingMaskIntoConstraints = YES.
6. Use a container view. Position the superview using constraints. Then add a subview with constraints that
don't fight the animation, eg: a center relative to the superview. This unloads part of the constraints to the
superview, so they don't fight the animation in the subview.
7. Animate layers instead views. Layer transforms don't trigger the Auto Layout.
8. Override layoutSubviews. Call [super layoutSubviews] and fine tune the constraints.
9. Change the frame in viewDidLayoutSubviews. Auto Layout is applied in layoutSubviews, so once done,
10. Opt out from Auto Layout and set views manually. You can do this overriding layoutSubviews/layout
without calling the super class’s implementation.
Quick tip: if the parent of the animated view is not being interpolated (that is, the animation jumps from beginning
to end state), call layoutIfNeeded() in the deepest view that is the parent of the view that is animated (in other
words, that is not affected by the animation). I don't know exactly why this works.
for example:
Objective-C
// 1. create views
UIView *blueView = [[UIView alloc] init];
blueView.backgroundColor = [UIColor blueColor];
[self.view addSubview:blueView];
// 2. forbid Autoresizing
blueView.translatesAutoresizingMaskIntoConstraints = NO;
redView.translatesAutoresizingMaskIntoConstraints = NO;
// 3. make contraints
// 3.1 blueView
NSLayoutConstraint *blueLeft = [NSLayoutConstraint constraintWithItem:blueView
attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view
attribute:NSLayoutAttributeLeft multiplier:1 constant:20];
[self.view addConstraint:blueLeft];
// 3.2 redView
NSLayoutConstraint *redTop = [NSLayoutConstraint constraintWithItem:redView
attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:blueView
attribute:NSLayoutAttributeBottom multiplier:1 constant:20];
[self.view addConstraint:redTop];
You can use multiplier to create proportional layout for different size factor.
Example:
Turquoise View (V1) is a square with width proportional superview width with ratio 1:1.1
Gary square(V2) is a subview of V1. Bottom space set by constant = 60, Trailing space set by multiplier = 1.125 and
constant = 0
Example: when you have a UIView that has a maskLayer, you may need to update maskLayer as soon as Auto
Layout changes UIView's frame
// CustomView.m
- (void)layoutSubviews {
[super layoutSubviews];
// now you can assume Auto Layout did its job
// you can use view's frame in your calculations
CALayer maskLayer = self.maskLayer;
maskLayer.bounds = self.bounds;
...
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
// now you can assume all your subviews are positioned/resized correctly
self.customView.frame = self.containerView.frame;
}
Auto layout constraints can be set in the Interface Builder or in code. In the Interface Builder you find the Auto
Layout tools at the bottom right. Clicking them will reveal different options for setting the constraints on a view.
If you wish to have different constraints for different device sizes or orientations, you can set them in wAny hAny
Size Class options found in the bottom middle.
Version ≥ iPhone OS 3
.standard
Displays a street map that shows the position of all roads and some road names.
Swift 2
mapView.mapType = .Standard
Swift 3
mapView.mapType = .standard
Objective-C
_mapView.mapType = MKMapTypeStandard;
Swift 2
mapView.mapType = .Satellite
Swift 3
mapView.mapType = .satellite
Objective-C
_mapView.mapType = MKMapTypeSatellite;
Displays a satellite image of the area with flyover data where available.
Swift 2
mapView.mapType = .SatelliteFlyover
Swift 3
mapView.mapType = .satelliteFlyover
Objective-C
_mapView.mapType = MKMapTypeSatelliteFlyover;
Version ≥ iPhone OS 3
.hybrid
Displays a satellite image of the area with road and road name information layered on top.
Swift 2
mapView.mapType = .Hybrid
Objective-C
_mapView.mapType = MKMapTypeHybrid;
Version ≥ iOS 9
.hybridFlyover
Swift 2
mapView.mapType = .HybridFlyover
Swift 3
mapView.mapType = .hybridFlyover
Objective-C
_mapView.mapType = MKMapTypeHybridFlyover;
<?xml version="1.0"?>
<gpx version="1.1" creator="Xcode">
<wpt lat="25.041865" lon="121.551361"> // Edit the latitude and longitude
<name>Taipei</name> // Edit the name of the location
<time>2014-09-24T14:55:37Z</time>
</wpt>
</gpx>
MKLocalSearchRequest *request =
[[MKLocalSearchRequest alloc] init];//initialising search request
request.naturalLanguageQuery = @”Gym”; // adding query
request.region = _mapView.region; //setting region
MKLocalSearch *search =
[[MKLocalSearch alloc]initWithRequest:request];//initiate search
[search startWithCompletionHandler:^(MKLocalSearchResponse
*response, NSError *error)
{
if (response.mapItems.count == 0)
NSLog(@"No Matches");
else
for (MKMapItem *item in response.mapItems)
{
NSLog(@"name = %@", item.name);
NSLog(@"Phone = %@", item.phoneNumber);
}
}];
You can add an overlay to your mapView that contains custom tiles for example from OpenStreetMap.
Let's assume, self.mapView is your MKMapView that you have already added to your ViewController.
mapView.delegate = self
Next, you configure the overlay for the map. You'll need an URL-template for this. The URL should be similar to this
on all tile-servers and even if you would store the map-data offline:
http://tile.openstreetmap.org/{z}/{x}/{y}.png
After you configured the overlay, you must add it to your mapView.
To use custom maps, it is recommended to use .aboveLabels for level. Otherwise, the default labels would be
visible on your custom map. If you want to see the default labels, you can choose .aboveRoads here.
If you would run your project now, you would recognize, that your map would still show the default map:
That's because we haven't told the mapView yet, how to render the overlay. This is the reason, why you had to set
the delegate before. Now you can add func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay)
-> MKOverlayRenderer to your view controller:
This will return the correct MKOverlayRenderer to your mapView. If you run your project now, you should see a map
like this:
/**
Sets the center of the `MKMapView` to a `CLLocationCoordinate2D` with a custom zoom-level.
There is no nee to set a region manually. :-)
zoomLevel is a Double value, usually between 0 and 21 (which is a very high zoom-level), but values up to 28 are
allowed.
[mapView removeAnnotations:mapView.annotations]
if (allAnnotations.count > 0)
{
//getting first annoation
id <MKAnnotation> annotation=[allAnnotations firstObject];
//removing annotation
[mapView removeAnnotation:annotation];
It's recommended to store the mapView as a property of the containing ViewController since you might want to
access it in more complex implementations.
Objective-C
[self.map setShowsUserLocation:YES];
Swift
self.map?.showsUserLocation = true
Objective-C
[self.map setUserTrackingMode:MKUserTrackingModeFollow];
Swift
self.map?.userTrackingMode = .follow
[self.mapView addAnnotation:pointAnnotation];
Yeaah.. Hurrah.. you have done the job. You can now see point annotation(red coloured pin) at given coordinate.
But now, what if you want to change color of the pin(3 available colors are - Purple,red and green). Then follow this
step.
self.mapView.delegate = self;
if (!pinView)
{
// If not dequed, then create new.
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:@"PinAnnotationView"];
Objective-C:
Demo:
//-----------------------
let array = [["one" : 1], ["two" : 2], ["three" : 3], ["four" : 4]]
//-----------------------
do {
let jsonData: Data = try JSONSerialization.data(withJSONObject: arrayObject, options:
[])
if let jsonString = NSString(data: jsonData, encoding: String.Encoding.utf8.rawValue)
{
return jsonString as String
}
A common application is to use this to display a string and adding custom kerning / letter-spacing.
This would be achieved as follows (where label is a UILabel), giving a different kerning for the word "kerning"
Swift
Objective-C
NSMutableAttributedString *attributedString;
attributedString = [[NSMutableAttributedString alloc] initWithString:@"Apply kerning"];
[attributedString addAttribute:NSKernAttributeName value:@5 range:NSMakeRange(6, 7)];
[label setAttributedText:attributedString];
Swift
Note:
The main here is to use a NSMutableAttributedString and the selector addAttribute:value:range with the
attribute NSForegroundColorAttributeName to change a color of a string range:
You could use another way to get the range, for example: NSRegularExpression.
Swift
Swift
yourLabel.attributedText = attributeString;
//HTML String
NSString *htmlString=[[NSString alloc]initWithFormat:@"<!DOCTYPE html><html><body><h1>My First
Heading</h1><p>My first paragraph.</p></body></html>"];
//Converting HTML string with UTF-8 encoding to NSAttributedString
NSAttributedString *attributedString = [[NSAttributedString alloc]
initWithData: [htmlString
dataUsingEncoding:NSUnicodeStringEncoding]
options: @{ NSDocumentTypeDocumentAttribute:
NSHTMLTextDocumentType }
documentAttributes: nil
error: nil ];
Swift
Swift 3
Objective-C
Setting repeats to false/NO indicates that we want the timer to fire only once. If we set this to true/YES, it would
fire every five seconds until manually invalidated.
timer.fire()
Objective-C
[timer fire];
Calling the fire method causes an NSTimer to perform the task it would have usually performed on a schedule.
In a non-repeating timer, this will automatically invalidate the timer. That is, calling fire before the time interval is
up will result in only one invocation.
In a repeating timer, this will simply invoke the action without interrupting the usual schedule.
Swift
func timerMethod() {
print("Timer method called")
}
func endTimer() {
timer.invalidate()
}
}
Swift 3
func timerMethod() {
print("Timer method called")
}
func endTimer() {
timer.invalidate()
}
}
Swift
Swift 3
Timer will be fired once, 3 seconds after time of execution. Will be invalidated automatically, once fired.
timer.invalidate()
Objective-C
[timer invalidate];
This will stop the timer from firing. Must be called from the thread the timer was created in, see Apple's notes:
You must send this message from the thread on which the timer was installed. If you send this message
from another thread, the input source associated with the timer may not be removed from its run loop,
which could prevent the thread from exiting properly.
Notes: Once timer has been invalidated, its impossible to fire same invalidated timer.Instead you need to
initialise the invalidated timer again and trigger fire method.
Here is the simple approach that gives brief idea about how you can pass the data to triggered method from the
Timer.
[Swift 3]
[Objective - C]
The above line of code passing ["Name": "i am iOS guy"] into the userInfo. So now when the iGotCall get call
you can get the passed value as below code snippet.
[Swift 3]
[Objective - C]
- (void)iGotCall:(NSTimer*)theTimer {
NSLog (@"%@", (NSString*)[theTimer userInfo]);
}
Swift 3
let dateFormatter = DateFormatter()
Objective-C
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
Objective-C
dateFormatter.dateFormat = @"yyyy-MM-dd 'at' HH:mm";
Swift 3
let date = Date() // your NSDate object
let dateString = dateFormatter.stringFromDate(date)
Objective-C
NSDate *date = [NSDate date]; // your NSDate object
NSString *dateString = [dateFormatter stringFromDate:date];
Note
Swift
Objective-C
- (BOOL)isEqualToDate:(NSDate *)anotherDate
- (NSDate *)earlierDate:(NSDate *)anotherDate
- (NSDate *)laterDate:(NSDate *)anotherDate
- (NSComparisonResult)compare:(NSDate *)anotherDate
Swift
let date1: NSDate = ... // initialized as July 7, 2016 00:00:00
let date2: NSDate = ... // initialized as July 2, 2016 00:00:00
Objective-C
NSDate *date1 = ... // initialized as July 7, 2016 00:00:00
NSDate *date2 = ... // initialized as July 2, 2016 00:00:00
Swift
if date1.isEqualToDate(date2) {
// returns false, as both dates aren't equal
}
earlierDate: NSDate = date1.earlierDate(date2) // returns the earlier date of the two (date 2)
laterDate: NSDate = date1.laterDate(date2) // returns the later date of the two (date1)
if result == .OrderedAscending {
// true if date1 is earlier than date2
} else if result == .OrderedSame {
// true if the dates are the same
} else if result == .OrderedDescending {
// true if date1 is later than date1
}
Objective-C
if ([date1 isEqualToDate:date2]) {
// returns false, as both date are not equal
}
NSDate *earlierDate = [date1 earlierDate:date2]; // returns date which comes earlier from both
date, here it will return date2
NSDate *laterDate = [date1 laterDate:date2]; // returns date which comes later from both date, here
it will return date1
If you want to compare dates and handle seconds, weeks, months and years:
Swift 3
let dateStringUTC = "2016-10-22 12:37:48 +0000"
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss X"
let date = dateFormatter.date(from: dateStringUTC)!
Objective-C
- (NSString *)getHistoricTimeText:(NSDate *)since
{
NSString *str;
NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:since];
if(interval < 60)
str = [NSString stringWithFormat:@"%is ago",(int)interval];
else if(interval < 3600)
{
int minutes = interval/60;
str = [NSString stringWithFormat:@"%im ago",minutes];
}
else if(interval < 86400)
{
int hours = interval/3600;
}
return str;
}
Swift
let date = NSDate() // current date
let unixtime = date.timeIntervalSince1970
Objective-C
NSDate *date = [NSDate date]; // current date
int unixtime = [date timeIntervalSince1970];
Objective-C
(NSDate*) getDateFromJSON:(NSString *)dateString
This uses a special date template string called "j" which according to the ICU Spec ...
[...] requests the preferred hour format for the locale (h, H, K, or k), as determined by the preferred
attribute of the hours element in supplemental data. [...] Note that use of 'j' in a skeleton passed to an API
is the only way to have a skeleton request a locale's preferred time cycle type (12-hour or 24-hour).
That last sentence is important. It "is the only way to have a skeleton request a locale's preferred time cycle type".
Since NSDateFormatter and NSCalendar are built on the ICU library, the same holds true here.
Reference
Swift
var date = NSDate()
Swift 3
var date = Date()
For doing this we have a method named dateWithTimerIntervalSinceNow(seconds: NSTimeInterval) -> NSDate
(Swift) or + (NSDate*)dateWithTimeIntervalSinceNow:(NSTimeInterval)seconds (Objective-C).
Now for example, if you require a date one week from current date and one week to current date, then we can do it
as.
Swift
let totalSecondsInWeek:NSTimeInterval = 7 * 24 * 60 * 60;
//Using negative value for previous date from today
let nextWeek = NSDate().dateWithTimerIntervalSinceNow(totalSecondsInWeek)
Swift 3
let totalSecondsInWeek:TimeInterval = 7 * 24 * 60 * 60;
//Using negative value to get date one week from current date
let lastWeek = Date(timeIntervalSinceNow: -totalSecondsInWeek)
Objective-C
NSTimeInterval totalSecondsInWeek = 7 * 24 * 60 * 60;
//Using negative value for previous date from today
NSDate *lastWeek = [NSDate dateWithTimeIntervalSinceNow:-totalSecondsInWeek];
The downside for this situation is that your NSDate is almost completely "naked" and what you need to do is to
create: day, month, year, second and time zone in order to this object to "play along" with other NSDate types.
For the sake of the example let's say that hourAndMinute is the NSDate type that is composed from hour and
minute format:
Objective-C
NSDateComponents *hourAndMinuteComponents = [calendar components:NSCalendarUnitHour |
NSCalendarUnitMinute
fromDate:hourAndMinute];
NSDateComponents *componentsOfDate = [[NSCalendar currentCalendar] components:NSCalendarUnitDay |
NSCalendarUnitMonth | NSCalendarUnitYear
fromDate:[NSDate date]];
iOS notifications are a simple and powerful way to send data in a loosely coupled way. That is, the sender of a
notification doesn't have to care about who (if anyone) receives the notification, it just posts it out there to the rest
of the app and it could be picked up by lots of things or nothing depending on your app's state.
Swift 3
//Remove observer for single notification
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue:
"TestNotification"), object: nil)
Objective-C
//Remove observer for single notification
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"TestNotification" object:nil];
Notifications are identified by global NSString objects whose names are composed in this way:
For example:
NSApplicationDidBecomeActiveNotification
NSWindowDidMiniaturizeNotification
NSTextViewDidChangeSelectionNotification
Swift 2.3
NSNotificationCenter.defaultCenter().addObserver(self,
selector: #selector(self.testNotification(_:)),
name: "TestNotification",
object: nil)
Swift 3
NSNotificationCenter.default.addObserver(self,
selector: #selector(self.testNotification(_:)),
name: NSNotification.Name(rawValue: "TestNotification"),
object: nil)
Objective-C
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(testNotification:)
name:@"TestNotification"
object:nil];
PS: It is also worth noting that the number of times an observer has been added has to be exactly the number of
times the observer is removed. A rookie mistake is to add the observer in the viewWillAppear: of a
UIViewController, but removing the observer in viewDidUnload:, will cause an uneven number of pushes and thus
leaking the observer and the notification selector getting called in a superfluous manner.
Objective-C
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:myObject forKey:@"someKey"];
[[NSNotificationCenter defaultCenter] postNotificationName: @"TestNotification" object:nil
userInfo:userInfo];
// Remove observer
NSNotificationCenter.defaultCenter().removeObserver(observer)
Objective-C
[[NSNotificationCenter defaultCenter] postNotificationName:@"TestNotification" object:nil];
Objective-C
- (void)testNotification:(NSNotification *)notification {
NSDictionary *userInfo = notification.userInfo;
MyObject *myObject = [userInfo objectForKey:@"someKey"];
}
[[session dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
// The response object contains the metadata (HTTP headers, status code)
// Swift:
let mySessionID = "com.example.bgSession"
let bgSessionConfig =
NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(mySessionID)
// Objective-C:
NSString *mySessionID = @"com.example.bgSession";
NSURLSessionConfiguration *configuration =
[NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier: mySessionID];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
delegate:self]
Additionally, in iOS, you must set up support for handling background app relaunch. When your app's
application:handleEventsForBackgroundURLSession:completionHandler: method (Objective-C) or
application(_:handleEventsForBackgroundURLSession:completionHandler:) method (Swift) gets called, it
means your app has been relaunched in the background to handle activity on a session.
In that method, you should create a new session with the provided identifier and configure it with a delegate to
handle events just like you normally would in the foreground. Additionally, you should store the provided
completion handler in a dictionary, using the session as the key.
If you're curious about the details, at a high level, when you create a background session, you're doing two things:
Normally, it is dangerous to create two sessions with the same session ID in a single launch of the app, because
they both are trying to talk to the same session in the background daemon. This is why the official documentation
says to never create multiple sessions with the same identifier. However, if the first session was a temporary
session created as part of a handleEventsForBackgroundURLSession call, the association between the now-
invalidated in-app session and the session in the background daemon no longer exists.
/*inside this block, we have access to NSData *data, NSURLResponse *response, and NSError
*error returned by the dataTaskWithURL() function*/
(data, response, error) in
if error == nil
{
// Data from the request can be manipulated here
}
else
{
// An error occurred
}
}
Be it you have a server for your small application or your working in a team with a full out back-end engineer, you'll
In the following code we will be composing a string of arguments that the destination server script will use to do
something that changes depending on your case. For example we may want to send the string:
name=Brendon&password=abcde
To the server when a user signs up to your application, so the server can store this information in a database.
Let's get started. You'll want to create a NSURLSession POST request with the following code.
// Create the configuration, which is necessary so we can cancel cacheing amongst other things.
NSURLSessionConfiguration * defaultConfigObject = [NSURLSessionConfiguration
defaultSessionConfiguration];
// Disables cacheing
defaultConfigObject.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
NSURLSession * defaultSession = [NSURLSession sessionWithConfiguration:defaultConfigObject
delegate:self delegateQueue:[NSOperationQueue mainQueue]];
The above code just created and fired the POST request to the server. Remember that the script URL and the POST
data string changes depending on your situation. If you're reading this, you'll know what to fill those variables with.
You'll also need to add a small method that does the URL encoding:
So, when the server is finished processing this data it will send a return to your iOS app. So we need to process this
return, but how?
We use event-driven programming and use NSURLSession's delegate methods. This means as the server sends
back a response these methods will start triggering. The following 5 methods are the ones that'll be triggered
throughout the ENTIRE request, each time one is made:
Below you'll see the above methods used in context. Each of their purposes are pretty self-explanatory thanks to
Apple, but I've commented their uses anyway:
// When the session receives a challenge (because of iOS 9 App Transport Security blocking non-
valid SSL certificates) we use the following methods to tell NSURLSession "Chill out, I can trust
me".
// The following is not necessary unless your server is using HTTP, not HTTPS
So that's it! That's all the code you need to send, receive and parse a request for an API in iOS 9! Okay...it was kind
of a lot of code. But if implemented right like above, it'll be fail-safe! Make sure to always handle errors where
suggested above.
URL encoding is a broadly compatible way to encode arbitrary data. However, it is relatively inefficient for uploading
binary data (such as photos) because every non-ASCII byte turns into a three-character code. It also does not
support file attachments, so you would have to pass filenames and file data as separate fields.
Suppose we want to upload a photograph in a way that is efficient and actually looks like a file on the server side.
One way to do that is to use form encoding instead. To do this, edit the code that creates the NSURLSession as
follows:
UIImage * imgToSend;
// This boundary serves as a separator between one form field and the next.
// It must not appear anywhere within the actual data that you intend to
// upload.
NSString * boundary = @"---------------------------14737809831466499882746641449";
// The body must start with the boundary preceded by two hyphens, followed
// by a carriage return and newline pair.
// This is followed by a series of headers for the first field and then
// TWO CR-LF pairs.
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data;
name=\"tag_name\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
// Next is the actual data for that field (called "tag_name") followed by
// a CR-LF pair, a boundary, and another CR-LF pair.
[body appendData:[strippedCompanyName dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary]
dataUsingEncoding:NSUTF8StringEncoding]];
// Encode the filename and image data as the "userfile" CGI parameter.
// This is similar to the previous field, except that it is being sent
// as an actual file attachment rather than a blob of data, which means
// it has both a filename and the actual file contents.
//
// IMPORTANT: The filename MUST be plain ASCII (and if encoded like this,
// must not include quotation marks in the filename).
//
NSString * picFileName = [NSString stringWithFormat:@"photoName"];
NSString * appendDataString = [NSString stringWithFormat:@"Content-Disposition: form-data;
name=\"userfile\"; filename=\"%@.jpg\"\r\n", picFileName];
[body appendData:[appendDataString dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@"Content-Type: application/octet-stream\r\n\r\n"
dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[NSData dataWithData:imageData]];
// Close the request body with one last boundary with two
// additional hyphens prepended **and** two additional hyphens appended.
[body appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary]
dataUsingEncoding:NSUTF8StringEncoding]];
This creates and fires the NSURLSession request just as before, and as a result the delegate methods will behave
exactly the same way. Make sure that the script the image is being sent to (located at the url in the variable url) is
expecting an image and can parse it correctly.
Swift < 3
setBool(_:forKey:)
setFloat(_:forKey:)
setInteger(_:forKey:)
setObject(_:forKey:)
setDouble(_:forKey:)
setURL(_:forKey:)
Swift 3
In Swift 3 the names of function is changed to set insted of set folloed by the type.
set(_:forKey:)
Objective-C
-(void)setBool:(BOOL)value forKey:(nonnull NSString *)defaultName;
-(void)setFloat:(float)value forKey:(nonnull NSString *)defaultName;
-(void)setInteger:(NSInteger)value forKey:(nonnull NSString *)defaultName;
-(void)setObject:(nullable id)value forKey:(nonnull NSString *)defaultName;
-(void)setDouble:(double)value forKey:(nonnull NSString *)defaultName;
-(void)setURL:(nullable NSURL *)value forKey:(nonnull NSString *)defaultName;
Swift < 3
NSUserDefaults.standardUserDefaults.setObject("Netherlands", forKey: "HomeCountry")
Swift 3
UserDefaults.standard.set("Netherlands", forKey: "HomeCountry")
Objective-C
[[NSUserDefaults standardUserDefaults] setObject:@"Netherlands" forKey:@"HomeCountry"];
Custom objects
To save custom objects into the `NSUserDefaults` you need to make your CustomClass confirm to protocol of
`NSCoding`. You need to implement the following methods: Swift
public func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(name, forKey:"name")
aCoder.encodeObject(unitId, forKey: "unitId")
}
Objective-C
- (id)initWithCoder:(NSCoder *)coder {
self = [super init];
if (self) {
name = [coder decodeObjectForKey:@"name"];
unitId = [coder decodeIntegerForKey:@"unitId"];
- (void)encodeWithCoder:(NSCoder*)coder {
[coder encodeObject:name forKey:@"name"];
[coder encodeInteger:unitId forKey:@"unitId"];
}
Swift 3
import Foundation
Suppose that we want to save a user’s score into NSUserDefaults. We can create a class like the one below that has
at two methods: setHighScore and highScore. Anywhere you want to access the high scores, create an instance of
this class.
Swift
public class ScoreManager: NSObject {
var highScore = {
set {
// This method includes your implementation for saving the high score
// You can use NSUserDefaults or any other data store like CoreData or
// SQLite etc.
Objective-C
#import "ScoreManager.h"
@implementation ScoreManager
- (void)setHighScore:(NSUInteger) highScore {
// This method includes your implementation for saving the high score
// You can use NSUserDefaults or any other data store like CoreData or
// SQLite etc.
- (NSInteger)highScore
{
//This method includes your implementation for reading the high score
return -1;
}
@end
1. The implementation of your read and write process is only in one place and you can change it (for example
switch from NSUserDefaults to Core Data) whenever you want and not worry about changing all places that
you are working with the high score.
2. Simply call only one method when you want to access to score or write it.
Note
If you are worried about synchronization, it is better to use a singleton class that manages the
synchronization.
Swift
NSUserDefaults.standardUserDefaults().synchronize()
Objective-C
[[NSUserDefaults standardUserDefaults] synchronize];
NSUserDefaults.standardUserDefaults().removePersistentDomainForName(bundleIdentifier)
Objective-C
NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
Swift
arrayForKey(_:)
boolForKey(_:)
dataForKey(_:)
dictionaryForKey(_:)
floatForKey(_:)
integerForKey(_:)
objectForKey(_:)
stringArrayForKey(_:)
stringForKey(_:)
doubleForKey(_:)
URLForKey(_:)
Objective-C
-(nullable NSArray *)arrayForKey:(nonnull NSString *)defaultName;
-(BOOL)boolForKey:(nonnull NSString *)defaultName;
-(nullable NSData *)dataForKey:(nonnull NSString *)defaultName;
-(nullable NSDictionary<NSString *, id> *)dictionaryForKey:(nonnull NSString *)defaultName;
-(float)floatForKey:(nonnull NSString *)defaultName;
-(NSInteger)integerForKey:(nonnull NSString *)defaultName;
-(nullable id)objectForKey:(nonnull NSString *)key;
-(nullable NSArray<NSString *> *)stringArrayForKey:(nonnull NSString *)defaultName;
-(nullable NSString *)stringForKey:(nonnull NSString *)defaultName;
-(double)doubleForKey:(nonnull NSString *)defaultName;
-(nullable NSURL *)URLForKey:(nonnull NSString *)defaultName;
Swift
let homeCountry = NSUserDefaults.standardUserDefaults().stringForKey("HomeCountry")
class CookiesSingleton {
func loadCookies() {
if let cookiesDetails = NSUserDefaults.standardUserDefaults().objectForKey("customeWebsite") {
for (keys,_) in cookiesDetails as! NSDictionary{
if let cookieDict = NSUserDefaults.standardUserDefaults().objectForKey(keys as!
String){
if let cookie = NSHTTPCookie(properties:cookieDict as! [String:AnyObject]) {
NSHTTPCookieStorage.sharedHTTPCookieStorage().setCookie(cookie)
if(CookiesSingleton.enableDebug){
print("Each Cookies",cookieDict)
}
}
}
}
}
}
func removeCookies(){
NSURLCache.sharedURLCache().removeAllCachedResponses()
NSURLCache.sharedURLCache().diskCapacity = 0
NSURLCache.sharedURLCache().memoryCapacity = 0
if(CookiesSingleton.enableDebug){
print("Cookies Removed")
}
}
func saveCookies() {
}
NSUserDefaults.standardUserDefaults().setValue(allCookiesDic, forKey: "customeWebsite")
NSUserDefaults.standardUserDefaults().synchronize()
if(CookiesSingleton.enableDebug){
print("Cookies Saved")
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// The request is complete and data has been received
// You can parse the stuff in your instance variable now
if (error == nil)
{
// Parse data here
Swift 3.0
Swift
extension NSData {
Objective-C
@implementation NSData (HexRepresentation)
- (NSString *)hexString {
const unsigned char *bytes = (const unsigned char *)self.bytes;
NSMutableString *hex = [NSMutableString new];
for (NSInteger i = 0; i < self.length; i++) {
[hex appendFormat:@"%02x", bytes[i]];
}
return [hex copy];
}
@end
Objective-C
NSData *data = [NSData dataWithContentsOfFile:filePath]; //assuming filePath is a valid path
Objective-C
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding]; //assuming string is a String
object
Objective-C
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; //assuming
To Array
Swift
let array = data.bytes as! NSMutableArray //assuming data is a valid NSData object
Objective-C
NSMutableArray *array = (NSMutableArray *)[data bytes]; //assuming data is a valid NSData object
To Bytes Array
Swift
let bytesArray = data.bytes as! UInt8 //assuming data is a valid NSData object
Objective-C
UInt8 *bytesArray = (UInt8 *)data.bytes; //assuming data is a valid NSData object
An NSInvocation is an Objective-C message rendered static, that is, it is an action turned into an object.
The concept of messages is central to the objective-c philosophy. Any time you call a method, or access a variable of
some object, you are sending it a message. NSInvocation comes in handy when you want to send a message to an
object at a different point in time, or send the same message several times. NSInvocation allows you to describe the
message you are going to send, and then invoke it (actually send it to the target object) later on.
For example, let's say you want to add a string to an array. You would normally send the addObject: message as
follows:
[myArray addObject:myString];
Now, let's say you want to use NSInvocation to send this message at some other point in time:
First, you would prepare an NSInvocation object for use with NSMutableArray's addObject: selector:
Next, you would specify which object to send the message to:
[myInvocation setTarget:myArray];
[myInvocation setSelector:@selector(addObject:)];
Note that object arguments must be passed by pointer. Thank you to Ryan McCuaig for pointing that out, and
please see Apple's documentation for more details.
At this point, myInvocation is a complete object, describing a message that can be sent. To actually send the
message, you would call:
[myInvocation invoke];
This final step will cause the message to be sent, essentially executing [myArray addObject:myString];.
NSUndoManager uses NSInvocation objects so that it can reverse commands. Essentially, what you are doing is
creating an NSInvocation object to say: "Hey, if you want to undo what I just did, send this message to that object,
with these arguments". You give the NSInvocation object to the NSUndoManager, and it adds that object to an array
of undoable actions. If the user calls "Undo", NSUndoManager simply looks up the most recent action in the array,
and invokes the stored NSInvocation object to perform the necessary action.
Key Value
NSUserActivityTypes [Array]
- item0 com.companyName.productName.activityName01
- item1 com.companyName.productName.activityName02
Once you have defined all supported activity types, you may begin to access and use them in your application's
code.
// Initialize the activity object and set its type from one of the ones specified in your app's
plist
NSUserActivity *currentActivity = [[NSUserActivity alloc]
initWithActivityType:@"com.companyName.productName.activityName01"];
// Configure additional properties like userInfo which will be included in the activity
currentActivity.userInfo = @{@"informationKey" : @"value"};
// Configure the activity so the system knows what may be done with it
// It is important that you only set YES to tasks that your application supports
// In this example, we will only enable the activity for use with Handoff
[currentActivity setEligibleForHandoff:YES];
[currentActivity setEligibleForSearch:NO]; // Defaults to NO
[currentActivity setEligibleForPublicIndexing:NO]; // Defaults to NO
After this, the activity above should be available for Handoff (although more work is required to properly handle the
"Handoff").
-(BOOL)validateEmail {
//Email address field should give an error when the email address begins with ".","-","_" .
NSPredicate *emailPredicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegex];
- (BOOL)validateFirstName {
NSPredicate *firstNamePredicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",
firstNameRegex];
return [firstNamePredicate evaluateWithObject:self.text];
}
- (BOOL)validateLastName {
NSPredicate *lastNamePredicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",
lastNameRegex];
return [lastNamePredicate evaluateWithObject:self.text];
}
- (BOOL)validateAlphaNumericMin2Max32 {
NSPredicate *firstNamePredicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",
firstNameRegex];
return [firstNamePredicate evaluateWithObject:self.text];
}
- (BOOL)validateMobileNumber {
NSString *strippedMobileNumber = [[[[self.text stringByReplacingOccurrencesOfString:@"("
withString:@""]
stringByReplacingOccurrencesOfString:@")" withString:@""]
stringByReplacingOccurrencesOfString:@"-" withString:@""]
stringByReplacingOccurrencesOfString:@" " withString:@""];
- (BOOL)validateZipcode {
NSPredicate *zipcodePredicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",
zipcodeRegEx];
- (BOOL)validateSSN {
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", SSNRegEx];
- (BOOL)validateAddress {
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", addressRegEx];
- (BOOL)validateCity {
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", cityRegEx];
return [predicate evaluateWithObject:self.text];
}
- (BOOL)validatePIN {
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", PINRegEx];
return [predicate evaluateWithObject:self.text];
}
- (BOOL)validateDriversLiscNumber {
if([self.text length] > 20) {
return NO;
}
NSPredicate *driversLiscPredicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",
driversLiscRegEx];
Swift
let predicate = NSPredicate { (item, bindings) -> Bool in
return item.isKindOfClass(UILabel.self)
}
In this example, the predicate will match items that are of the class UILabel.
Swift
let predicate = NSPredicate(format: "self[SIZE] >= %d", 5)
Objective-C
NSPredicate *template = [NSPredicate predicateWithFormat: @"self BEGINSWITH $letter"];
NSDictionary *variables = @{ @"letter": @"r" };
NSPredicate *beginsWithR = [template predicateWithSubstitutionVariables: variables];
Swift
let template = NSPredicate(format: "self BEGINSWITH $letter")
let variables = ["letter": "r"]
let beginsWithR = template.predicateWithSubstitutionVariables(variables)
The template predicate is not modified by predicateWithSubstitutionVariables. Instead, a copy is created, and
that copy receives the substitution variables.
Objective-c
AND - Condition
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"samplePredicate"];
NSPredicate *anotherPredicate = [NSPredicate predicateWithFormat:@"anotherPredicate"];
NSPredicate *combinedPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:
@[predicate,anotherPredicate]];
OR - Condition
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"samplePredicate"];
NSPredicate *anotherPredicate = [NSPredicate predicateWithFormat:@"anotherPredicate"];
NSPredicate *combinedPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:
@[predicate,anotherPredicate]];
NOT - Condition
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"samplePredicate"];
NSPredicate *anotherPredicate = [NSPredicate predicateWithFormat:@"anotherPredicate"];
NSPredicate *combinedPredicate = [NSCompoundPredicate notPredicateWithSubpredicate:
@[predicate,anotherPredicate]];
Swift
let heroes = ["tracer", "bastion", "reaper", "junkrat", "roadhog"]
To obtain the bundle at a specific path using Cocoa, call the bundleWithPath: class method of the
NSBundle
NSBundle *myBundle;
// obtain a reference to a loadable bundle
myBundle = [NSBundle bundleWithPath:@"/Library/MyBundle.bundle";
To obtain the bundle at a specific path using Core Foundation, call the CFBundleCreate function and must
use CFURLRef type.
CFURLRef bundleURL;
CFBundleRef myBundle;
// Make a CFURLRef from the CFString representation of the bundle's path.
bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
CFSTR("/Library/MyBundle.bundle"), kCFURLPOSIXPathStyle, true);
// Make a bundle instance using the URLRef.
myBundle = CFBundleCreate(kCFAllocatorDefault, bundeURL);
// You can release the URL now.
CFRelease(bundleURL);
// Use the bundle ...
// Release the bundle when done.
CFRelease(myBundle);
To get the main bundle in Cocoa application, call the mainBundle class method of the NSBundle class.
NSBundle *mainBundle;
// Get the main bundle for the app;
mainBundle = [NSBundle mainBundle];
Use the CFBundleGetMainBundle function to retrieve the main bundle for your C-based application.
CFBundleRef mainBundle;
// Get the main bundle for the app
mainBundle = CFBundleGetMainBundle();
Swift
let animation = CABasicAnimation(keyPath: "position.x")
animation.fromValue = NSNumber(value: 0.0)
animation.toValue = NSNumber(value: 320.0)
The view will move from 0 to 320 horizontally. if you want to Move view to Vertically just replace keypath like this:
"position.y"
SWIFT
var transition = CATransition()
transition.startProgress = 0
transition.endProgress = 1.0
transition.type = "flip"
transition.subtype = "fromLeft"
transition.duration = 0.8
transition.repeatCount = 5
label.layer.addAnimation(transition, forKey: "transition")
Swift
Swift 3
dispatch_group_enter(preapreWaitingGroup);
[self doAsynchronousTaskWithComplete:^(id someResults, NSError *error) {
// Notify that this task has been completed.
dispatch_group_leave(preapreWaitingGroup);
}]
dispatch_group_enter(preapreWaitingGroup);
[self doOtherAsynchronousTaskWithComplete:^(id someResults, NSError *error) {
dispatch_group_leave(preapreWaitingGroup);
}]
dispatch_group_notify(preapreWaitingGroup, dispatch_get_main_queue(), ^{
// This block will be executed once all above threads completed and call dispatch_group_leave
NSLog(@"Prepare completed. I'm readyyyy");
});
prepareGroup.enter()
doOtherAsynchronousTaskWithComplete() { (someResults, error) in
// Notify that this task has been completed.
prepareGroup.leave()
}
prepareGroup.notify(queue: DispatchQueue.main) {
// This block will be executed once all above threads completed and call dispatch_group_leave
print("Prepare completed. I'm readyyyy")
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//Perform expensive tasks
//...
//Now before updating the UI, ensure we are back on the main thread
dispatch_async(dispatch_get_main_queue(), ^{
label.text = //....
});
}
Whenever you update views on the screen, always ensure you are doing so on the main thread, otherwise
undefined behavior could occur.
dispatch_async(dispatch_queue_create("Foo", DISPATCH_QUEUE_CONCURRENT), ^{
for (int i = 0; i < 100; i++) {
NSLog(@"Foo");
usleep(100000);
}
});
This will log "Foo" 100 times, pausing for 100ms each time it logs, but it will do all this on a separate thread. While
Foo is being logged, "Bar" will also be logged in 50ms intervals, at the same time. You should ideally see an output
with "Foo"s and "Bars" mixed together
// Set colors.
gradientLayer.colors = [topColor, bottomColor]
Result :
// Set receiver to remain visible in its final state when the animation is completed.
animation.fillMode = kCAFillModeForwards
// Set linear pacing, which causes an animation to occur evenly over its duration.
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
Result :
// Set colors.
gradientLayer.colors = [topColor, bottomColor]
Result :
// Set colors.
gradientLayer.colors = [topColor, middleColor, bottomColor]
Result :
// Set colors.
gradientLayer.colors = [topColor, middleColor, bottomColor]
Result :
import SafariServices
//Objective-C
@import SafariServices;
Optionally you can also tell SafariViewController to enter reading mode if possible once it's done loading.
The default Reading List can be nil if access to the Reading List is not permitted.
Additionally you can check if the Reading List supports a URL by calling supportsURL.
SSReadingList.default().supportsURL(URL(string: "https://example.com")!)
This will return either true or false indicating if the given URL is supported by Safari Reading List. Use this for
example to determine whether to show a button to add a URL to the Reading List.
There are a number of different transforms you can do on a layer, but the basic ones are
translate (move)
scale
rotate
To do transforms on a CALayer, you set the layer's transform property to a CATransform3D type. For example, to
translate a layer, you would do something like this:
The word Make is used in the name for creating the initial transform: CATransform3DMakeTranslation. Subsequent
transforms that are applied omit the Make. See, for example, this rotation followed by a translation:
Now that we have the basis of how to make a transform, let's look at some examples of how to do each one. First,
though, I'll show how I set up the project in case you want to play around with it, too.
Setup
For the following examples I set up a Single View Application and added a UIView with a light blue background to
the storyboard. I hooked up the view to the view controller with the following code:
import UIKit
func addSubLayer() {
myLayer.frame = CGRect(x: 0, y: 0, width: 100, height: 40)
myLayer.backgroundColor = UIColor.blueColor().CGColor
myLayer.string = "Hello"
myView.layer.addSublayer(myLayer)
}
func transformExample() {
There are many different kinds of CALayer, but I chose to use CATextLayer so that the transforms will be more clear
visually.
Translate
where tx is the change in the x coordinates, ty is the change in y, and tz is the change in z.
Example
In iOS the origin of the coordinate system is in the top left, so if we wanted to move the layer 90 points to the right
and 50 points down, we would do the following:
Notes
Remember that you can paste this into the transformExample() method in the project code above.
Since we are just going to deal with two dimensions here, tz is set to 0.
The red line in the image above goes from the center of the original location to the center of the new
location. That's because transforms are done in relation to the anchor point and the anchor point by default
is in the center of the layer.
The scale transform stretches or squishes the layer. The basic syntax is
where sx, sy, and sz are the numbers by which to scale (multiply) the x, y, and z coordinates respectively.
Example
If we wanted to half the width and triple the height, we would do the following
Notes
Since we are only working in two dimensions, we just multiply the z coordinates by 1.0 to leave them
unaffected.
The red dot in the image above represents the anchor point. Notice how the scaling is done in relation to the
anchor point. That is, everything is either stretched toward or away from the anchor point.
Rotate
The rotation transform rotates the layer around the anchor point (the center of the layer by default). The basic
syntax is
where angle is the angle in radians that the layer should be rotated and x, y, and z are the axes about which to
rotate. Setting an axis to 0 cancels a rotation around that particular axis.
Example
Notes
Since we are working in two dimentions, we only want the xy plane to be rotated around the z axis. Thus we
set x and y to 0.0 and set z to 1.0.
This rotated the layer in a clockwise direction. We could have rotated counterclockwise by setting z to -1.0.
The red dot shows where the anchor point is. The rotation is done around the anchor point.
Multiple transforms
However, we will just do one after another. The first transform will use the Make in its name. The following
transforms will not use Make, but they will take the previous transform as a parameter.
Example
// translate
var transform = CATransform3DMakeTranslation(90, 50, 0)
// rotate
transform = CATransform3DRotate(transform, radians, 0.0, 0.0, 1.0)
Notes
We did all our transforms above without changing the anchor point. Sometimes it is necessary to change it, though,
like if you want to rotate around some other point besides the center. However, this can be a little tricky.
The anchor point and position are both at the same place. The anchor point is expressed as a unit of the layer's
coordinate system (default is 0.5, 0.5) and the position is expressed in the superlayer's coordinate system. They
can be set like this
If you only set the anchor point without changing the position, then the frame changes so that the position will be
in the right spot. Or more precisely, the frame is recalculated based on the new anchor point and old position. This
usually gives unexpected results. The following two articles have an excellent discussion of this.
See also
self.layer.shadowOpacity = 0.2;
shadowRadius - this is the blur radius (equivalent of the blur property in Sketch or Photoshop)
shadowPath - this is an important property for performance, when unset iOS bases the shadow on the alpha
channel of the view, which can be performance intensive with a complex PNG with alpha. This property lets
you force a shape for your shadow and be more performant because of it.
Objective-C
Swift 3
import QuartzCore
// intensity of appearance
var intensity: Float!
func setup() {
// initialization
colors = [UIColor.redColor(),
UIColor.greenColor(),
UIColor.blueColor()
]
intensity = 0.2
active = false
}
func startConfetti() {
emitter = CAEmitterLayer()
emitter.emitterCells = cells
layer.addSublayer(emitter)
active = true
}
func stopConfetti() {
emitter?.birthRate = 0
active = false
}
// WARNING: A layer can set this property to a CGImageRef to display the image as its
contents.
confetti.contents = UIImage(named: "confetti")?.CGImage
return confetti
}
The particles are drawn above the layer’s background color and border.
emitter.emitterCells = cells
layer.addSublayer(emitter)
If you wish to add the image in its own layer, you can do it like this:
The above code produces a view like this. The light blue is the UIView and the dark blue star is the UIImage.
As you can see, though, it looks pixelated. This is because the UIImage is smaller than the UIView so it is being
scaled to fill the view, which is the default it you don't specify anything else.
The examples below show variations on the layer's contentsGravity property. The code looks like this:
In iOS, you may want to set the geometryFlipped property to true if you are doing anything with top or bottom
gravity, otherwise it will be the opposite of what you expect. (Only the gravity is flipped vertically, not the content
rendering. If you are having trouble with the content being flipped, see this Stack Overflow answer.)
There are two UIView examples below for every contentsGravity setting, one view is larger than the UIImage and
the other is smaller. This way you can see the effects of the scaling and gravity.
kCAGravityResize
kCAGravityResizeAspectFill
kCAGravityCenter
kCAGravityTop
kCAGravityLeft
kCAGravityRight
kCAGravityTopLeft
kCAGravityBottomLeft
kCAGravityBottomRight
Related
Notes
Swift
CATransaction.begin()
CATransaction.setDisableActions(true)
Objective-C
[CATransaction begin];
[CATransaction setDisableActions:YES];
[CATransaction commit];
A demo on XMPP in Objective C, with various simple and complex features implemented in it. All the features of
XMPP is done by "in band" xmpp functions. Few features this project contains are --
SRXMPP - A wrapper Singleton class that almost has all features needed for one-to-one chat application.
Steps to follow
You want to use this project as a reference then you can do the following--
2. Want to try it out without a hassle in your own computer - You need to download, install and setup 3 things
to start
a. Java -
b. XAMPP -
c. Openfire -
.
Next complete setup by giving a username and password and reconfirming it. Thats it your done
Setting up Openfire.
Now the part comes when you have to change a tiny detail in the code.
#Important We need to go to the class - SRXMPP.m, locate the NSString extern SRXMPP_Hostname (in the top)
and overwrite the value of it to the
Thats it, you are ready to use this example project and start coding and making it into a better project of your own.
This starter pack will help you in understanding XMPP structure better as well as getting a grasp into XMPP
protocols.
Development is still left and parts where I hope to include them later on
1. Group Chat
2. Image sending support
In short this example project along with the singleton has almost all features that are needed for a One-to-One chat
application to have.
If you have an existing class that you'd like to use, perform Step 2 and then skip to Step 5. (For some
cases, I had to add an explicit #import <Foundation/Foundation.h to an older ObjC File)
When adding your .m file, you'll likely be hit with a prompt that looks like this:
Click YES !
If you did not see the prompt, or accidentally deleted your bridging header, add a new .h file to your project and
name it <#YourProjectName#>-Bridging-Header.h
In some situations, particularly when working with ObjC frameworks, you don't add an Objective-C class explicitly
and Xcode can't find the linker. In this case, create your .h file named as mentioned above, then make sure you link
its path in your target's project settings like so:
It's best practice to link your project using the $(SRCROOT) macro so that if you move your project, or work on it with
others using a remote repo, it will still work. $(SRCROOT) can be thought of as the directory that contains your
.xcodeproj file. It might look like this:
$(SRCROOT)/Folder/Folder/<#YourProjectName#>-Bridging-Header.h
In CustomObject.h
#import <Foundation/Foundation.h>
- (void) someMethod;
@end
In CustomObject.m
@implementation CustomObject
- (void) someMethod {
NSLog(@"SomeMethod Ran");
}
@end
In YourProject-Bridging-Header.h:
#import "CustomObject.h"
In SomeSwiftFile.swift:
In MySwiftObject.swift:
import Foundation
init() {}
In SomeRandomClass.m:
#import "<#YourProjectName#>-Swift.h"
The file:<#YourProjectName#>-Swift.h should already be created automatically in your project, even if you can not
Note:
1. CodeCompletion wasn't behaving as accurately as I'd like it to. On my system, running a quick build w/ "cmd + r"
seemed to help Swift find some of the Objc code and vice versa.
2. If you add .swift file to an older project and get error: dyld: Library not loaded:
@rpath/libswift_stdlib_core.dylib, try completely restarting Xcode.
3. While it was originally possible to use pure Swift classes in Objective-C by using the @objc prefix, after Swift 2.0,
this is no longer possible. See edit history for original explanation. If this functionality is reenabled in future Swift
versions, the answer will be updated accordingly.
Once the fonts have been set in the Info.plist, you can use your custom fonts as any other font in IB or
programatically.
1. Drag and drop your font to Xcode Supporting Files folder. Don't forget to mark your app at "Add to targets"
section. From this moment you can use this font in IB and choose it from font pallet.
2. To make this font available on the device, open Info.plist and add Fonts provided by application key
(UIAppFonts). Add font name as the value to the Item 0 key. Note: Font name can vary from your font file
name.
[Swift 3]
[Objective - C]
(You will likely need to toggle the Bar Tint for the Navigation Bar before Xcode picks up the new font)
Notes (Caveats)
Verified that this does work on Xcode 7.1.1+. (See the Samples below)
1. You do need to toggle the nav bar tint before the font takes effect (seems like a bug in Xcode; you can switch
it back to default and font will stick)
2. If you choose a system font ~ Be sure to make sure the size is not 0.0 (Otherwise the new font will be
ignored)
3. Seems like this works with no problem when only one NavBar is in the view hierarchy. It appears that
secondary NavBars in the same stack are ignored. (Note that if you show the master navigation controller's
navBar all the other custom navBar settings are ignored).
Gotchas (deux)
Some of these are repeated which means they are very likely worth noting.
Result
Samples
Note ~ A nice checklist can be found from the Code With Chris website and you can see the sample download project.
If you have your own font and want to use that in your storyboard, then there is a decent set of answers on the
following SO Question. One answer identifies these steps.
So Xcode naturally looks like it can handle custom fonts on UINavigationItem but that feature is just not updating
properly (The font selected is ignored).
One way is to fix using the storyboard and adding a line of code: First add a UIView (UIButton, UILabel, or
some other UIView subclass) to the View Controller (Not the Navigation Item...Xcode is not currently
allowing one to do that). After you add the control you can modify the font in the storyboard and add a
reference as an outlet to your View Controller. Just assign that view to the UINavigationItem.titleView. You
could also set the text name in code if necessary. Reported Bug (23600285).
//Sometime later...
self.navigationItem.titleView = customFontTitleView
Steps to follow
1. Font File: Add the Font file (.ttf) to the application bundle and add the entry for the font in Info.plist
under Font provided by application as in this documentation of custom fonts.
2. Define Categories: Add a file like UIKit+IBExtensions and add the categories for UI elements like
UIKit+IBExtensions.h
#import <UIKit/UIKit.h>
3. Getters and Setters: Define getters and setters for the fontName property towards each category
added.
UIKit+IBExtensions.m
#import "UIKit+IBExtensions.h"
- (NSString *)fontName {
return self.font.fontName;
}
- (void)setFontName:(NSString *)fontName {
self.font = [UIFont fontWithName:fontName size:self.font.pointSize];
}
@end
- (NSString *)fontName {
return self.font.fontName;
}
- (void)setFontName:(NSString *)fontName {
self.font = [UIFont fontWithName:fontName size:self.font.pointSize];
}
@end
- (NSString *)fontName {
return self.titleLabel.font.fontName;
- (void)setFontName:(NSString *)fontName{
self.titleLabel.font = [UIFont fontWithName:fontName size:self.titleLabel.font.pointSize];
}
@end
4. Setting font in storyboard: Add an entry in User Defined Runtime Attributes with fontName as
keyPath and your Custom Font's Name as value with type as String as shown.
This will set your custom font while running the app.
Notes:
Objective C
Swift
"str" = "str-language";
//Try to provide description on the localized string to be able to create a proper documentation if
needed
NSString *str = NSLocalizedString(@"string", @"description of the string");
Alamofire.request(.GET, "https://httpbin.org/get")
func initiateRegion(ref:BeaconHandler){
let uuid: NSUUID = NSUUID(UUIDString: "<UUID>")
let beacon = CLBeaconRegion(proximityUUID: uuid, identifier: "")
locationManager?.requestAlwaysAuthorization() //cllocation manager obj.
beacon?.notifyOnEntry = true
beacon?.notifyOnExit = true
beacon?.notifyEntryStateOnDisplay = true
locationManager?.startMonitoringForRegion(beacon!)
locationManager?.delegate = self;
// Check if beacon monitoring is available for this device
if (!CLLocationManager.isMonitoringAvailableForClass(CLBeaconRegion)) {
print("error")
}
locationManager!.startRangingBeaconsInRegion(self.beacon!)
}
E.g. In the above example code above, location changes of less than 5 metres won’t be sent to the callback, but
instead be ignored.
root directory -> build phases -> Link Binary With Libraries
Click on the (+) button, look for CoreLocation.framework and click add.
2- Modify the info.plist file to ask for permission to use user location by opening it as source code. Add either of the
following key:value pair under the tag to ask for usage of user's location while the application is in use:
<key>NSLocationWhenInUseUsageDescription</key>
<string>message to display when asking for permission</string>
import CoreLocation
After these steps, we can create a CLLocationManager object as instance variable and use it in the ViewController.
var manager:CLLocationManager!
We do not use 'let' here because we will modify the manager to specify its delegate, minimum distance before
update event, and its accuracy
//specify delegate
manager.delegate = self
//set the minimum distance the phone needs to move before an update event is triggered (for
example: 100 meters)
manager.distanceFilter = 100
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestLocation()
} else {
manager.startUpdatingLocation()
Now to get access to the location updates, we can implement the function below which is called overtime the
distanceFilter is reached.
The locations parameter is an array of CLLocation objects that represent the actual location of the device.From
these objects, one can get access to the following attributes: coordinate,altitude, floor, horizontalAccuracy,
verticalAccuracy, timestamp, description, course, speed, and a function distance(from:) that measures
the distance between two locations.
Note: While requesting permission for location, there are two different types of authorization.
"When In Use" authorization only gives the app permission to receive your location when the app is in use
or foreground.
“Always" authorization, gives the app background permissions which may lead to decrease battery life in
case your app is closed.
Objective-C
NSString *version = @"3.1.3";
NSString *currentVersion = @"3.1.1";
NSComparisonResult result = [currentVersion compare:version options:NSNumericSearch];
switch(result){
case: NSOrderedAscending:
//less than the current version
break;
case: NSOrderedDescending:
case: NSOrderedSame:
// equal or greater than the current version
break;
}
Objective-C
Swift
let version = UIDevice.currentDevice().systemVersion
Swift 3
let version = UIDevice.current.systemVersion
1. Configuring the app’s entitlement, and enabling the universal links by turning on the Associated Domains
capability in the project.
2. Handling Incoming Links in your AppDelegate.
The first step in configuring your app’s entitlements is to enable it for your App ID. Do this in the Apple Developer
Member Center. Click on Certificates, Identifiers & Profiles and then Identifiers. Select your App ID (create it first if
required), click Edit and enable the Associated Domains entitlement.
The App ID prefix and suffix should match the one in the apple-app-site-association file.
Next in Xcode, select your App’s target, click Capabilities and toggle Associated Domains to On. Add an entry for
each domain that your app supports, prefixed with app links:
Note: Ensure you have selected the same team and entered the same Bundle ID as the registered App ID on the
Member Center. Also ensure that the entitlements file is included by Xcode by selecting the file and in the File
Inspector, ensure that your target is checked.
All redirects from Safari to the app for universal links go via the below method in the Application's AppDelegate
class. You parse this URL to determine the right action in the app.
Objective-C
-(BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler{
///Checking whether the activity was from a web page redirect to the app.
if ([userActivity.activityType isEqualToString: NSUserActivityTypeBrowsingWeb]) {
///Getting the URL from the UserActivty Object.
NSURL *url = userActivity.webpageURL;
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UINavigationController *navigationController = (UINavigationController
*)_window.rootViewController;
if ([url.pathComponents containsObject:@"home"]) {
[navigationController pushViewController:[storyBoard
instantiateViewControllerWithIdentifier:@"HomeScreenId"] animated:YES];
}else if ([url.pathComponents containsObject:@"about"]){
[navigationController pushViewController:[storyBoard
instantiateViewControllerWithIdentifier:@"AboutScreenId"] animated:YES];
}
}
return YES;
}
Swift :
func application(application: UIApplication, continueUserActivity userActivity: NSUserActivity,
If your app targets iOS 9 and your server uses HTTPS to serve content, you don’t need to sign the file. If not (e.g.
when supporting Handoff on iOS 8), it has to be signed using a SSL certificate from a recognized certificate
authority.
Note: This is not the certificate provided by Apple to submit your app to the App Store. It should be provided by a
third-party, and it’s recommended to use the same certificate you use for your HTTPS server (although it’s not
required).
To sign the file, first create and save a simple .txt version of it. Next, in the terminal, run the following command:
This will output the signed file in the current directory. The example.com.key, example.com.pem, and
intermediate.pem are the files that would made available to you by your Certifying Authority.
Note: If the file is unsigned, it should have a Content-Type of application/json. Otherwise, it should be
application/pkcs7-mime.
The apple-app-site-association file needs to be accessible via HTTPS, without any redirects, at
https://{domain}/apple-app-site-association.
The order in which the paths are mentioned in the array is important. Earlier indices have higher priority. Once a
path matches, the evaluation stops, and other paths ignored. Each path is case-sensitive.
#Website Code
[self drawText];
UIGraphicsEndPDFContext();
fileName is the document file where You are going to append or attach
Where drawText is
(void)drawText
{
NSString* textToDraw = @"Lorem Ipsum is simply dummy text of the printing and typesetting
industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an
unknown printer took a galley of type and scrambled it to make a type specimen book.";
CGContextSetTextMatrix(currentContext, CGAffineTransformIdentity);
CGContextTranslateCTM(currentContext, 0, 450);
CGContextScaleCTM(currentContext, 2, -2);
CFRelease(frameRef);
CFRelease(stringRef);
CFRelease(framesetter);
}
NSArray *arrayPaths =
NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory,
NSUserDomainMask,
YES);
[webView loadRequest:request];
[self.view addSubview:webView];
UIGraphicsEndPDFContext();
- (NSData*) printToPDF;
@end
- (NSData*) printToPDF
{
NSMutableData *pdfData = [NSMutableData data];
UIGraphicsBeginPDFContextToData( pdfData, self.paperRect, nil );
[self prepareForDrawingPages: NSMakeRange(0, self.numberOfPages)];
CGRect bounds = UIGraphicsGetPDFContextBounds();
for ( int i = 0 ; i < self.numberOfPages ; i++ )
{
UIGraphicsBeginPDFPage();
[self drawPageAtIndex: i inRect: bounds];
}
UIGraphicsEndPDFContext();
return pdfData;
}
@end
-(void)createPDF:(UIWebView *)webView {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if (pdfData) {
[pdfData writeToFile:directoryPath atomically: YES];
}
else
{
NSLog(@"PDF couldnot be created");
}
});}
import StoreKit
product_id = "YOUR_PRODUCT_ID"
super.viewDidLoad()
SKPaymentQueue.defaultQueue().addTransactionObserver(self)
// Hide ads
adView.hidden = true
} else {
print("Should show ads...")
{
print("Received Payment Transaction Response from Apple");
if (SKPaymentQueue.canMakePayments()) {
SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
}
First
import StoreKit
Then you will need to fill out all of the information for your IAP.
If you have any trouble you can consult the IAP Set Up Guide.
CGContextSetLineWidth(context, 5.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGContextMoveToPoint(context, 200, 400);
CGContextAddLineToPoint(context, 100, 100);
CGContextStrokePath(context);
CGColorSpaceRelease(colorspace);
CGContextSetTextMatrix(currentContext, CGAffineTransformIdentity);
CGContextTranslateCTM(currentContext, 200, 300);
CGContextScaleCTM(currentContext, 2, -2);
CTFrameDraw(frameRef, currentContext);
CFRelease(frameRef);
CFRelease(stringRef);
CFRelease(framesetter);
//Swift
let status: CLAuthorizationStatus = CLLocationManager.authorizationStatus()
//Objective-C
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
//Swift
switch status {
case .NotDetermined:
// Do stuff
case .AuthorizedAlways:
// Do stuff
case .AuthorizedWhenInUse:
// Do stuff
case .Restricted:
// Do stuff
case .Denied:
// Do stuff
}
//Objective-C
switch (status) {
case kCLAuthorizationStatusNotDetermined:
//The user hasn't yet chosen whether your app can use location services or not.
break;
case kCLAuthorizationStatusAuthorizedAlways:
//The user has let your app use location services all the time, even if the app is in the
background.
break;
case kCLAuthorizationStatusAuthorizedWhenInUse:
//The user has let your app use location services only when the app is in the foreground.
break;
case kCLAuthorizationStatusRestricted:
//The user can't choose whether or not your app can use location services or not, this
could be due to parental controls for example.
break;
case kCLAuthorizationStatusDenied:
//The user has chosen to not let your app use location services.
default:
break;
}
Simplest method is to initialize the location manager as a property of your root view controller and place the
permission request in its viewDidLoad.
//Swift
let locationManager = CLLocationManager()
locationManager.requestWhenInUseAuthorization()
//Objective-C
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
[locationManager requestWhenInUseAuthorization];
Add the NSLocationWhenInUseUsageDescription key to your Info.plist. The value will be used in the alert
controller's message label.
To ask for permission to use location services even when the app is not active, use the following call instead:
//Swift
locationManager.requestAlwaysAuthorization()
//Objective-C
[locationManager requestAlwaysAuthorization];
Then add the NSLocationAlwaysUsageDescription key to your Info.plist. Again, the value will be used in the alert
controller's message label.
<?xml version="1.0"?>
<gpx version="1.1" creator="Xcode">
<!--
Provide one or more waypoints containing a latitude/longitude pair. If you provide one
waypoint, Xcode will simulate that specific location. If you provide multiple waypoints,
Xcode will simulate a route visitng each waypoint.
-->
<wpt lat="52.599878" lon="4.702029">
<name>location name (eg. Florida)</name>
</wpt>
then go to product-->Scheme-->Edit Scheme and into RUN set default location as your GPX file name.
//Swift
import CoreLocation
//Objective-C
#import <CoreLocation/CoreLocation.h>
<key>NSLocationAlwaysUsageDescription</key>
<string>I want to get your location Information in background</string>
Objective C
[_locationManager startUpdatingLocation];
Swift
self.locationManager.delegate = self
self.locationManager.startUpdatingLocation()
1. In your storyboard, drag your UIButton and set it however you want it to be.
2. Ctrl + drag your button to your view controller as IBAction.
3. Inside the IBAction method you will have simulate a tap on the actual Facebook button as follow:
Swift:
Objective-C:
[FBButton sendActionsForControlEvents:UIControlEventTouchUpInside];
You're done.
You can install the SDK manually or via CocoaPods. The latter option is highly recommended.
pod 'FBSDKCoreKit'
pod 'FBSDKLoginKit'
pod 'FBSDKShareKit'
end
Run pod install in the terminal and open .xcworkspace instead of .xcodeproj afterwards.
FBSDKLoginKit and FBSDKShareKit are optional. You may or may not need them.
Facebook will ask you to download the SDK after creating the app. You can skip this part if you installed the SDK via
CocoaPods already.
a. To make your app able to "communicate" with Facebook, you need to put some settings in your .plist file.
Facebook will give you the customized snippet on the Quick Starts page.
c. Paste your customized snippet in the source code. Be careful! The snippet must be exactly the child of the
<dict> tag. Your source code should be something like:
<plist version="1.0">
<dict>
// ...
//some default settings
// ...
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>fb{FBAppId}</string>
</array>
</dict>
</array>
<key>FacebookAppID</key>
<string>{FBAppId}</string>
If you paste the snippet at a wrong place, you will run into problems.
Step 4: Tell Facebook your bundle identifier on the Quick Starts page.
a.
import FBSDKCoreKit
b.
Swift:
if FBSDKAccessToken.currentAccessToken() != nil
{
// Getting user facebook data
FBSDKGraphRequest(graphPath: "me",
parameters: [FacebookParametesField.FIELDS_KEY.rawValue :
FacebookParametesField.FIELDS_VALUE.rawValue])
.startWithCompletionHandler({ (graphConnection : FBSDKGraphRequestConnection!, result : AnyObject!,
error : NSError!) -> Void in
if error == nil
{
print("Facebook Graph phaze")
This example sets a custom thread that dispatch to the completion block:
AFNetworking 2.xx:
// Create dispatch_queue_t with your name and DISPATCH_QUEUE_SERIAL as for the flag
dispatch_queue_t myQueue = dispatch_queue_create("com.CompanyName.AppName.methodTest",
DISPATCH_QUEUE_SERIAL);
AFNetworking 3.xx:
<CallKit/CXCallObserver.h>
self.callObserver = callObserver;
Section 106.2: Intercepting calls from your app even from the
background
From Apple documentation:
Use the CTCallCenter class to obtain a list of current cellular calls, and to respond to state changes for
calls such as from a dialing state to a connected state. Such state changes are known as cellular call
events.
The purpose of CTCallCenter is to give the developer the opportunity to pause his app state during a call in order to
give the user the best experience.
Objective-C:
First, we will define a new class member inside the class we want to handle the interceptions:
Inside our class init (constructor) we will allocate new memory for our class member:
Afterwards, we will invoke our new method that actually handles the interceptions:
- (void)registerPhoneCallListener
{
[[self callCenter] setCallEventHandler:^(CTCall * _Nonnull call) {
NSLog(@"CallEventHandler called - interception in progress");
That's it, if the user will use your app and will receive a phone call you could intercept this call and handle your app
for a save state.
It is worth mentioning that there are 4 call states you can intercept:
CTCallStateDialing
CTCallStateIncoming
CTCallStateConnected
CTCallStateDisconnected
Swift:
Define your class member at the relevant class and define it:
self.callCenter = CTCallCenter()
self.callCenter.callEventHandler = { call in
// Handle your interception
if call.callState == CTCallStateConnected
{
}
}
What will happen if your app is in the background and you need to intercept calls while the app is in the
background ?
For example, if you develop an enterprise app you can basically just add 2 capabilities (VOIP & Background fetch)
in the Capabilities tab:
Your project target -> Capabilities -> Background Modes -> mark Voice over IP & Background fetch
Swift
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions:
[NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
if UIDevice.currentDevice().systemVersion.compare(v, options: .NumericSearch) ==
NSOrderedAscending {
// Register for Push Notitications, if running iOS < 8
if application.respondsToSelector("registerUserNotificationSettings:") {
let types:UIUserNotificationType = (.Alert | .Badge | .Sound)
let settings:UIUserNotificationSettings = UIUserNotificationSettings(forTypes: types,
categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
} else {
// Register for Push Notifications before iOS 8
application.registerForRemoteNotificationTypes(.Alert | .Badge | .Sound)
}
} else {
var center = UNUserNotificationCenter.currentNotificationCenter()
center.delegate = self
center.requestAuthorizationWithOptions((UNAuthorizationOptionSound |
UNAuthorizationOptionAlert | UNAuthorizationOptionBadge)) {(granted: Bool, error: NSError) -> Void
in
if !error {
UIApplication.sharedApplication().registerForRemoteNotifications()
// required to get the app to do anything at all about push notifications
print("Push registration success.")
} else {
print("Push registration FAILED")
print("ERROR: \(error.localizedFailureReason!) - \(error.localizedDescription)")
print("SUGGESTIONS: \(error.localizedRecoveryOptions) -
\(error.localizedRecoverySuggestion!)")
})
}
return true
}
Objective-C
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v
options:NSNumericSearch] == NSOrderedAscending)
[application registerForRemoteNotifications];
}
else
{
// iOS < 8 Notifications
[application registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert |
UIRemoteNotificationTypeSound)];
}
}
else
{
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
[center requestAuthorizationWithOptions:(UNAuthorizationOptionSound |
UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError
* _Nullable error)
{
if( !error )
{
[[UIApplication sharedApplication] registerForRemoteNotifications]; // required to
get the app to do anything at all about push notifications
NSLog( @"Push registration success." );
}
else
{
NSLog( @"Push registration FAILED" );
NSLog( @"ERROR: %@ - %@", error.localizedFailureReason, error.localizedDescription );
NSLog( @"SUGGESTIONS: %@ - %@", error.localizedRecoveryOptions,
error.localizedRecoverySuggestion );
}
}];
}
}
else
{}
//------------------------------------------------
The above code will try to communicate with APNs server to get device token (prerequiesites are you have APNs
enabled in your iOS provisioning profile).
Once it establishes reliable connection with APNs server, the server provides you a device token.
After adding the code above, add these methods to the AppDelegate class:
Swift
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken
deviceToken: NSData) {
print("DEVICE TOKEN = \(deviceToken)")
}
Objective-C
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSString * deviceTokenString = [[[[deviceToken description]
stringByReplacingOccurrencesOfString: @"<" withString: @""]
stringByReplacingOccurrencesOfString: @">" withString: @""]
stringByReplacingOccurrencesOfString: @" " withString: @""];
- (void)application:(UIApplication*)application
didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
NSLog(@"Failed to get token, error: %@", error.description);
}
The above methods are called according to registration success or failure scenario.
Swift
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken
deviceToken: NSData) {
print("DEVICE TOKEN = \(deviceToken)")
}
Objective-C
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
if(application.applicationState == UIApplicationStateInactive) {
NSLog(@"Inactive - the user has tapped in the notification when app was closed or in
background");
//do some tasks
[self handelPushNotification:userInfo];
}
else if (application.applicationState == UIApplicationStateBackground) {
NSLog(@"application Background - notification has arrived when app was in background");
[self handelPushNotification:userInfo];
}
else {
NSLog(@"application Active - notication has arrived while app was opened");
//Show an in-app banner
//do tasks
}
}
Swift
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError
error: NSError) {
print(error)
}
Objective-C
- (void)application:(UIApplication*)application
didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
Note
If none of the above methods are getting called, your device is not able to create reliable connection with
APNs server, which might be because of internet access problems.
1- Log in to developer.apple.com Member Center (the Account link on the home page)
2- Go to "Certificates"
9- From Keychain Access menu, click Certificate Assistant -> Request a Certificate from a Certificate Authority
15- Download the generated file by Apple and open it while Keychain Access is open
1. Save the script as a file (send_push.php for example) in the same folder as your certificate (development or
production)
2. Edit it to put your device token, password from the certificate
3. Choose the correct path for opening a connection, dev_path or prod_path (this is where 'Open a connection
to the APNS server' happens in the script)
4. cd to the folder in Terminal and run command 'php send_push'
<?php
// sample point
$alert = 'Hello world!';
$event = 'new_incoming_message';
// You can choose either of the paths, depending on what kind of certificate you are using
$dev_path = 'ssl://gateway.sandbox.push.apple.com:2195';
$prod_path = 'ssl://gateway.push.apple.com:2195';
////////////////////////////////////////////////////////////////////////////////
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', $cert_name);
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
if (!$fp)
exit("Failed to connect: $err $errstr" . PHP_EOL);
if (!$result)
echo 'Message not delivered' . PHP_EOL;
else
echo 'Message successfully delivered' . PHP_EOL;
2. Open "Keychain access" and export the key that is under that certificate to a .p12 file (call it key.p12). To do
that right click on it and choose Export. Save it to the same folder as step 1. On export you will be prompted
for a password. Make something up and memorize it.
5. Convert your key to .pem format. To open the key, enter the password you exported it with from the
keychain, in step 2. Then, enter another password that will protect the exported file. You will be prompted to
enter it twice for confirmation.
7. The final_cert.pem is the final result. Pass it on to server developers with the password from step 5, so that
they will be able to use the protected certificate.
Objective-C
[[UIApplication sharedApplication] unregisterForRemoteNotifications];
Swift
UIApplication.sharedApplication().unregisterForRemoteNotifications()
NOTE: There may be rare cases where you would need this(eg: when your app no longer supports push
notifications)
If you just want to allow the user to temporarily disable Notifications. You should implement a method to remove
device token in the database on your server. else if you only disable Notification locally on your device your server
will still send messages.
Objective-C
Swift
UIApplication.shared.applicationIconBadgeNumber = someNumber
Then the callback function didRegisterUserNotificationSettings will be called and in that case you just trigger
the register like this:
And in that case and system alert will be shown asking for persmission to receive push notification. One of the
following callback functions will be called:
for i in 0..<deviceToken.length {
tokenString += String(format: "%02.2hhx", arguments: [tokenChars[i]])
}
In very rare cases, neither success or failure callback functions are called. This happens when you have internet
connection problems or the APNS Sandbox is down. The system do an API call to APNS to do some verification,
failing to do so will lead to none of the two callbacks functions will be called. Visit Apple system status to make sure
its fine.
Swift
Objective C
iOS 10
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification
withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
{
NSLog( @"Handle push from foreground" );
// custom code to handle push while app is in the foreground
NSLog(@"%@", notification.request.content.userInfo);
}
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)())completionHandler
{
Notification content consists of: title, subtitle, body and attachment. Attachment can contain images/gifs/videos up
to 50 mb.
Content extension helps us to create custom user interface upon notification expanasion.
You use this framework to define an extension that receives the notification data and provides the corresponding
visual representation. Your extension can also respond to custom actions associated with those notifications.
UNNotificationExtensionCategory (Required)
The value of this key is a string or an array of strings. Each string contains the identifier of a category declared by
the app using the UNNotification?Category class.
UNNotificationExtensionInitialContentSizeRatio (Required)
Number that represents the initial size of your view controller’s view expressed as a ratio of its height to its width.
UNNotificationExtensionDefaultContentHidden (Optional)
When set to YES, the system displays only your custom view controller in the notification interface. When set to NO,
the system displays the default notification content in addition to your view controller’s content.
UNNotificationExtensionOverridesDefaultTitle (Optional)
The value of this key is a Boolean. When set to true, the system uses the title property of your view controller as the
title of the notification. When set to false, the system sets the notification's title to the name of your app. If you do
not specify this key, the default value is set to false.
Push:
{
aps: {
alert: { … },
category: 'io.swifting.notification-category'
}
}
Local:
Making the environment suitable for Notification. Make sure you enabled Background Modes and Push
Notification
Click on the + icon in the bottom which creates a target template and select Notification Content Extention -> next
-> create a name for the content extension -> finish
The dictionary in NSExtension signifies how the notification content is displayed, these are performed on long
pressing the received notification
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().setNotificationCategories([notifCategory])
UIApplication.shared.registerForRemoteNotifications()
We created two UNNotificationAction with identifiers ID1 and ID2 and added those actions to a
UNNotificationCategory with identifier CATID1 (the categoryID in ContentExtension's info.plist file are same, what
we created here should be used in payload and the plist file). We set the category to our application's
UNUserNotificationCenter and in next line we are registering for the notification which calls the
didRegisterForRemoteNotificationsWithDeviceToken function where we get the device token
'aps': {
'badge': 0,
'alert': {
'title': "Rich Notification",
'body': "Body of RICH NOTIFICATION",
},
'sound' : "default",
'category': "CATID1",
'mutable-content':"1",
},
'attachment': "2"
The corresponding actions for the category is automatically displayed while the notification action is performed.
Lets us see the code how its being performed
import UIKit
import UserNotifications
import UserNotificationsUI
self.title = "Koushik"
imageView?.image = UIImage.init(named: "Success.jpeg")
if(response.actionIdentifier == "ID1")
{
imageView?.image = UIImage.init(named: "Success.jpeg")
}
else
{
imageView?.image = UIImage.init(named: "welcome.jpeg")
}
}
}
Step 7: Result
After receiving and long press/Clicking View notification, the notification looks like this
To start observing a property named firstName of an object named personObject do this in the observing class:
[personObject addObserver:self
forKeyPath:@"firstName"
options:NSKeyValueObservingOptionNew
context:nil];
The object that self in the above code refers to will then receive a
observeValueForKeyPath:ofObject:change:context: message whenever the observed key path changes.
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSString *,id> *)change
context:(void *)context
{
NSLog(@"new value of %@ is: %@", keyPath, change[NSKeyValueChangeNewKey]);
}
"Key path" is a KVC term. NSObject subclasses implement KVC functionality by default.
An instance variable named _firstName will be accessible by the @"firstName" key path.
A getter method named firstName will be called when accessing the @"firstName" key path, regardless of there
being a _firstName instance variable or setFirstName setter method.
Context is important if you ship your class for others to use.Context lets your class observer verify that its you
observer which is being called.
The problem with not passing an observer is, if some one subclass your class and register an observer for the same
object,same key and he does not passes a context ,then the super class observer can be called multiple time.
A variable which is unique and internal for your use is a good context.
Usage:
Init(UILabel(frame: CGRect.zero)) {
$0.backgroundColor = UIColor.blackColor()
}
import Foundation
extension Then
//Objective-c
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
//Objective-c
UIViewController *initailScreen = [storyboard instantiateInitialViewController];
//Objective-c
UIViewController *viewController = [storyboard
instantiateViewControllerWithIdentifier:@"identifier"];
as following picture..
AppDelegate.h
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
AppDelegate.m
in application didFinishLaunchingWithOptions
If you want changes as per events you have to add following code in AppDelegate.m
- (void)remoteControlReceivedWithEvent:(UIEvent *)theEvent {
Install fastlane
1. Open a terminal.
2. Run sudo gem install fastlane --verbose
3. If you haven’t installed the Xcode command-line tools yet, run xcode-select --install to install them
4. Now, cd into your project folder (type cd [with the space at the end] and drag your project folder into the
terminal)
5. Run fastlane init to get fastlane setup.
6. Now you can able to use all the Fastlane tools:
iOS Tools
deliver: Upload screenshots, metadata, and your app to the App Store
snapshot: Automate taking localized screenshots of your iOS app on every device
frameit: Quickly put your screenshots into the right device frames
pem: Automatically generate and renew your push notification profiles
sigh: Because you would rather spend your time building stuff than fighting provisioning
produce: Create new iOS apps on iTunes Connect and Dev Portal using the command line
cert: Automatically create and maintain iOS code signing certificates
gym: Building your iOS apps has never been easier
match: Easily sync your certificates and profiles across your team using Git
scan: The easiest way to run tests for your iOS and Mac apps
spaceship: Ruby library to access the Apple Dev Center and iTunes Connect
pilot: The best way to manage your TestFlight testers and builds from your terminal
boarding: The easiest way to invite your TestFlight beta testers
Android Tools
supply: Upload your Android app and its metadata to Google Play
screengrab: Automate taking localized screenshots of your Android app on every device
CGPathCloseSubpath(path);
mask.path = path;
CGPathRelease(path);
self.view.layer.mask = mask;
pathAnimation.duration = 1.5f;
pathAnimation.repeatCount = 10;
pathAnimation.autoreverses = YES;
[circle addAnimation:pathAnimation
forKey:@"strokeEnd"];
Remove ShapeLayer
Keep a reference to that shape layer. For example, you might have a property currentShapeLayer: Now that you
have a reference, you can easily remove the layer:
Type 1:
[self.currentShapeLayer removeFromSuperlayer];
Type 2:
Other Operation
//Subpaths
//UIBezierPath can have any number of “path segments” (or subpaths) so you can effectively draw as
shapeLayer.path = combinedPath;
[[self.view layer] addSublayer:shapeLayer];
//Open Path
// Paths do not need to connect their end points back to their starting points. A path that
connects back to its starting point is called a closed path, and one that does not is called an
open path.
//Fill Rule
//Type 1: kCAFillRuleNonZero
squareLayer = [CAShapeLayer layer];
squareLayer.frame = CGRectMake(0, 140, 150, 150);
squareLayer.lineWidth = 2.0;
squareLayer.fillColor = [[UIColor yellowColor]CGColor];
squareLayer.fillRule = kCAFillRuleNonZero; // indicate the rule type
squareLayer.strokeColor = [[UIColor redColor] CGColor];
UIBezierPath *outerPath = [UIBezierPath bezierPathWithRect:CGRectInset(squareLayer.bounds, 20.0,
20.0)];
UIBezierPath *innerPath = [UIBezierPath bezierPathWithRect:CGRectInset(squareLayer.bounds, 50.0,
50.0)];
CGMutablePathRef combinedPath= CGPathCreateMutableCopy(outerPath.CGPath);
CGPathAddPath(combinedPath, NULL, innerPath.CGPath);
squareLayer.path = combinedPath;
[[self.view layer] addSublayer:squareLayer];
//Type 2: kCAFillRuleEvenOdd
squareLayer = [CAShapeLayer layer];
squareLayer.frame = CGRectMake(140, 140, 150, 150);
squareLayer.lineWidth = 2.0;
squareLayer.fillColor = [[UIColor yellowColor]CGColor];
squareLayer.fillRule = kCAFillRuleEvenOdd; // indicate the rule type
squareLayer.strokeColor = [[UIColor redColor] CGColor];
outerPath = [UIBezierPath bezierPathWithRect:CGRectInset(squareLayer.bounds, 20.0, 20.0)];
innerPath = [UIBezierPath bezierPathWithRect:CGRectInset(squareLayer.bounds, 50.0, 50.0)];
combinedPath= CGPathCreateMutableCopy(outerPath.CGPath);
CGPathAddPath(combinedPath, NULL, innerPath.CGPath);
squareLayer.path = combinedPath;
[[self.view layer] addSublayer:squareLayer];
fillColor
Fill the color based on the drawed shape.
fillRule
Fill Rule the there are two rule is applied to draw the shape.
1. kCAFillRuleNonZero
2. kCAFillRuleEvenOdd
lineCap
Below type used to change the style of the line.
1. kCALineCapButt
2. kCALineCapRound
3. kCALineCapSquare
lineDashPattern
The dash pattern applied to the shape’s path when stroked.
Create DashStyle while you will stroke the line.
lineDashPhase
The dash phase applied to the shape’s path when stroked. Animatable.
lineJoin
Line join style for the shape path.Below style use to draw the line join style.
1. kCALineJoinMiter
2. kCALineJoinRound
3. kCALineJoinBevel
lineWidth
Which using to set the line width.
miterLimit
The miter limit used when stroking the shape’s path. Animatable.
strokeColor
Set the stroke color based on the path of the line.
strokeStart
When the stroke will start.
strokeEnd
When the stroke will end.
Boasting responsive 60fps scrolling, built-in gestures, streamlined communication between app and webpage, and
the same JavaScript engine as Safari, WKWebView is one of the most significant announcements to come out of
WWDC 2014.
window.webkit.messageHandlers.{NAME}.postMessage()
NOTE: adding same "{NAME}" handler with addScriptMessageHandler:name: more than once, results in
NSInvalidArgumentExceptionexception.
self.initControls()
self.setTheme()
self.doLayout()
}
func initControls() {
self.searchbar = UISearchBar()
//WKUserContentController allows us to add Javascript scripts to our webView that will run
either at the beginning of a page load OR at the end of a page load.
self.toolbar = UIToolbar()
self.layoutToolbar()
func setTheme() {
self.edgesForExtendedLayout = UIRectEdge(rawValue: 0)
self.navigationController?.navigationBar.barTintColor = UIColor.white()
func layoutToolbar() {
//Browsers typically have a back button, forward button, refresh button, and
newTab/newWindow button.
self.toolbar.items = items
}
func doLayout() {
//Add the searchBar to the navigationBar.
self.navigationItem.titleView = self.searchbar
constraints.append("H:|-0-[webView]-0-|")
constraints.append("H:|-0-[toolbar]-0-|")
constraints.append("V:|-0-[webView]-0-[toolbar(50)]-0-|")
//Searchbar Delegates
//Toolbar Delegates
//WebView Delegates
//Handle the error. Display an alert to the user telling them what happened.
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: NSError)
{
//This is called when a webView or existing loaded page wants to open a new window/tab.
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for
//The view that represents the new tab/window. This view will have an X button at the top
left corner + a webView.
let container = UIView()
constraints.append("H:|-(-22)-[XButton(44)]")
constraints.append("H:|-0-[webView]-0-|")
constraints.append("V:|-(-22)-[XButton(44)]-0-[webView]-0-|")
//TODO: Add the containerView to self.view or present it with a new controller. Keep track
of tabs..
return webView
}
IFA
isAdvertisingTrackingEnabled: A Boolean value that indicates whether the user has limited ad
tracking.
IFV
Represents UUID strings, which can be used to uniquely identify types, interfaces, and other items.
Swift 3.0
print(UUID().uuidString)
Objective-C
+ (NSString *)randomUUID {
if(NSClassFromString(@"NSUUID")) { // only available in iOS >= 6.0
return [[NSUUID UUID] UUIDString];
}
CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
CFStringRef cfuuid = CFUUIDCreateString(kCFAllocatorDefault, uuidRef);
Swift
let UDIDString = UIDevice.currentDevice().identifierForVendor?.UUIDString
Objective-C
NSString *UDIDString = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
The identifierForVendor is an unique identifier that stays the same for every app of a single vendor on a single
device, unless all of the vendor's apps are deleted from this device. See Apple's documentation about when this
UUID changes.
For example we want to set some custom fonts. Lets create a category that add functionality to UIFont class. Open
your Xcode project, click on File -> New -> File and choose Objective-C file , click Next enter your category name say
"CustomFont" choose file type as Category and Class as UIFont then Click "Next" followed by "Create."
Click "UIFont+CustomFonts.h" to view the new category's header file. Add the following code to the interface to
declare the method.
+(UIFont *)productSansRegularFontWithSize:(CGFloat)size;
@end
Click "UIFont+CustomFonts.m" to view the category's implementation file. Add the following code to create a
method that will set ProductSansRegular Font.
+(UIFont *)productSansRegularFontWithSize:(CGFloat)size{
#import "UIFont+CustomFonts.h"
Objective-C:
NSURL *url = [NSURL URLWithString:@"mailto://[email protected]"];
if ([[UIApplication sharedApplication] canOpenURL:url]) {
[[UIApplication sharedApplication] openURL:url];
} else {
NSLog(@"Cannot open URL");
}
Objective-C
Swift:
Objective-C
Swift:
HTML
<a href="tel:1-408-555-5555">1-408-555-5555</a>
Objective-C
Swift:
HTML
Objective-C
Swift:
HTML
Objective-C
Swift:
HTML
You can also include a subject field, a message, and multiple recipients in the To, Cc, and Bcc fields. (In iOS, the from
attribute is ignored.) The following example shows a mailto URL that includes several different attributes:
mailto:[email protected][email protected]&subject=Greetings%20from%20Cupertino!&body=Wish%20you%20w
ere%20here!
Note: Compose email dialog can also be presented within app using MFMailComposeViewController.
@end
@implementation BaseModel
+ (NSString *)primaryKey
{
return @"uuid";
}
+ (NSDictionary *)defaultPropertyValues
{
NSMutableDictionary *defaultPropertyValues = [NSMutableDictionary
dictionaryWithDictionary:[super defaultPropertyValues]];
NSString *uuid = [[NSUUID UUID] UUIDString];
[defaultPropertyValues setValue:@"" forKey:@"metadata"];
[defaultPropertyValues setValue:uuid forKey:@"uuid"];
return defaultPropertyValues;
}
+ (NSArray *)ignoredProperties
{
return @[];
}
@end
Swift
// build HTML header for dynamic type and responsive design
func buildHTMLHeader() -> String {
return patternText
Objective-C
[UIApplication sharedApplication].preferredContentSizeCategory;
This returns a content size category constant, or an accessibility content size category constant.
Swift
@IBOutlet var label:UILabel!
if #available(iOS 10.0, *) {
label.adjustsFontForContentSizeCategory = true
} else {
// Observe for UIContentSizeCategoryDidChangeNotification and handle it manually
// since the adjustsFontForContentSizeCategory property isn't available.
}
Swift
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(updateFont), name:
name:UIContentSizeCategoryDidChangeNotification, object: nil)
Objective-C
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateFont)
name:UIContentSizeCategoryDidChangeNotification object:nil];
The notification userInfo object contains the new size under UIContentSizeCategoryNewValueKey.
and add
#import "SWRevealViewController.h"
Then rename the viewController on files to MainViewController and add new ViewController with
RightViewController name
after this we need to do the same with the segue (from SWRevealViewController to RightViewController)
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer());
And this is all, you have a basic app with SWRevealViewController integrated, you can swipe to right to show
RightViewController as lateral menu
Concurrency
When using a DispatchGroup, for each request, you enter the group and for each completed request, you leave
the group.
When there are no longer requests in the group, you will be notify (notified).
Usage:
import UIKit
//Process Response..
//Process Response..
//Get notified on the main thread/queue.. when ALL of the tasks above has been completed.
dispatchGroup.notify(queue: DispatchQueue.main) {
With the above, you don't have to wait infinitely until all the tasks are completed. You can display a loader BEFORE
all the tasks have started and dismiss the loader AFTER all tasks are completed. This way, your main thread does
not get blocked and your code remains clean.
Now suppose you also wanted the tasks to be ordered or add their responses to an array sequentially. You could
do the following:
import UIKit
//Locking mechanism..
func synchronized(_ lock: AnyObject, closure: () -> Void) {
objc_sync_enter(lock)
closure()
objc_sync_exit(lock)
}
//Process Response..
//Get notified on the main thread.. when ALL of the requests above has been completed.
dispatchGroup.notify(queue: DispatchQueue.main) {
for i in 0..<self.responseArray.count {
if self.responseArray[i] == nil {
print("Request #\(i) Failed.\n")
}
else {
print("Request #\(i) Succeeded.\n")
}
}
}
//Two tasks added to the array. Responses are assumed nil until they complete.
self.responseArray.append(nil)
self.responseArray.append(nil)
Notes
Every entry must have an exit in a DispatchGroup. If you forget to leave after entering, you are setting yourself up.
You will NEVER be notified when the tasks are completed.
A scenario for when to use a semaphore could be if you are doing some file reading/writing, if multiple tasks are
trying to read and write from file at the same time, it could increase your performance to make each task wait its
turn so as to not overburden the I/O controller.
Swift 3
func do2TasksAtATime () {
print("starting long running tasks (2 at a time)")
let sem = DispatchSemaphore(value: 2) //this semaphore only allows 2 tasks to run at
the same time (the resource count)
for i in 0...7 { //launch a bunch of tasks
DispatchQueue.global().async { //run tasks on a background thread
sem.wait() //wait here if no resources available
sleep(2) //do some long task eg file access (here we
are just sleeping for a 2 seconds for demonstration purposes)
print("long task \(i) done! \(Date())")
sem.signal() //let the semaphore know this resource is now
available
}
}
}
DispatchGroup allows for aggregate synchronization of work. You can use them to submit multiple
different work items and track when they all complete, even though they might run on different queues.
This behavior can be helpful when progress can’t be made until all of the specified tasks are complete.
Swift 3
func doLongTasksAndWait () {
print("starting long running tasks")
let group = DispatchGroup() //create a group for a bunch of tasks we are about to do
for i in 0...3 { //launch a bunch of tasks (eg a bunch of webservice calls
that all need to be finished before proceeding to the next ViewController)
group.enter() //let the group know that something is being added
DispatchQueue.global().async { //run tasks on a background thread
sleep(arc4random() % 4) //do some long task eg webservice or database lookup (here
we are just sleeping for a random amount of time for demonstration purposes)
print("long task \(i) done!")
group.leave() //let group know that the task is finished
}
}
group.wait() //will block whatever thread we are on here until all the
above tasks have finished (so maybe don't use this function on your main thread)
print("all tasks done!")
}
Alternatively, if you do not want to wait for the groups to finish, but instead want to run a function once all the tasks
have completed, use the notify function in place of the group.wait()
group.notify(queue: DispatchQueue.main) { //the queue: parameter is which queue this block will run
on, if you need to do UI updates, use the main queue
print("all tasks done!") //this will execute when all tasks have left the group
}
Example output:
For more info, refer to the Apple Docs or the related topic
You need to get to the main queue in order to update UI on completion of an asynchronous process like
NSURLSession
There are two types of main queue calls synchronous and asynchronous. When you invoke something
synchronously, it means that the thread that initiated that operation will wait for the task to finish before
continuing. Asynchronous means that it will not wait.
Code Objective-C
dispatch_async(dispatch_get_main_queue(), ^{
// do work here to Usually to update the User Interface
});
SWIFT 3
DispatchQueue.main.async {
DispatchQueue.main.sync {
Objective-C
Swift
// Before Swift 3
let queue = dispatch_queue_create("com.example.myqueue", DISPATCH_QUEUE_SERIAL)
// Swift 3
let queue = DispatchQueue(label: "com.example.myqueue") //default is serial queue, unless
.concurrent is specified as an attribute otherwise
Serial Queue
func serialQueues () {
let serialQueue = DispatchQueue(label: "com.example.serial") //default queue type is a serial
queue
let start = Date ()
for i in 0...3 { //launch a bunch of tasks
serialQueue.async { //run tasks on a background
thread, using our serial queue
sleep(2) //do some long task eg webservice
or database lookup
let timeTaken = Date().timeIntervalSince(start)
Example output:
Concurrent Queue
func concurrentQueues () {
let concurrentQueue = DispatchQueue(label: "com.example.concurrent", attributes: .concurrent)
//explicitly specify the queue to be a concurrent queue
let start = Date ()
for i in 0...3 { //launch a bunch of tasks
concurrentQueue.async { //run tasks on a background thread, using our concurrent queue
sleep(2) //do some long task eg webservice or database lookup
let timeTaken = Date().timeIntervalSince(start)
print("concurrent long task \(i) done! total time taken: \(timeTaken)")
}
}
}
Example output:
Discussion
As we can see from the examples above, a serial queue will complete each task in the order they are submitted to
the queue. Each task will wait for the previous task to finish before executing. As for the concurrent queue, each
task does not wait on the others in the queue and executes as soon as possible; the advantage is that all tasks on
the queue will run at the same time on separate threads, making a concurrent queue take less time than a serial
queue.
If order of execution of tasks is not important, always use a concurrent queue for the best efficiency.
Apple defines two size classes: regular and compact. Each of these size classes are available on both axes of the
device (horizontal and vertical). Your app may exist in any these four states throughout its lifetime. As a
shorthand, developers often describe a size class combination by saying or writing the two size classes, with the
horizontal axis first: "Compact/Regular" describes an interface that is horizontally compact but vertically regular.
In your app, use methods on the UITraitEnvironment protocol to check your current size class and respond to
changes:
Both UIView and UIViewController conform to UITraitEnvironment, so you can look at your current trait collection
and handle changes in subclasses of either.
For example, consider an app that uses a UIStackView to arrange two UILabels. We might want these labels to stack
on top of each other in horizontally compact environments, but sit next to each other when we have a little more
room in horizontally regular environments.
stackView = UIStackView()
for text in ["foo", "bar"] {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = text
stackView.addArrangedSubview(label)
}
The easiest way for existing apps to opt in to multitasking is to create such a storyboard, then set it as the project's
Launch Screen:
//ViewController.h
#import <UIKit/UIKit.h>
@end
//ViewController.m
#import "ViewController.h"
@implementation ViewController
@synthesize myLabel;
-(void) viewDidLoad {
[super viewDidLoad];
//Editing the properties of the outlet
myLabel.text = @"TextHere";
@end
And swift:
import UIKit
class ViewController: UIViewController {
//This is the declaration of the outlet
@IBOutlet weak var myLabel: UILabel!
The connection between the storyboard object, and the programmed object can be verified as connected if the dot
to the left of the declaration of the outlet in the .h is filled. An empty circle implied an incomplete connection.
Let's start, first, we should create an enum that represent the S3 configuration:
Now, we should set the credentials when your app launch for the first time, thus, we should set them inside the
AppDelegate at the didFinishLaunchingWithOptions method (pay attention that you should set your region at the
regionType param):
Since we are already inside the AppDelegate, we should implement the background callback that is handled by the
AWS SDK:
Now, when the user will move the app to the background your upload will continue the actual upload.
In order to upload the file using the AWS SDK we will have to write the file to the device and give the SDK the actual
path. For the sake of the example, imagine we have a UIImage (could be a video also..) and we will write it to a temp
folder:
// Some image....
FileURL and fileName will be used for the actual uploading later.
There are 2 closures we will have to define that are provided by the AWS SDK,
If you plan to have a Singleton you should define those types as class members. The implementation should look
like this:
if ((error) != nil)
{
print("Upload failed")
}
else
{
print("File uploaded successfully")
}
}
NOTE: If you are using a Singleton you might want to define a delegate that will report back with progress or when
the file is done. If you are not using a Singleton you can create a static method that would have the relevant types:
let transferUtility =
AWSS3TransferUtility.S3TransferUtilityForKey(S3Configuration.CALLBACK_KEY.rawValue)
transferUtility?.uploadData(fileData!,
bucket: S3Configuration.BUCKET_NAME.rawValue,
key: fileName,
contentType: S3Configuration.CONTENT_TYPE_IMAGE.rawData,
expression: expression,
completionHander: completionHandler).continueWithBlock
{ (task : AWSTask) -> AnyObject? in
return nil
}
Happy S3 uploading :)
Most EXC_BAD_ACCESS errors are caused by trying to dereference a NULL pointer. If this is the case, the address
listed in the red arrow will usually be a hexadecimal number that is lower than a normal memory address, often
0x0. Set breakpoints in the debugger or add occasional printf/NSLog statements to find out why that pointer is
NULL.
An EXC_BAD_ACCESS that occurs less reliably or makes no sense at all could be the result of a memory management
problem. Common problems that can cause this are:
In the Diagnostics section of the Scheme Editor, Xcode includes a few useful tools to help debug memory problems:
The Address Sanitizer adds lots of checks that will stop the app whenever memory problems occur and provide a
helpful error message detailing exactly what happened. Zombie Objects detects problems with deallocated
Objective-C objects, but you shouldn't get these kinds of problems with Automatic Reference Counting turned on.
The red arrow displays which line of code crashed & why it crashed.
Many crashes log more information to the debugger console. It should automatically appear when the app crashes,
but if it's not there, show the debugger by selecting the button in the top-right corner of Xcode, and show the
The stack trace lists the functions the program came from before it got to the code that crashed.
Part of the stack trace is displayed in the Debug Navigator on the left of the screen, and the debugger controls allow
you to select a stack frame to view in the debugger:
(lldb) bt
* thread #1: tid = 0x3aaec5, 0x00007fff91055f06 libsystem_kernel.dylib`__pthread_kill + 10, queue =
'com.apple.main-thread', stop reason = signal SIGABRT
frame #0: 0x00007fff91055f06 libsystem_kernel.dylib`__pthread_kill + 10
frame #1: 0x000000010008142d libsystem_pthread.dylib`pthread_kill + 90
frame #2: 0x00007fff96dc76e7 libsystem_c.dylib`abort + 129
frame #3: 0x00007fff8973bf81 libc++abi.dylib`abort_message + 257
frame #4: 0x00007fff89761a47 libc++abi.dylib`default_terminate_handler() + 267
frame #5: 0x00007fff94f636ae libobjc.A.dylib`_objc_terminate() + 103
frame #6: 0x00007fff8975f19e libc++abi.dylib`std::__terminate(void (*)()) + 8
frame #7: 0x00007fff8975ec12 libc++abi.dylib`__cxa_throw + 121
frame #8: 0x00007fff94f6108c libobjc.A.dylib`objc_exception_throw + 318
frame #9: 0x00007fff8d067372 CoreFoundation`-[__NSPlaceholderArray initWithObjects:count:] +
290
frame #10: 0x00007fff8d0eaa1f CoreFoundation`+[NSArray arrayWithObject:] + 47
* frame #11: 0x0000000100001b54 test`main(argc=1, argv=0x00007fff5fbff808) + 68 at main.m:15
frame #12: 0x00007fff8bea05ad libdyld.dylib`start + 1
frame #13: 0x00007fff8bea05ad libdyld.dylib`start + 1
Many SIGABRTs are caused by uncaught Objective-C exceptions. There are a lot of reasons exceptions can be
thrown, and they will always log a lot of helpful information to the console.
1- Select the project in the Project Navigator, and then open the General tab.
2- In the Identity section, set your developer Apple ID to the Team dropdown menu. (If it is not available, add it in
Xcode menu -> Preferences -> Accounts.
3- Go to Capabilities tab in the project properties and turn iCloud on. Then, select "Key-Value Storage" and
"CloudKit".
If all of the items are checked, then your app is ready to use CloudKit.
Record Types
Here, you get a list of all the existing record types in the app. When you first open CloudKit Dashboard for an app,
there’s a record type called Users there, which you can use it or just delete it and use your own.
In this page, you could make your data typed manually. Of course, in most cases this is pointless, because iOS SDK
To ensure that every new record identifier is unique, we use the current timestamp, which is unique. We get the
timestamp using NSDate's method timeIntervalSinceReferenceDate(). It is in form of ###.### (# are numbers),
which we will use the integer part. To do this, we split the string:
Swift
let timestamp = String(format: "%f", NSDate.timeIntervalSinceReferenceDate())
let timestampParts = timestamp.componentsSeparatedByString(".")
let recordID = CKRecordID(recordName: timestampParts[0])
To make the record, we should specify the record type (explained in Using CloudKit Dashboard) as Users, the ID as
the thing we made just now and the data. Here, we will add a sample text, a picture and the current date to the
record:
Swift
let record = CKRecord(recordType: "Users", recordID: recordID)
record.setObject("Some Text", forKey: "text")
record.setObject(CKAsset(fileURL: someValidImageURL), forKey: "image")
record.setObject(NSDate(), forKey: "date")
Objective-C
CKRecord *record = [[CKRecord alloc] initWithRecordType: "Users" recordID: recordID];
[record setObject: "Some Text" forKey: "text"];
[record setObject: [CKAsset assetWithFileURL: someValidImageURL] forKey: "image"];
[record setObject: [[NSDate alloc] init] forKey: "date"];
Note
Here, we didn't add the UIImage directly to the record, because as mentioned in Remarks, image format
isn't directly supported in CloudKit, so we have converted UIImage into CKAsset.
Beside the GKRandomSource.sharedRandom which is used in the following chapters there are three additional types
of GKRandomSource's out of the box.
In the following chapter we only use the nextInt() method of a GKRandomSource. In addition to this there is the
nextBool() -> Bool and the nextUniform() -> Float
Generation
Swift
import GameplayKit
Objective-C
#import <GameplayKit/GameplayKit.h>
Swift
let randomNumber = GKRandomSource.sharedRandom().nextInt()
Objective-C
int randomNumber = [[GKRandomSource sharedRandom] nextInt];
Note
The nextInt() function, when used without parameters, will return a random number between
-2,147,483,648 and 2,147,483,647, including themselves, so we are not sure that it is always a positive or
non-zero number.
Swift
let randomNumber = GKRandomSource.sharedRandom().nextInt(upperBound: 10)
Objective-C
int randomNumber = [[GKRandomSource sharedRandom] nextIntWithUpperBound: 10];
This code will give us a number between 0 and 10, including themselves.
To do this you create a GKRandomDistribution object with a GKRandomSource and pass in the bounds. A
GKRandomDistribution can be used to change the distribution behaviour like GKGaussianDistribution or
GKShuffledDistribution.
After that the object can be used like every regular GKRandomSource since it does implement the GKRandom protocol
too.
Swift
let randomizer = GKRandomDistribution(randomSource: GKRandomSource(), lowestValue: 0, highestValue:
6)
let randomNumberInBounds = randomizer.nextInt()
Objective-C outdated
int randomNumber = [[GKRandomSource sharedRandom] nextIntWithUpperBound: n - m] + m;
For example, to generate a random number between 3 and 10, you use this code:
Swift
let randomNumber = GKRandomSource.sharedRandom().nextInt(upperBound: 7) + 3
Objective-C outdated
int randomNumber = [[GKRandomSource sharedRandom] nextIntWithUpperBound: 7] + 3;
Lets assume we have the following classe for the following chapters:
GKEntity
An entity is a collection of components and offers several functions to add, remove and interact with components
of it.
While we could just use the GKEntity it is common to Subclass it for a specific type of game entity.
It is important that it is only possible to add a component of a class once. In case you add a second component of
the same class it will override the first exsisting component inside of the GKEntity
You may ask why. The reason for this is the methods called component(for: T.Type) which returns the component
of a specific type of the entity.
In addition to the components-methods it has an update method which is used to delegate the delta time or
current time of the game logic to it's components.
GKComponent
A component represents something of an entity for example the visual component or the logic component.
If an the update method of an entity is called it will delegate this to all of it's components. Overriding this method is
used to manipulate an Entity.
In addition to this it is possible to override the method didAddToEntity and willRemoveFromEntity to inform other
components about it's removal or add.
To manipulate a other component inside of a component it is possible to get the GKEntity which the component is
added to.
While this is possible it is not a common pattern since it wires the two components together.
GKComponentSystem
While we just talked about using the update delegate mechanism of the GKEntity to update the GKComponents
there is a different way to update GKComponents which is called GKComponentSystem.
It is used in case it is needed that all components of a specific type need to be updated in one go.
system.addComponent(PlayerSpriteComponent())
But a more common way is to pass the created entity with it's components to the GKComponentSystem and it will
find a matching component inside of the entity.
system.addComponent(foundIn: player)
system.update(deltaTime: delta)
In case you want to use the GKComponentSystem instead of a entity based update mechanism you have to have a
GKComponentSystem for every component and call the update on all of the systems.
Archive:
You should check "Include Unit Tests" in the project creation dialog.
If you missed checking that item while creating your project, you could always add test files later. To do so:
2- Go to "Targets"
At the end, you should have a file named [Your app name]Tests.swift. In Objective-C, you should have two files
named [Your app name]Tests.h and [Your app name]Tests.m instead.
Swift
import XCTest
func testPerformanceExample() {
// This is an example of a performance test case.
self.measure {
// Put the code you want to measure the time of here.
}
}
Objective-C
#import <XCTest/XCTest.h>
@end
@implementation MyProjectTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the
class.
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the
class.
[super tearDown];
}
- (void)testExample {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
- (void)testPerformanceExample {
// This is an example of a performance test case.
[self measureBlock:^{
// Put the code you want to measure the time of here.
}];
}
@end
Test Methods
A test method is an instance method of a test class that begins with the prefix test, takes no parameters,
and returns void, for example, (void)testColorIsRed(). A test method exercises code in your project and, if
that code does not produce the expected result, reports failures using a set of assertion APIs. For
example, a function’s return value might be compared against an expected value or your test might
So we add a test method using "test" as the prefix of the method, like:
Swift
func testSomething() {
Objective-C
- (void)testSomething {
To actually test the results, we use XCTAssert() method, which takes a boolean expression, and if true, marks the
test as succeeded, else it will mark it as failed.
Let's say we have a method in View Controller class called sum() which calculates sum of two numbers. To test it,
we use this method:
Swift
func testSum(){
let result = viewController.sum(4, and: 5)
XCTAssertEqual(result, 9)
}
Objective-C
- (void)testSum {
int result = [viewController sum:4 and:5];
XCTAssertEqual(result, 9);
}
Note
By default, you can't access label, text box or other UI items of the View Controller class from test class if
they are first made in Storyboard file. This is because they are initialized in loadView() method of the
View Controller class, and this will not be called when testing. The best way to call loadView() and all
other required methods is accessing the view property of our viewController property. You should add
this line before testing UI elements:
XCTAssertNotNil(viewController.view)
Now let's discuss what's going on here. The import XCTest line will allow us to extend XCTestCase and use
Swift
let storyboard = UIStoryboard(name: "Main", bundle: nil)
viewController = storyboard.instantiateInitialViewController() as! ViewController
Objective-C
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:"Main" bundle:nil];
viewController = (ViewController *) [storyboard instantiateInitialViewController];
This way, you could write test methods, and they will know where to check for errors. In this case, there are View
Controller and the Storyboard.
Let's say we have a main module called ToDo and we want to write tests for it. We would import that module like
this:
All test methods in the file with this import statement can now access all internal classes, structs, enums and all
their internal methods of the ToDo module.
You should never add the files with the elements you want to test to the test target because that can lead to hard to
debug errors.
In a test for a view controller you want sometimes to trigger the execution of loadView() or viewDidLoad(). This
can be done by accessing the view. Let's say you have view controller instance in your test called sut (system under
XCTAssertNotNil(sut.view)
View appearance
You can also trigger the methods viewWillAppear(_:) and viewDidAppear(_:) by adding the following code:
To test a specific method, click the square next to the method definition.
To test all methods, click the square next to the class definition.
If there is a green check next to the definition, the test has succeeded.
If there is a red cross next to the definition, the test has failed.
It will run all the tests from all the test targets!
Swift
let url = NSURL(string: "YOUR URL")
let player = AVPlayer(URL: videoURL!)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = self.view.bounds
self.view.layer.addSublayer(playerLayer)
player.play()
Swift
let player = AVPlayer(URL: url) // url can be remote or local
playerViewController.player!.play()
}
mytasks://create?title=hello&body=world
(Of course, the text and body parameters are used to populate our task that we're creating!)
Here are the Big Steps to adding this URL scheme to your project:
1. Register a URL scheme in your app's Info.plist file, so the system knows when to route a URL to your app.
2. Add a function to your UIApplicationDelegate that accepts and handles incoming URLs.
3. Perform whatever task needs to occur when that URL is opened.
First, we need to add a "URL Types" entry to our Info.plist file. Click the (+) button here:
...then enter a unique identifier for your app, as well as the URL scheme you want to use. Be specific! You don't
want the URL scheme to conflict with another app's implementation. Better to be too-long here than too-short!
func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {
if url.scheme == "mytasks" && url.host == "create" {
let title = // get the title out of the URL's query using a method of your choice
let body = // get the title out of the URL's query using a method of your choice
self.rootViewController.createTaskWithTitle(title, body: body)
return true
}
return false
}
When a user opens your app via a URL, they probably expected something to happen. Maybe that's navigating to a
piece of content, maybe that's creating a new item - in this example, we're going to create a new task in the app!
Objective-C
Swift
HTML
Note: It's useful to check if link can be opened to otherwise display an appropriate message to the user.
This can be done using canOpenURL: method.
4. Scroll down to the bottom until you see an option of URL Types
6. You will see URL schemes add a string using which you want to open your app.Lets add "DeepLinking" in
URL schemes.
So, to open your app you can launch it by typing "DeepLinking://" into your safari. Your deep-linking string has
following format.
Note : Even if don't add host and path it will launch the app,so no worries.But you can add host and path to
additionally redirect to particular page after application launch.
Swift:
Objective-c:
-(BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
The above method is called whenever your app is launched using a deep-linking string you set for your app.
8. Now is the time to install your app but wait before you directly jump to run button.Lets do a small change in
scheme's app-launch method.
10. You'll see a message "Waiting for DeepLinkPOC(or your app name) to launch".
11. Open safari and type in "DeepLinking://" into the search bar this will show prompt "open this page in
DeepLinkPOC" click open to launch your app.
Hope you got to know how to set up deep-linking for your app :)
A Core Graphics context is a canvas which we can draw in it and set some properties like the line
thickness.
Making a context
To make a context, we use the UIGraphicsBeginImageContextWithOptions() C function. Then, when we are done
with drawing, we just call UIGraphicsEndImageContext() to end the context:
Swift
let size = CGSize(width: 256, height: 256)
UIGraphicsBeginImageContextWithOptions(size, false, 0)
UIGraphicsEndImageContext()
Objective-C
CGSize size = [CGSize width:256 height:256];
UIGraphicsEndImageContext();
1. A CGSize object which stores the whole size of the context (the canvas)
3. An integer value which sets the scale (1 for non-retina, 2 for retina and 3 for retina HD screens). If set to 0,
the system automatically handles the scale based on the target device.
Objective-C
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
imageView.image = image; //assuming imageView is a valid UIImageView object
Unwind Segues give you a way to “unwind” the navigation stack and specify a destination to go back to.
The signature of this function is key to Interface Builder recognizing it. It must have a return value of
IBAction and take one parameter of UIStoryboardSegue. The name of the function does not matter.
In fact, the function does not even have to do anything. It’s just there as a marker of which
UIViewController is the destination of the Unwind Segue. [source][1]
Objective C:
-(IBAction)prepareForUnwind:(UIStoryboardSegue *)segue {
}
Swift:
A UIStoryboardSegue object is responsible for performing the visual transition between two view
controllers. In addition, segue objects are used to prepare for the transition from one view controller to
another. Segue objects contain information about the view controllers involved in a transition.
When a segue is triggered, but before the visual transition occurs, the storyboard runtime calls the
current view controller’s prepareForSegue:sender: method so that it can pass any needed data to the
view controller that is about to be displayed.
Attributes
Swift
References:
Parameters
Example in Swift
Determines whether the segue with the specified identifier should be performed.
Parameters
Example in Swift
Initiates the segue with the specified identifier from the current view controller's storyboard file
Parameters
Example in Swift
Performing a segue with identifier "SomeSpecificIdentifier" from a table view row selection:
Swift
let calendarsArray = eventStore.calendarsForEntityType(EKEntityType.Event) as! [EKCalendar]
Swift
for calendar in calendarsArray{
//...
}
Objective-C
UIColor *calendarColor = [UIColor initWithCGColor: calendar.CGColor];
NSString *calendarTitle = calendar.title;
Swift
import EventKit
Objective-C
#import <EventKit/EventKit.h>
Making an EKEventStore
Then, we make an EKEventStore object. This is the object from which we can access calendar and reminders data:
Swift
let eventStore = EKEventStore()
Objective-C
EKEventStore *eventStore = [[EKEventStore alloc] init];
Note
Making an EKEventStore object every time we need to access calendar is not efficient. Try to make it once
and use it everywhere in your code.
Availability has three different status: Authorized, Denied and Not Determined. Not Determined means the app
needs to grant access.
Swift
switch EKEventStore.authorizationStatusForEntityType(EKEntityTypeEvent){
case .Authorized: //...
case .Denied: //...
case .NotDetermined: //...
default: break
}
Objective-C
switch ([EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent]){
case EKAuthorizationStatus.Authorized:
//...
break;
case EKAuthorizationStatus.Denied:
//...
break;
case EKAuthorizationStatus.NotDetermined:
//...
break;
default:
break;
}
Requesting Permission
Swift
eventStore.requestAccessToEntityType(EKEntityTypeEvent, completion: { [weak self]
(userGrantedAccess, _) -> Void in
if userGrantedAccess{
//access calendar
}
}
Objective-C
EKEvent *event = [EKEvent initWithEventStore:eventStore];
Objective-C
NSError *error;
BOOL *result = [eventStore saveEvent:event span:EKSpanThisEvent error:&error];
if (result == NO){
//error
}
Adding capability
1- In the project settings, select your iOS app target and go to Capabilities tab
According to Apple:
Intents Extension template builds an Intents extension that allows your app to handle intents issued by
system services like Siri and Maps.
By doing this steps, two new targets (Intents Extension and UI Extension) are created, and by default they contain
Workout Intent code. For different types of Siri requests, see Remarks.
Note
Anytime you want to debug your extension, just select the Intent scheme from the available schemes.
Note
You can't test SiriKit apps in the Simulator. Instead, you need a real device.
contact.givenName = "John"
contact.familyName = "Appleseed"
contact.phoneNumbers = [CNLabeledValue(
label:CNLabelPhoneNumberiPhone,
value:CNPhoneNumber(stringValue:"(408) 555-0126"))]
Objective-C
#import <Contacts/Contacts.h>
Checking accessibility
Swift
switch CNContactStore.authorizationStatusForEntityType(CNEntityType.Contacts){
case .Authorized: //access contacts
case .Denied, .NotDetermined: //request permission
default: break
}
Requesting Permission
Swift
var contactStore = CKContactStore()
contactStore.requestAccessForEntityType(CKEntityType.Contacts, completionHandler: { (ok, _) -> Void
in
if access{
//access contacts
}
}
To access contacts, we should apply a filter of type NSPredicate to our contactStore variable which we defined it in
Authorizing Contact Access example. For example, here we want to sort out contacts with name matching with our
own:
Swift
let predicate = CNContact.predicateForContactsMatchingName("Some Name")
Objective-C
NSPredicate *predicate = [CNContact predicateForContactsMatchingName:@"Some Name"];
Here, we want to fetch the contact's first name, last name and profile image:
Swift
let keys = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactImageDataKey]
Fetching contacts
Swift
do {
let contacts = try contactStore.unifiedContactsMatchingPredicate(predicate, keysToFetch: keys)
} catch let error as NSError {
//...
}
// this function is required to stop audio on audio completion otherwise it will play same audio
again and again
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool)
{
player.stop()
}
// this function is required to get a speech recognizer and after that make and request to speech
recognizer
func requestSpeechAuth()
{
SFSpeechRecognizer.requestAuthorization { authStatus in
if authStatus == SFSpeechRecognizerAuthorizationStatus.authorized {
if let path = Bundle.main.url(forResource: "mpthreetest", withExtension: "m4a") {
do {
let sound = try AVAudioPlayer(contentsOf: path)
self.audioPlayer = sound
self.audioPlayer.delegate = self
sound.play()
} catch {
print("error")
}
import StoreKit
In order to process the products from the productsRequest, we need to assign a delegate to the request that
handles the response. The delegate needs to conform to the SKProductsRequestDelegate protocol, which means
that it must inherit from NSObject (i.e. any Foundation object) and implement the productsRequest method:
products = response.products
To initiate the productsRequest we assign PaymentManager as the products-request's delegate, and call the start()
method on the request:
Provisioning Profiles are split into two types, Development, and Distribution:
Development
iOS App Development / tvOS App Development - used in development in order to install your app onto a test
device.
Distribution
App Store / tvOS App Store - used to sign your application for app store upload.
In House - Used for Enterprise distribution of your app, to devices within your business.
Ad Hoc / tvOS Ad Hoc - Used to distribute your app to a limited number of specific devices (e.g. you will need
to know the UDIDs of the devices you want to install your app to).
Step 4: when you click on show in finder you will redirect to Archive folder, looks like this
Step 5: Right click on .xarchive file -> select Show in finder option.
Step 7: Now to convert .app to .ipa just drag and drop into itunes . check below image ,
Note: if you want to know how to upload app with application loader then check this ,
EDIT:
WARNING: Don't make .ipa with changing extension from .aap to .zip and .zip to .ipa.
I have seen in many answer that , they have suggest compress .app file and then change the extension from .zip to
.ipa . It is not working now . By this method you will get Error like ,
2. Now we need to pin this view to it's superview for fixing it's size and position using constraints as:
4. To see the preview on screen of these added constraints we can use Assistant Editor as;
Objective-C
CLLocationDistance distance=42;
MKDistanceFormatter *formatter=[[MKDistanceFormatter alloc]init];
NSString *answer=[formatter stringFromDistance:distance];
// answer = "150 feet"
formatter.units = .Metric
var answer = formatter.stringFromDistance(distance)
// "40 m"
formatter.units = .ImperialWithYards
answer = formatter.stringFromDistance(distance)
// "50 yards"
Objective-C
formatter.units=MKDistanceFormatterUnitsImperialWithYards;
NSString *answer=[formatter stringFromDistance:distance];
//50 yards
formatter.unitStyle = .Full
var answer = formatter.stringFromDistance(distance)
// "150 feet"
formatter.unitStyle = .Abbreviated
answer = formatter.stringFromDistance(distance)
// "150 ft"
formatter.unitStyle=MKDistanceFormatterUnitStyleFull;
NSString *answer=[formatter stringFromDistance:distance];
// "150 feet"
formatter.unitStyle=MKDistanceFormatterUnitStyleAbbreviated;
NSString *answer=[formatter stringFromDistance:distance];
// "150 ft"
You should check if the device has a 3D touch support. You can do this by checking the value of forceTouchCapability
property of a UITraitCollection object. UITraitCollection describes the iOS interface environment for your app.
if (traitCollection.forceTouchCapability == .Available) {
registerForPreviewingWithDelegate(self, sourceView: view)
}
You need to implement the two methods of UIViewControllerPreviewingDelegate in your class. One of the methods is
for peek and the other one is for pop behavior.
datailVC.peekActive = true
previewingContext.sourceRect = cell.frame
// Do the stuff
return datailVC
// Do the stuff
As you can see they are overloaded methods. You can use 3D touch in any way implementing these methods.
Objective-C
1. Sign in to iTunesConnect
2. Go to My Apps. Create an app for your project then go to Features.
3. Click on Game Center
4. Click the plus sign next to Leaderboards.
5. Choose Single Leaderboard for Leaderboard types.
6. Create a Leaderboard Reference Name for your reference.
7. Create a Leaderboard ID for your app to refer to when reporting scores.
8. Set score format to Integer
9. Score Submission will be Best Score
10. Click Add language and fill the entries.
Copy your LeaderboardID that you made and lets head over to Xcode.
4. Viewing leaderboards
func authenticateLocalPlayer() {
if viewController != nil {
//If the user is not signed in to GameCenter, we make them sign in
let vc:UIViewController = self.view!.window!.rootViewController!
vc.presentViewController(viewController!, animated: true, completion: nil)
} else {
Identifier which is defined as a string and used to enter your leaderboardID that you made in iTunesConnect.
score which is defined as an Int which will be the users score to submit to iTunesConnect
if GKLocalPlayer.localPlayer().authenticated {
scoreReporter.value = Int64(score)
GKScore.reportScores(scoreArray, withCompletionHandler: {
error -> Void in
if error != nil {
print("Error")
} else {
}
})
}
}
4. Now if the user wants to view leaderboards, call the function below
//This function will show GameCenter leaderboards and Achievements if you call this function.
func showGameCenter() {
Swift
var dict = [String : AnyObject]()
First, you need a key/value pair that lets the Keychain know this is a password. Note that because our dict key is a
String we must cast any CFString to a String explicitly in Swift 3. CFString may not be used as the key to a Swift
Dictionary because it is not Hashable.
Swift
dict[kSecClass as String] = kSecClassGenericPassword
Next, our password may have a series of attributes to describe it and help us find it later. Here's a list of attributes
for generic passwords.
Swift
// The password will only be accessible when the device is unlocked
dict[kSecAttrAccessible as String] = kSecAttrAccessibleWhenUnlocked
// Label may help you find it later
dict[kSecAttrLabel as String] = "com.me.myapp.myaccountpassword" as CFString
// Username
dict[kSecAttrAccount as String] = "My Name" as CFString
// Service name
dict[kSecAttrService as String] = "MyService" as CFString
Finally, we need our actual private data. Be sure not to keep this around in memory for too long. This must be
CFData.
Swift
dict[kSecValueData as String] = "my_password!!".data(using: .utf8) as! CFData
Finally, the Keychain Services add function wants to know how it should return the newly constructed keychain
item. Since you shouldn't be holding on to the data very long in memory, here's how you could only return the
attributes:
Swift
dict[kSecReturnAttributes as String] = kCFBooleanTrue
Swift
var result: AnyObject?
let status = withUnsafeMutablePointer(to: &result) {
SecItemAdd(dict as CFDictionary, UnsafeMutablePointer($0))
}
let newAttributes = result as! Dictionary<String, AnyObject>
Swift
let error: Unmanaged<CFError>?
Next, add it to the dictionary with kSecAttrAccessControl key (which is mutually exclusive with kSecAttrAccessible
key you've been using in other examples):
Swift
var dictionary = [String : Any]()
Swift
let lastResultCode = SecItemAdd(query as CFDictionary, nil)
To access stored data, just query Keychain for a key. Keychain Services will present authentication dialog to the user
and return data or nil depending on whether suitable fingerprint was provided or passcode matched.
Swift
var query = [String: Any]()
Pay attention that status will be err if user declined, canceled or failed authorization.
Swift
if status == noErr {
let password = String(data: queryResult as! Data, encoding: .utf8)!
print("Password: \(password)")
} else {
print("Authorization not passed")
}
Swift
var dict = [String : AnyObject]()
dict[kSecClass as String] = kSecClassGenericPassword
Swift
// Label
dict[kSecAttrLabel as String] = "com.me.myapp.myaccountpassword" as CFString
// Username
dict[kSecAttrAccount as String] = "My Name" as CFString
// Service name
dict[kSecAttrService as String] = "MyService" as CFString
Finally, we need to say how we'd like our data returned. Below, we'll request that just the private password itself be
returned as a CFData object:
Swift
dict[kSecReturnData as String] = kCFBooleanTrue
Swift
var queryResult: AnyObject?
let status = withUnsafeMutablePointer(to: &queryResult) {
SecItemCopyMatching(dict as CFDictionary, UnsafeMutablePointer($0))
}
// Don't keep this in memory for long!!
let password = String(data: queryResult as! Data, encoding: .utf8)!
Here, SecItemCopyMatching takes in a query dictionary and a pointer to where you'd like the result to go. It returns
an OSStatus with a result codes. Here are the possibilities.
So first, let's construct a class key and a list of attributes. These attributes can narrow our search but you must
include any attributes and there old values if you will be changing them.
Swift
var dict = [String : AnyObject]()
dict[kSecClass as String] = kSecClassGenericPassword
// Label
dict[kSecAttrLabel as String] = "com.me.myapp.myaccountpassword" as CFString
// Username
dict[kSecAttrAccount as String] = "My Name" as CFString
Swift
dict[kSecValueData as String] = "my_password!!".data(using: .utf8) as! CFData
Swift
var newDict = [String : AnyObject]()
newDict[kSecClass as String] = kSecClassGenericPassword
// Label
newDict[kSecAttrLabel as String] = "com.me.myapp.myaccountpassword" as CFString
// Username
newDict[kSecAttrAccount as String] = "My Name" as CFString
// New password
newDict[kSecValueData as String] = "new_password!!".data(using: .utf8) as! CFData
Swift
let status = SecItemUpdate(dict as CFDictionary, newDict as CFDictionary)
A query dictionary, in this context exclusively includes a class key to describe what the item is and attributes to
describe information about the item. Inclusion of search restrictions such as kSecMatchCaseInsensitive is not
allowed.
Swift
var dict = [String : AnyObject]()
dict[kSecClass as String] = kSecClassGenericPassword
Swift
let status = SecItemDelete(dict as CFDictionary)
#import <Foundation/Foundation.h>
typedef void (^KeychainOperationBlock)(BOOL successfulOperation, NSData *data, OSStatus status);
@end
Keychain.m
#import "Keychain.h"
#import <Security/Security.h>
@implementation Keychain
{
NSString * keychainService;
NSString * keychainGroup;
}
return self;
}
-(void)insertKey:(NSString *)key
-(void)findDataForKey:(NSString *)key
withCompletionBlock:(KeychainOperationBlock)completionBlock
{
NSMutableDictionary *dict = [self prepareDict:key];
[dict setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
[dict setObject:keychainService forKey:(id)kSecAttrService];
[dict setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
CFTypeRef result = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)dict,&result);
-(void)updateKey:(NSString *)key
withData:(NSData *)data
withCompletion:(KeychainOperationBlock)completionBlock
{
NSMutableDictionary * dictKey =[self prepareDict:key];
-(void)removeDataForKey:(NSString *)key
withCompletionBlock:(KeychainOperationBlock)completionBlock {
NSMutableDictionary *dict = [self prepareDict:key];
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)dict);
if( status != errSecSuccess) {
DLog(@"Unable to remove item for key %@ with error:%d",key,(int)status);
}
if (completionBlock) {
completionBlock(errSecSuccess == status, nil, status);
}
}
return dict;
}
@end
First, we create two targets for 2 environments by duplicating the main target:
For each target, we will define a custom macro. Here I will define macro named "CI" in build settings of target CI,
macro named "STAGING" for target Staging.
Target Staging:
If you want to do more customize, for example: Change app name for each target:
UIGraphicsBeginImageContext(self.view.frame.size);
[[UIImage imageNamed:@"image.png"] drawInRect:self.view.bounds];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.view.backgroundColor = [UIColor colorWithPatternImage:image];
Swift 3.1:
func createGradient() {
let caLayer = CAGradientLayer()
caLayer.colors = [UIColor.white, UIColor.green, UIColor.blue]
caLayer.locations = [0, 0.5, 1]
caLayer.bounds = self.bounds
self.layer.addSublayer(caLayer)
}
The CAGradientLayer locations and bounds variables can take multiple values to create a gradient layer with how
ever many colors you desire. From the documentation:
By default, the colors are spread uniformly across the layer, but you can optionally specify locations for
control over the color positions through the gradient.
Swift:
view.backgroundColor! = UIColor.redColor()
view.backgroundColor = UIColor.redColor
typedef void(^myCustomCompletion)(BOOL);
2- Create custom method which takes your custom completion block as a parameter.
The carat “^” character defines a block. For example, ^{ … } is a block. More specifically, it is a block that returns
“void” and accepts no arguments. It is equivalent to a method such like: “- (void)something;” but there is no inherent
name associated with the code block.
Define a block that can accept arguments work very similarly. To supply an argument to a block, you define the
block like so: ^(BOOL someArg, NSString someStr) { … }*. When you use API calls that support blocks, you’ll be writing
blocks that look similar to this, especially for animation blocks or NSURLConnection blocks as shown in the above
example.
A label knows how wide and tall it is because it knows the length of the text that has been set on it, as well as the
font size for that text. Likewise for a button, which might combine the text with a background image and some
padding.
The same is true for segmented controls, progress bars, and most other controls, although some may only have a
predetermined height but an unknown width.
This is known as the intrinsic content size, and it is an important concept in Auto Layout. Auto Layout asks your
controls how big they need to be and lays out the screen based on that information.
Usually you want to use the intrinsic content size, but there are some cases where you may not want to do
that. You can prevent this by setting an explicit Width or Height constraint on a control.
Imagine what happens when you set an image on a UIImageView if that image is much larger than the screen. You
usually want to give image views a fixed width and height and scale the content, unless you want the view to resize
to the dimensions of the image.
Reference: https://www.raywenderlich.com/115444/auto-layout-tutorial-in-ios-9-part-2-constraints
First we need to get the users location by getting their current longitude and latitude.
import GooglePlaces
import GooglePlacePicker
4. Request authorization
currentLocation = CLLocationManager()
currentLocation.requetAlwayAuthorization()
if CLLOcationManager.authorizationStatues() == .AuthorizedAlways {
extension UIApplication {
return base!
}
NotificationCenter.default.addObserver(
self,
selector: #selector(ViewController.do(_:)),
name: NSNotification.Name.UIApplicationDidBecomeActive,
object: nil)
You can register for a lot of more events, just take a look at
https://developer.apple.com/reference/foundation/nsnotification.name.
[myImageView1 setImage:newImg];
CGImageRelease(cgimg);
[imageView2 setImage:newImg];
CGImageRelease(cgimg);
[self.view addSubview:imageView1];
/* CIAccordionFoldTransition,
CIAdditionCompositing,
CIAffineClamp,
CIAffineTile,
CIAffineTransform,
CIAreaAverage,
CIAreaHistogram,
CIAreaMaximum,
CIAreaMaximumAlpha,
CIAreaMinimum,
CIAreaMinimumAlpha,
CIAztecCodeGenerator,
CIBarsSwipeTransition,
CIBlendWithAlphaMask,
CIBlendWithMask,
CIBloom,
CIBoxBlur,
CIBumpDistortion,
CIBumpDistortionLinear,
CICheckerboardGenerator,
CICircleSplashDistortion,
CICircularScreen,
CICircularWrap,
CICMYKHalftone,
CICode128BarcodeGenerator,
#import <CoreImage/CoreImage.h>
#import <CoreImage/CoreImage.h>
#import <QuartzCore/QuartzCore.h>
[self faceDetector];
Function definition:
-(void)faceDetector
{
// Load the picture for face detection
UIImageView* image = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"download.jpeg"]];
// create a face detector - since speed is not an issue we'll use a high accuracy
// detector
CIDetector* detector = [CIDetector detectorOfType:CIDetectorTypeFace
context:nil options:[NSDictionary
dictionaryWithObject:CIDetectorAccuracyHigh forKey:CIDetectorAccuracy]];
// create an array containing all the detected faces from the detector
NSArray* features = [detector featuresInImage:image];
NSLog(@"Number of faces %d",[features count]);
if(faceFeature.hasLeftEyePosition)
{
// create a UIView with a size based on the width of the face
UIView* leftEyeView = [[UIView alloc]
initWithFrame:CGRectMake(faceFeature.leftEyePosition.x-faceWidth*0.15,
faceFeature.leftEyePosition.y-faceWidth*0.15, faceWidth*0.3, faceWidth*0.3)];
// change the background color of the eye view
[leftEyeView setBackgroundColor:[[UIColor blueColor] colorWithAlphaComponent:0.3]];
// set the position of the leftEyeView based on the face
[leftEyeView setCenter:faceFeature.leftEyePosition];
// round the corners
leftEyeView.layer.cornerRadius = faceWidth*0.15;
// add the view to the window
[self.view addSubview:leftEyeView];
}
if(faceFeature.hasRightEyePosition)
{
// create a UIView with a size based on the width of the face
UIView* leftEye = [[UIView alloc]
initWithFrame:CGRectMake(faceFeature.rightEyePosition.x-faceWidth*0.15,
faceFeature.rightEyePosition.y-faceWidth*0.15, faceWidth*0.3, faceWidth*0.3)];
// change the background color of the eye view
[leftEye setBackgroundColor:[[UIColor blueColor] colorWithAlphaComponent:0.3]];
// set the position of the rightEyeView based on the face
[leftEye setCenter:faceFeature.rightEyePosition];
// round the corners
leftEye.layer.cornerRadius = faceWidth*0.15;
// add the new view to the window
[self.view addSubview:leftEye];
}
if(faceFeature.hasMouthPosition)
{
// create a UIView with a size based on the width of the face
UIView* mouth = [[UIView alloc] initWithFrame:CGRectMake(faceFeature.mouthPosition.x-
faceWidth*0.2, faceFeature.mouthPosition.y-faceWidth*0.2, faceWidth*0.4, faceWidth*0.4)];
// change the background color for the mouth to green
[mouth setBackgroundColor:[[UIColor greenColor] colorWithAlphaComponent:0.3]];
// set the position of the mouthView based on the face
[mouth setCenter:faceFeature.mouthPosition];
// }
}
func updatePlayer(){
let item = mediaItems[currentIndex]
// DO-TRY-CATCH try to setup AVAudioPlayer with the path, if successful, sets up the
AVMusicPlayer, and song values.
if let path: NSURL = item.assetURL as NSURL? {
do
{
avMusicPlayer = try AVAudioPlayer(contentsOf: path as URL)
avMusicPlayer.enableRate = true
avMusicPlayer.rate = 1.0
avMusicPlayer.numberOfLoops = 0
avMusicPlayer.currentTime = 0
}
catch
{
avMusicPlayer = nil
}
}
}
In the project directory add a text file to your project called Podfile by typing pod init in your project directory
Cocoapods will generate a xcworkspace file, which you should use for launching your project (the .xcodeproj file will
not include the pod libraries)
#import <CorePlot/ios/CorePlot.h>
//#import "CorePlot-CocoaTouch.h" or the above import statement
@interface ViewController : UIViewController<CPTPlotDataSource>
-(void)loadView
{
[super loadView];
// We need a hostview, you can create one in IB (and create an outlet) or just do this:
CPTGraphHostingView* hostView = [[CPTGraphHostingView alloc] initWithFrame:CGRectMake(10, 40,
300, 400)];
hostView.backgroundColor=[UIColor whiteColor];
self.view.backgroundColor=[UIColor blackColor];
[self.view addSubview: hostView];
// Create a CPTGraph object and add to hostView
CPTGraph* graph = [[CPTXYGraph alloc] initWithFrame:CGRectMake(10, 40, 300, 400)];
hostView.hostedGraph = graph;
// Get the (default) plotspace from the graph so we can set its x/y ranges
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *) graph.defaultPlotSpace;
// Note that these CPTPlotRange are defined by START and LENGTH (not START and END) !!
[plotSpace setYRange: [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat( 0 )
length:CPTDecimalFromFloat( 20 )]];
[plotSpace setXRange: [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat( -4 )
length:CPTDecimalFromFloat( 8 )]];
// Create the plot (we do not define actual x/y values yet, these will be supplied by the
datasource...)
CPTScatterPlot* plot = [[CPTScatterPlot alloc] initWithFrame:CGRectZero];
// Let's keep it simple and let this class act as datasource (therefore we implemtn
<CPTPlotDataSource>)
plot.dataSource = self;
// Finally, add the created plot to the default plot space of the CPTGraph object we created
before
[graph addPlot:plot toPlotSpace:graph.defaultPlotSpace];
}
// This method is here because this class also functions as datasource for our graph
1- If you don't have an Xcode project yet, create one now. Create a Podfile if you don't have one:
$ cd your-project directory
$ pod init
2- Add the pods that you want to install. You can include a Pod in your Podfile like this:
pod 'Firebase/Core'
pod 'Firebase/Messaging'
3- Install the pods and open the .xcworkspace file to see the project in Xcode.
$ pod install
$ open your-project.xcworkspace
if #available(iOS 10.0, *) {
let authOptions : UNAuthorizationOptions = [.Alert, .Badge, .Sound]
UNUserNotificationCenter.currentNotificationCenter().requestAuthorizationWithOptions(
authOptions,
completionHandler: {_,_ in })
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
10- and if u want monitor for token change use below code in appDelegate file
// Connect to FCM since connection may have failed when attempted before having a token.
connectToFcm()
}
func connectToFcm() {
FIRMessaging.messaging().connectWithCompletion { (error) in
if (error != nil) {
print("Unable to connect with FCM. \(error)")
} else {
print("Connected to FCM.")
}
}
}
in your appDelegate.
the initialization complete and client ready to recieve message from fcm panel or send by token from third party
server
to add created framework to another project, first you should create a workspace
add "target project" and "framework project" to workspace, then :
Add new Cocoatouch file of type of type UIView and add an interface file
#import <UIKit/UIKit.h>
@end
@property (nonatomic, strong) UIButton *nextKeyboardButton and all the code associated with it
-(void) addGestureToKeyboard
{
[self.keyboard.deleteKey addTarget:self action:@selector(pressDeleteKey)
forControlEvents:UIControlEventTouchUpInside];
[self.keyboard.globe addTarget:self action:@selector(advanceToNextInputMode)
forControlEvents:UIControlEventTouchUpInside];
}
-(void) pressDeleteKey
{
[self.textDocumentProxy deleteBackward];
}
-(void)keyPressed:(UIButton *)key
{
[self.textDocumentProxy insertText:[key currentTitle]];
}
Run the Main Application and go to Settings->General->Keyboard->Add New Keyboard-> and add keyboard from
the third party keyboard section (The displayed keyboardName would be keyBoardCustom)
The keyboard name can be changed by adding a key called Bundle display name and in the Value String Value
enter the desired name for the keyboard of the main Project.
Airdrop can be used from UIActivityViewController. The UIActivityViewController class is a standard view
controller that provides several standard services, such as copying items to the clipboard, sharing content to social
media sites, sending items via Messages, AirDrop and some third party applications.
UIActivityTypeCopyToPasteboard,UIActivityTypeAssignToContact,
UIActivityTypeSaveToCameraRoll,UIActivityTypeAddToReadingList,
UIActivityTypePostToFlickr,UIActivityTypePostToVimeo,
UIActivityTypePostToTencentWeibo];
controller.excludedActivityTypes = excludeActivities;
[self presentViewController:controller animated:YES completion:nil];
}
Swift
if ((newImage) != nil)
{
let activityVC = UIActivityViewController(activityItems: [newImage],
applicationActivities: nil)
activityVC.excludedActivityTypes =[UIActivityTypeAddToReadingList]
self.presentViewController(activityVC, animated: true, completion: nil)
if([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook])
{
SLComposeViewController *fbVC=[SLComposeViewController
composeViewControllerForServiceType:SLServiceTypeFacebook];
[fbVC setInitialText:text];
//To send link together with text
[fbVC addURL:[NSURL URLWithString:@"https://twitter.com/IbrahimH_ss_n"]];
//To add a photo to a link
[fbVC addImage:[UIImage imageNamed:@"image"]];
[self presentViewController:fbVC animated:YES completion:nil];
}
else
{//Shows alert if twitter is not signed in
UIAlertController *alertCont=[UIAlertController alertControllerWithTitle:@"SocialShare"
message:@"You are not signed in to twitter."preferredStyle:UIAlertControllerStyleAlert];
SinaWeibo
//- - SinaWeibo - -
if([SLComposeViewController isAvailableForServiceType:SLServiceTypeSinaWeibo]){
SLComposeViewController *SinaWeiboVC=[SLComposeViewController
composeViewControllerForServiceType:SLServiceTypeSinaWeibo];
[SinaWeiboVC setInitialText:text];
TencentWeibo
#define DefaultFontSize 48
#define PaddingFactor 0.1f
-(IBAction)print:(id)sender;
{
/* Get the UIPrintInteractionController, which is a shared object */
UIPrintInteractionController *controller = [UIPrintInteractionController
sharedPrintController];
if(!controller){
NSLog(@"Couldn't get shared UIPrintInteractionController!");
return;
}
/* Use landscape orientation for a banner so the text print along the long side of the paper.
*/
printInfo.orientation = UIPrintInfoOrientationLandscape;
printInfo.jobName = self.textField.text;
controller.printInfo = printInfo;
/* Create the UISimpleTextPrintFormatter with the text supplied by the user in the text field
*/
_textFormatter = [[UISimpleTextPrintFormatter alloc] initWithText:self.textField.text];
/* Set the text formatter's color and font properties based on what the user chose */
_textFormatter.color = [self chosenColor];
_textFormatter.font = [self chosenFontWithSize:DefaultFontSize];
/* Set up a completion handler block. If the print job has an error before spooling, this is
where it's handled. */
void (^completionHandler)(UIPrintInteractionController *, BOOL, NSError *) =
^(UIPrintInteractionController *printController, BOOL completed, NSError *error) {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
[controller presentFromRect:self.printButton.frame inView:self.view animated:YES
completionHandler:completionHandler];
else
[controller presentAnimated:YES completionHandler:completionHandler]; // iPhone
}
- (CGFloat)printInteractionController:(UIPrintInteractionController *)printInteractionController
cutLengthForPaper:(UIPrintPaper *)paper {
/* Create a font with arbitrary size so that you can calculate the approximate
font points per screen point for the height of the text. */
UIFont *font = _textFormatter.font;
CGSize size = [self.textField.text sizeWithAttributes:@{NSFontAttributeName: font}];
/* Create a new font using a size that will fill the width of the paper */
font = [self chosenFontWithSize: paper.printableRect.size.width *
approximateFontPointPerScreenPoint];
/* Calculate the height and width of the text with the final font size */
CGSize finalTextSize = [self.textField.text sizeWithAttributes:@{NSFontAttributeName: font}];
/* Set the UISimpleTextFormatter font to the font with the size calculated */
_textFormatter.font = font;
/* Calculate the margins of the roll. Roll printers may have unprintable areas
before and after the cut. We must add this to our cut length to ensure the
printable area has enough room for our text. */
CGFloat lengthOfMargins = paper.paperSize.height - paper.printableRect.size.height;
/* The cut length is the width of the text, plus margins, plus some padding */
return finalTextSize.width + lengthOfMargins + paper.printableRect.size.width * PaddingFactor;
}
Download the latest version of Carthage from the given link Download Link
Once the download is complete install it by double clinking on the download pkg file.
To check for successful download run the following command in your Terminal carthage version This should give
the version installed like 0.18-19-g743fa0f
First go the Target->Capabilities and enable HealthKit. This would setup the info.plist entry.
Make a new CocoaClass of type NSObject The filename I gave is GSHealthKitManager and the header file is as
shown below
GSHealthKitManager.h
#import <Foundation/Foundation.h>
#import <HealthKit/HealthKit.h>
@interface GSHealthKitManager : NSObject
+ (GSHealthKitManager *)sharedManager;
- (void)requestAuthorization;
- (NSDate *)readBirthDate;
- (void)writeWeightSample:(double)weight;
- (NSString *)readGender;
@end
GSHealthKitManager.m
#import "GSHealthKitManager.h"
#import <HealthKit/HealthKit.h>
@interface GSHealthKitManager ()
@end
@implementation GSHealthKitManager
+ (GSHealthKitManager *)sharedManager {
static dispatch_once_t pred = 0;
static GSHealthKitManager *instance = nil;
dispatch_once(&pred, ^{
instance = [[GSHealthKitManager alloc] init];
instance.healthStore = [[HKHealthStore alloc] init];
});
return instance;
}
- (void)requestAuthorization {
- (NSDate *)readBirthDate {
NSError *error;
NSDate *dateOfBirth = [self.healthStore dateOfBirthWithError:&error]; // Convenience method
of HKHealthStore to get date of birth directly.
if (!dateOfBirth) {
NSLog(@"Either an error occurred fetching the user's age information or none has been
stored yet. In your app, try to handle this gracefully.");
}
return dateOfBirth;
}
- (NSString *)readGender
{
NSError *error;
HKBiologicalSexObject *gen=[self.healthStore biologicalSexWithError:&error];
if (gen.biologicalSex==HKBiologicalSexMale)
{
return(@"Male");
}
else if (gen.biologicalSex==HKBiologicalSexFemale)
{
return (@"Female");
}
else if (gen.biologicalSex==HKBiologicalSexOther)
{
return (@"Other");
}
else{
return (@"Not Set");
}
}
@end
- (IBAction)pressed:(id)sender {
Log Output
1. Create a new iOS project and add CoreSpotlight and MobileCoreServices framework to your project.
2. Create the actual CSSearchableItem and associating the uniqueIdentifier, domainIdentifier and the
attributeSet. Finally index the CSSearchableItem using [[CSSearchableIndex defaultSearchableIndex]...] as
show below.
import CoreMotion
Next, we need to create a CMAltimeter object, but a common pitfall is to create it in the viewDidLoad(). If done that
way, the altimeter won’t be accessible when we need to call a method on it. Nevertheless, go ahead and create your
CMAltimeter object just before the viewDidLoad():
Now:
2. If that returns true, you can then begin monitoring altitude change with
startRelativeAltitudeUpdatesToQueue
3. If there are no errors, you should be able to retrieve data from the relativeAltitude and pressure
properties.
Given below is the definition of a button action to begin monitoring with our barometer.
Step 1
import AVFoundation
class ViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate
Step 2
QR code reading is totally based on video capture. So to capture continuous video create an AVCaptureSession and
set up device input and output. Add the below code in view controller viewDidLoad method
// Create an instance of the AVCaptureDevice and provide the video as the media type parameter.
let captureDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
do {
// Create an instance of the AVCaptureDeviceInput class using the device object and intialise
capture session
let input = try AVCaptureDeviceInput(device: captureDevice)
captureSession = AVCaptureSession()
captureSession?.addInput(input)
// Create a instance of AVCaptureMetadataOutput object and set it as the output device the
capture session.
let captureMetadataOutput = AVCaptureMetadataOutput()
captureSession?.addOutput(captureMetadataOutput)
// Set delegate with a default dispatch queue
captureMetadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
//set meta data object type as QR code, here we can add more then one type as well
captureMetadataOutput.metadataObjectTypes = [AVMetadataObjectTypeQRCode]
// Initialize the video preview layer and add it as a sublayer to the viewcontroller view's
layer.
videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
videoPreviewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
videoPreviewLayer?.frame = view.layer.bounds
view.layer.addSublayer(videoPreviewLayer!)
Step 3
// Check if the metadataObjects array contains at least one object. If not no QR code is in our
video capture
if metadataObjects == nil || metadataObjects.count == 0 {
// NO QR code is being detected.
return
}
if metadataObj.type == AVMetadataObjectTypeQRCode {
// If the found metadata is equal to the QR code metadata then get the string value from
meta data
let barCodeObject = videoPreviewLayer?.transformedMetadataObject(for: metadataObj)
if metadataObj.stringValue != nil {
// metadataObj.stringValue is our QR code
}
}
}
here metadata object can give you the bounds of the QR code read on the camera feed as well. To get the bounds
simply pass the metadata object to videoPreviewLayer' s transformedMetadataObject method like below.
func viewDidLoad() {
self.initCaptureSession()
}
self._viewController?.view.layer
.addSublayer(videoPreviewLayer!)
self.captureSession?.startRunning()
} catch {
//TODO: handle input open error
}
}
private func dismissCaptureSession() {
if let running = self.captureSession?.isRunning, running {
self.captureSession?.stopRunning()
}
self.captureSession = nil
self.videoPreviewLayer?.removeFromSuperLayer()
self.videoPreviewLayer = nil
}
if let metadataObj =
metadataObjects[0] as? AVMetadataMachineReadableCodeObject {
guard metadataObj.type == AVMetadataObjectTypeQRCode else {
return
}
handleQRRead - will be called on a successful scan initCaptureSession - initialize scanning for QR and camera input
dismissCaptureSession - hide the camera input and stop scanning
// Your dictionary contains an array of dictionary // Now pull an Array out of it.
For this purpose you will have to store your plist in Document Directory. You can edit your plist saved in document
directory.
if(plistData)
{
[plistData writeToFile:plistPath atomically:YES];
}
}
else
{
You can edit remove, add new data as per your requirement and save the plist again to Document Directory.
func startWatchSession(){
if(WCSession.isSupported()){
watchSession = WCSession.default()
watchSession!.delegate = self
watchSession!.activate()
}
}
Normally used to perform tasks on application startup (setup app environment, analitycs (ex.:
Mixpanel/GoogleAnalytics/Crashlitics), DB stack etc.) and shutdown (ex.: save DB context), handling URL open
requests and similar application-wide tasks.
AppDidFinishLaunching
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the active state; here you can undo
many of the changes made on entering the background.
}
When App Launching and also background to Foreground hit below method:
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive.
If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store
enough application state information to restore your application to its current state in case it is
terminated later.
// If your application supports background execution, this method is called instead of
applicationWillTerminate: when the user quits.
}
- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for
certain types of temporary interruptions (such as an incoming phone call or SMS message) or when
the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering
callbacks. Games should use this method to pause the game.
}
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also
applicationDidEnterBackground:.
}
Example of usage:
Registration:
In case where the submission is an update to the existing app on the store, make sure that the build number is
higher than the current and that the version number is different. For example, current application has build
number 30 and version label 1.0. The next update should have at least build number 31 and version label 1.0.1. In
most cases, you should add third decimal to your version in case of some urgent bug fixes or small patches, second
decimal is mostly reserved for feature updates while first decimal is incremented in case of a major app update.
If you have multiple accounts in your Xcode, you will be asked to choose. Naturally pick the one you used for code
signing in the first step. Pick "Deliver your app" and upload the code. Once the upload is done it may take up to one
do {
//here I write chunk data to ReadData or you can directly write to socket.
ReadData.append(datas!)
print("Running: \(ReadData.length)")
}
After file reading complete you will get file Data in ReadData variable Here outputFileHandle is a object
of FileHandle
import UIKit
print("FilePath: \(fileURL.path)")
// Reading
var fromFileString = ""
do {
fromFileString = try String(contentsOfURL: fileURL)
} catch let error as NSError {
print("Failed reading from URL: \(fileURL), Error: " + error.localizedDescription)
}
print("Text input from file: \(fromFileString)")
Swift 2
import UIKit
let fileURL =
DocumentDirectoryURL.URLByAppendingPathComponent(fileName).URLByAppendingPathExtension("txt")
print("FilePath: \(fileURL.path)")
// Reading
var fromFileString = ""
do {
fromFileString = try String(contentsOfURL: fileURL)
Swift
let synthesizer = AVSpeechSynthesizer()
let utterance = AVSpeechUtterance(string: "Some text")
utterance.rate = 0.2
In Swift 2 : synthesizer.speakUtterance(utterance)
In Swift 3 : synthesizer.speak(utterance)
Helpful methods
You can Stop or Pause all speech using these two methods :
- (BOOL)pauseSpeakingAtBoundary:(AVSpeechBoundary)boundary;
- (BOOL)stopSpeakingAtBoundary:(AVSpeechBoundary)boundary;
The AVSpeechBoundary indicates if the speech should pause or stop immediately (AVSpeechBoundaryImmediate) or
it should pause or stop after the word currently being spoken (AVSpeechBoundaryWord).
!!! A very important note is that the MPVolumeView only works on an actual device and not on a simulator.
First introduced in iOS 3.1 as part of the Objective-C runtime, associated objects provide a way to add instance
variables to an existing class object (w\o subclassing.
This means you'll be able to attach any object to any other object without subclassing.
In this example we not only create an associated object but also wrap it in a computed property in a category for
extra neatness
#import <objc/runtime.h>
- (void)setAssociated:(NSString *)object {
objc_setAssociatedObject(self, @selector(associated), object,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *)associated {
return objc_getAssociatedObject(self, @selector(associated));
}
For example entity A can place a message that entity B can read whenever suitable.
A view controller would like to talk to another view controller, but you don't want to create a strong or weak
relationship.
// set
messageBox.setObject("TestObject1", forKey:"TestKey1")
// get
// but don't remove it, keep it stored, so that it can still be retrieved later
let someObject:String = messageBox.getObject(forKey:"TestKey1", removeIfFound:false)
// get
// and remove it
let someObject:String = messageBox.getObject(forKey:"TestKey1", removeIfFound:true)
The diagram above shows how MVVM looks like. You have a standard ViewController + View (in storyboard, XIB or
Code), which acts as MVVM's View (in later text - View will reference MVVM's View). A view has a reference to a
ViewModel, where our business logic is. It's important to notice that ViewModel doesn't know anything about the
View and never has a reference to the view. ViewModel has a reference to a Model.
This is enough with a theoretical part of the MVVM. More about it can be read here.
One of the main issues with MVVM is how to update View via the ViewModel when ViewModel doesn't have any
references and doesn't even know anything about the View.
The main part of this example is to show how to use MVVM (more precisely, how to bind ViewModel and View)
without any reactive programming (ReactiveCocoa, ReactiveSwift or RxSwif). Just as a note: if you want to use
Reactive programming, even better since MVVM bindings are done really easy using it. But this example is on how
to use MVVM without Reactive programming.
Our MVVMExampleViewController is a simple ViewController with a label and a button. When button is pressed, the
label text should be set to 'Hello'. Since deciding what to do on user user interaction is part of the business logic,
ViewModel will have to decide what to do when user presses the button. MVVM's View shouldn't do any business
logic.
func userTriggeredSayHelloButton() {
// How to update View's label when there is no reference to the View??
}
}
You might wonder, how to set the ViewModel's reference in the View. I usually do it when ViewController is being
initialized or before it will be shown. For this simple example, I would do something like this in the AppDelegate:
return true
The real question now is: how to update View from ViewModel without giving a reference to the View to the
ViewModel? (Remember, we won't use any of the Reactive Programming iOS libraries)
You could think about using KVO, but that would just complicate things too much. Some smart people have thought
about the issue and came up with the Bond library. The library might seem complicated and a little harder to
understand at first, so I'll just take one small part of it and make our MVVM fully functional.
Let's introduce the Dynamic class which is the core of our simple yet fully functional MVVM pattern.
class Dynamic<T> {
typealias Listener = (T) -> Void
var listener: Listener?
var value: T {
didSet {
listener?(value)
}
}
init(_ v: T) {
value = v
}
}
Dynamic class is using Generics and Closures to bind our ViewModel with our View. I won't go into details about this
class, we can do it in the comments (to make this example shorter). Let's now update our
MVVMExampleViewController and MVVMExampleViewModel to use those classes.
func bindViewModel() {
if let viewModel = viewModel {
viewModel.helloText.bind({ (helloText) in
DispatchQueue.main.async {
// When value of the helloText Dynamic variable
// is set or changed in the ViewModel, this code will
// be executed
self.helloLabel.text = helloText
}
})
}
}
Updated MVVMExampleViewModel:
class MVVMExampleViewModel {
func userTriggeredSayHelloButton() {
// Setting the value of the Dynamic variable
// will trigger the closure we defined in the View
helloText.value = "Hello"
}
}
That is it. Your ViewModel is now able to update View without it having a reference to the View.
This is a really simple example, but I think you have an idea how powerful this can be. I won't go into details about
benefits of the MVVM, but once you switch from MVC to MVVM, you won't go back. Just try it and see for yourself.
SetUp:
Alamofire.request(self.nameUrl[i]).responseImage { response in
if response.result.value != nil {
let image = UIImage(data: response.data!, scale: 1.0)!
imageCache.add(image, withIdentifier: self.nameUrl[i])
}
}
https://github.com/MKGitHub/MKBlockQueue
// block 1
let b1:MKBlockQueueBlockType =
{
(blockQueueObserver:MKBlockQueueObserver, dictionary:inout Dictionary<String, Any>) in
// block 2
let b2:MKBlockQueueBlockType =
{
(blockQueueObserver:MKBlockQueueObserver, dictionary:inout Dictionary<String, Any>) in
copyOfDictionary["Block2Key"] = "Block2Value"
copyOfDictionary["Block3Key"] = "Block3Value"
// run queue
print("Queue starting with dictionary: \(myDictionary)")
myBlockQueue.run(with:&myDictionary)
Using "Simulator", you could run iOS and tvOS, but "Simulator (Watch)" will only run watchOS.
If your MacBook has a Force Touch trackpad, you could use your trackpad force to simulate 3D / Force
Touch.
Lock
Rotation
To get started:
Swift
UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplicationBackgroundFetchIntervalMinimum)
Objective-C
[[UIApplication shared]
setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum]
Now you will see that data is fetched and ready for you.
iOS will automatically handle this for you, and you don't need to write any code!
In examples you'll find a simple project built with MVP pattern in mind.
struct Dog {
let name: String
let breed: String
let age: Int
}
class DoggyService {
DispatchQueue.main.asyncAfter(deadline: delay) {
result([firstDoggy,
secondDoggy,
thirdDoggy])
}
}
}
class DoggyPresenter {
// MARK: - Private
fileprivate let dogService: DoggyService
init(dogService: DoggyService){
self.dogService = dogService
}
func getDogs(){
self.dogView?.startLoading()
if doggies.count == 0 {
self?.dogView?.setEmpty()
} else {
self?.dogView?.setDoggies(doggies.map {
return DoggyViewData(name: "\($0.name) \($0.breed)",
age: "\($0.age)")
})
}
}
}
}
struct DoggyViewData {
let name: String
let age: String
}
tableView?.dataSource = self
spinner?.hidesWhenStopped = true
dogPresenter.attachView(true, view: self)
dogPresenter.getDogs()
}
// MARK: DataSource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dogsToDisplay.count
}
func startLoading() {
spinner?.startAnimating()
}
func finishLoading() {
spinner?.stopAnimating()
}
func setEmpty() {
tableView?.isHidden = true
emptyView?.isHidden = false;
}
}
Callback to centralManagerDidUpdateState indicates that CoreBluetooth is ready, so you can search for BLE now.
Update centralManagerDidUpdateState code to search for all BLE device when it is ready.
func SearchBLE(){
cb_manager.scanForPeripherals(withServices: nil, options: nil)
StopSearchBLE()
}
func StopSearchBLE() {
let when = DispatchTime.now() + 5 // change 5 to desired number of seconds
DispatchQueue.main.asyncAfter(deadline: when) {
self.cb_manager.stopScan()
}
}
In the documention of your BLE device, you should look for the SERVICE UUID and MAJOR UUID
CHARACTERISTIC
Create a variable 'service_uuid' and 'major_uuid' like code above. '-0000-1000-8000-00805f9b34fb' is part of
the standard. 'fff0' is my SERVICE UUID, 'fff2' is my MAJOR UUID characteristic and '0000' are required to fill
the 4 bytes uuid 1º block.
discoverCharacteristics([major_uuid], for: (peripheral.services?[0])!) will get major characteristic from my
device gatt server and it will have NIL as value for now.
(peripheral.services?[0])! - 0 beacuse will return a single value once I did
peripheral.discoverServices([service_uuid])
iPhone by deafult will send and receive bytes in Little Endian format, but my device MINEW witch chipset
NRF51822 have ARM archteture and need bytes in Big Endian format, so I have to swap it.
BLE Device documentation will say what type of input and output each characteristic will have and if you can
read it like above (CBCharacteristicWriteType.withResponse).
To update a gatt server information you have to reboot it programmatically or save data to it and turn off
and turn on manually.
FFFF is characteristic that do it in this device.
'minew123' is the default password for reboot o save information in this case.
run your app and watch you console for any error, I hope none, but you will not see the new value yet.
Last step is to comment last line in method didUpdateValueFor and rerun the app, now you will the new
value.
Core Data isn't the database of your application nor is it an API for persisting data to a database. Core Data is a
framework that manages an object graph. It's as simple as that. Core Data can persist that object graph by writing it
to disk, but that is not the primary goal of the framework.
To fetch data:
To add data:
To save context:
This screen displays the Call Tree. The Call Tree shows the amount of time spent executing in various methods
within an app. Each row is a different method that the program’s execution path has followed. The time spent in
each method can be determined from the number of times the profiler is stopped in each method. For instance, if
100 samples are done at 1 millisecond intervals, and a particular method is found to be at the top of the stack in
10 samples, then you can deduce that approximately 10% of the total execution time — 10 milliseconds — was
spent in that method. It’s a fairly crude approximation, but it works!
From Xcode’s menu bar, select Product\Profile, or press ?I. This will build the app and launch Instruments. You
will be greeted with a selection window that looks like this:
Select the Time Profiler instrument and click Choose. This will open up a new Instruments document. Click the
red record button in the top left to start recording and launch the app. You may be asked for your password to
authorize Instruments to analyze other processes — fear not, it’s safe to provide here! In the Instruments
window, you can see the time counting up, and a little arrow moving from left to right above the graph in the
center of the screen. This indicates that the app is running.
Now, start using the app. Search for some images, and drill down into one or more of the search results. You have
probably noticed that going into a search result is tediously slow, and scrolling through a list of search results is also
incredibly annoying – it’s a terribly clunky app!
Well, you’re in luck, for you’re about to embark on fixing it! However, you’re first going to get a quick run down on
what you’re looking at in Instruments. First, make sure the view selector on the right hand side of the toolbar has
both options selected, like so:
That will ensure that all panels are open. Now study the screenshot below and the explanation of each section
beneath it:
2. This is the run timer. The timer counts how long the app being profiled has been running, and how many times it
has been run. If you stop and then restart the app using the recording controls, that would start a new run and the
display would then show Run 2 of 2.
3. This is called a track. In the case of the Time Profiler template you selected, there’s just one instrument so there’s
just one track. You’ll learn more about the specifics of the graph shown here later in the tutorial.
4. This is the detail panel. It shows the main information about the particular instrument you’re using. In this case,
it’s showing the methods which are “hottest” — that is, the ones that have used up the most CPU time. If you click
on the bar at the top which says Call Tree (the left hand one) and select Sample List, then you are presented with a
different view of the data. This view is showing every single sample. Click on a few samples, and you’ll see the
captured stack trace appear in the Extended Detail inspector.
5. This is the inspectors panel. There are three inspectors: Record Settings, Display Settings, and Extended Detail.
You’ll be learning more about some of these options shortly.
Drilling Deep
Perform an image search, and drill into the results. I personally like searching for “dog”, but choose whatever you
wish – you might be one of those cat people!
You really wouldn’t expect any UI to be as clunky as this no table view is ready to ship until it scrolls like butter! To
help pinpoint the problem, you need to set some options.
On the right hand side, select the Display Settings inspector (or press ?+2). In the inspector, under the Call
Tree section, select Separate by Thread, Invert Call Tree, Hide Missing Symbols and Hide System Libraries. It will
look like this:
Here’s what each option is doing to the data displayed in the table to the left:
Separate by Thread: Each thread should be considered separately. This enables you to understand which threads
are responsible for the greatest amount of CPU use.
Invert Call Tree: With this option, the stack trace is considered from top to bottom. This is usually what you want,
as you want to see the deepest methods where the CPU is spending its time.
Hide Missing Symbols: If the dSYM file cannot be found for your app or a system framework, then instead of seeing
method names (symbols) in the table, you’ll just see hex values corresponding to addresses inside the binary. If this
option is selected, then only fully resolved symbols are displayed and the unresolved hex values are hidden. This
helps to declutter the data presented.
Hide System Libraries: When this option is selected, only symbols from your own app are displayed. It’s often
useful to select this option, since usually you only care about where the CPU is spending time in your own code –
you can’t do much about how much CPU the system libraries are using!
Flatten Recursion: This option treats recursive functions (ones which call themselves) as one entry in each stack
trace, rather than multiple.
Top Functions: Enabling this makes Instruments consider the total time spent in a function as the sum of the time
directly within that function, as well as the time spent in functions called by that function.
So if function A calls B, then A’s time is reported as the time spent in A PLUS the time spent in B. This can be really
useful, as it lets you pick the largest time figure each time you descend into the call stack, zeroing in on your most
If you’re running an Objective-C app, there’s also an option of Show Obj-C Only: If this is selected, then only
Objective-C methods are displayed, rather than any C or C++ functions. There are none in your program, but if you
were looking at an OpenGL app, it might have some C++, for example.
Although some values may be slightly different, the order of the entries should be similar to the table below once
you have enabled the options above:
Well, that certainly doesn’t look too good. The vast majority of time is spent in the method that applies the ‘tonal’
filter to the thumbnail photos. That shouldn’t come as too much of a shock to you, as the table loading and scrolling
were the clunkiest parts of the UI, and that’s when the table cells are constantly being updated.
To find out more about what’s going on within that method, double click its row in the table. Doing so will bring up
the following view:
Well that’s interesting, isn’t it! applyTonalFilter() is a method added to UIImage in an extension, and almost 100%
of the time spent in it is spent creating the CGImage output after applying the image filter.
There’s not really much that can be done to speed this up: creating the image is quite an intensive process, and
takes as long as it takes. Let’s try stepping back and seeing where applyTonalFilter() is called from. Click Call
Tree in the breadcrumb trail at the top of the code view to get back to the previous screen:
Now click the small arrow to the left of the applyTonalFilter row at the top of the table. This will unfold the Call Tree
Now you can see what the problem is. The method to apply the tonal filter takes a long time to execute, and it’s
called directly from cellForItemAtIndexPath, which will block the main thread (and therefore the entire UI) each
time it’s ask for a filtered image.
Allocations
There are detailed information about all the objects that are being created and the memory that backs them; it
also shows you retain counts of each object. To start afresh with a new instruments profile, quit the
Instruments app. This time, build and run the app, and open the Debug Navigator in the Navigators area. Then click
on Memory to display graphs of memory usage in the main window:
These graphs are useful for to get a quick idea about how your app is performing. But you’re going to need a bit
more power. Click the Profile in Instruments button and then Transfer to bring this session into Instruments.
The Allocations instrument will start up automatically.
True memory leaks are where an object is no longer referenced by anything but still allocated – that means the
memory can never be re-used. Even with Swift and ARC helping manage memory, the most common kind of
memory leak is a retain cycle or strong reference cycle. This is when two objects hold strong references to
one another, so that each object keeps the other one from being deallocated. This means that their memory is
never released!
Unbounded memory growth is where memory continues to be allocated and is never given a chance to be
deallocated. If this continues forever, then at some point the system’s memory will be filled and you’ll have a big
memory problem on your hands. In iOS this means that the app will be killed by the system.
With the Allocations instrument running on the app, make five different searches in the app but do not drill down
into the results yet. Make sure the searches have some results! Now let the app settle a bit by waiting a few
seconds.
You should have noticed that the graph in the Allocations track has been rising. This is telling you that memory is
being allocated. It’s this feature that will guide you to finding unbounded memory growth.
What you’re going to perform is a generation analysis. To do this, press the button called Mark Generation. You’ll
find the button at the top of the Display Settings inspector:
The purpose of generation analysis is to perform an action multiple times, and see if memory is growing in an
unbounded fashion. Drill into a search, wait a few seconds for the images to load, and then go back to the main
page. Then mark the generation again. Do this repeatedly for different searches. After a drilling into a few
searches, Instruments will look like this:
At this point, you should be getting suspicious. Notice how the blue graph is going up with each search that you
drill into. Well, that certainly isn’t good. But wait, what about memory warnings? You know about those, right?
Memory warnings are iOS’s way of telling an app that things are getting tight in the memory department, and you
need to clear out some memory.
Simulate a memory warning by selecting Instrument\Simulate Memory Warning in Instruments’ menu bar, or
Hardware\Simulate Memory Warning from the simulator’s menu bar. You’ll notice that memory usage dips a little,
or perhaps not at all. Certainly not back to where it should be. So there’s still unbounded memory growth
happening somewhere.
The reason for marking a generation after each iteration of drilling into a search is that you can see what memory
has been allocated between each generation. Take a look in the detail panel and you’ll see a bunch of generations.
In addition, you can continue to include a persistent link in the settings or configuration screens of your app that
deep-links to your App Store product page. To automatically ope
SKStoreReviewController.requestReview()
UIView *A = UIView.new;
A.leftPos.equalTo(@0.2);
A.rightPos.equalTo(@0.3);
A.heightSize.equalTo(A.widthSize);
[S addSubview:A];
UIView *B = UIView.new;
B.leftPos.equalTo(@40);
B.widthSize.equalTo(@60);
B.heightSize.equalTo(@40);
[S addSubview:B];
UIView *C = UIView.new;
UIView *D = UIView.new;
D.rightPos.equalTo(@20);
D.widthSize.equalTo(S.widthSize).multiply(0.5);
D.heightSize.equalTo(@40);
[S addSubview:D];
Go to ~/Library/Developer/CoreSimulator/Devices/
then click on the one of the directories and make following selection
Data/Containers/Bundle/Application/
Again you will find directories with alphanumeric names if you click on that you will find
Note:
-(void)checkAndOpenDB{
sqlite3 *db;
NSString *strPassword = @"password";
- (NSURL *)databaseURL
{
NSArray *URLs = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask];
NSURL *directoryURL = [URLs firstObject];
NSURL *databaseURL = [directoryURL URLByAppendingPathComponent:@"database.sqlite"];
return databaseURL;
}
But we can exclude our app data from this backup using URLResourceKey.isExcludedFromBackupKey key.
Here is the directory structure of our app:
e.g. If we want to exclude all our data stored in Application Support directory then we can use above mentioned
key as follow:
There are lots of tools available to see iTunes backups for all the backed up data to confirm whether above
approach works or not.
Whenever app tries to call web services to pull or push data to servers, it should use SSL over HTTP, i.e. HTTPS.
To do this, app must call https://server.com/part such web services and not http://server.com/part.
In this case, app needs to trust the server server.com using SSL certificate.
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
let serverTrust:SecTrust = challenge.protectionSpace.serverTrust!
func acceptServerTrust() {
let credential:URLCredential = URLCredential(trust: serverTrust)
challenge.sender?.use(credential, for: challenge)
completionHandler(.useCredential, URLCredential(trust:
challenge.protectionSpace.serverTrust!))
}
@implementation SSLTrustManager
+ (BOOL)shouldTrustServerTrust:(SecTrustRef)serverTrust forCert:(NSString*)certName {
// Load up the bundled certificate.
NSString *certPath = [[NSBundle mainBundle] pathForResource:certName ofType:@"der"];
NSData *certData = [[NSData alloc] initWithContentsOfFile:certPath];
CFDataRef certDataRef = (__bridge_retained CFDataRef)certData;
SecCertificateRef cert = SecCertificateCreateWithData(NULL, certDataRef);
// Clean up.
CFRelease(certArrayRef);
CFRelease(cert);
CFRelease(certDataRef);
Using this approach our app can make sure that it is communicating to the intended server and no one is
intercepting the app-server communication.
ATS is configured in the target's Info.plist file with the NSAppTransportSecurity dictionary (App Transport
Security Settings in the Xcode Info.plist editor). To allow all HTTP content, add the Allow Arbitrary Loads
boolean (NSAllowsArbitraryLoads) and set it to YES. This is not recommended for production apps, and if HTTP
content is required, it is recommended that it be selectively enabled instead.
For every domain, add a dictionary item to the Exception Domains, where the key is the domain in question. Set
NSExceptionAllowsInsecureHTTPLoads to YES to disable the HTTPS requirement for that domain.
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>testdomain.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
The key that permits such behavior is NSExceptionAllowsInsecureHTTPLoads. In this case, app will allow HTTP
connection to mentioned domain (testdomain.com) only and block all other HTTP connections.
The key NSIncludesSubdomains specifies that any and all subdomains of the mentioned domain (testdomain.com)
should also be allowed.
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
In this case, app will allow HTTP connection to any domain. As of January 1st 2017, using this flag will cause
thorough App Store review and the app developers will have to explain why they need to use this exception in the
first place. Possible explanations include:
An application that loads encrypted media content that contains no personalized information.
Connections to devices that cannot be upgraded to use secure connections.
Connection to a server that is managed by another entity and does not support secure connections.
protocol GreetingViewPresenter {
init(view: GreetingView, person: Person)
func showGreeting()
}
protocol GreetingProvider {
func provideGreetingData()
}
func provideGreetingData() {
let person = Person(firstName: "David", lastName: "Blaine") // usually comes from data
access layer
let subject = person.firstName + " " + person.lastName
let greeting = GreetingData(greeting: "Hello", subject: subject)
self.output.receiveGreetingData(greeting)
}
}
protocol GreetingViewEventHandler {
func didTapShowGreetingButton()
}
func didTapShowGreetingButton() {
self.greetingProvider.provideGreetingData()
}
}
// layout code goes here
}
// Assembling of MVC
let model = Person(firstName: "David", lastName: "Blaine")
let view = GreetingViewController()
view.person = model
#import <Foundation/Foundation.h>
{
//Handle multiple observers of delegate
NSMutableArray* _delegates;
}
@end
#import "RRMulticastDelegate.h"
@implementation RRMulticastDelegate
- (id)init
{
if (self = [super init])
{
_delegates = [NSMutableArray array];
}
return self;
}
-(NSArray *)delegatesObjects
{
return _delegates;
}
- (void)removeDelegate:(id)delegate
{
if ([_delegates containsObject:delegate])
[_delegates removeObject:delegate];
}
- (void)addDelegate:(id)delegate
- (BOOL)respondsToSelector:(SEL)aSelector
{
if ([super respondsToSelector:aSelector])
return YES;
if ([delegate respondsToSelector:aSelector])
{
return YES;
}
}
return NO;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
// can this class create the sinature?
NSMethodSignature* signature = [super methodSignatureForSelector:aSelector];
if ([delegate respondsToSelector:aSelector])
{
return [delegate methodSignatureForSelector:aSelector];
}
}
}
return signature;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
// forward the invocation to every delegate
for(id delegate in _delegates)
{
if (!delegate)
continue;
@end
#import <Foundation/Foundation.h>
#import "RRMulticastDelegate.h"
- (RRMulticastDelegate *)multicastDelegate;
- (RRMulticastDelegate *)multicastDatasource;
-(void)addDelegate:(id)delegate;
-(void)addDataSource:(id)datasource;
@end
#import "NSObject+RRProperty.h"
#import <objc/message.h>
#import <objc/runtime.h>
-(id)objectForKey:(NSString *)key
{
return objc_getAssociatedObject(self, (__bridge const void *)(key));
}
- (RRMulticastDelegate *)multicastDelegate
{
id multicastDelegate = [self objectForKey:MULTICASTDELEGATE];
if (multicastDelegate == nil) {
multicastDelegate = [[RRMulticastDelegate alloc] init];
return multicastDelegate;
}
return multicastDatasource;
}
-(void)addDelegate:(id)delegate
{
[self.multicastDelegate addDelegate:delegate];
-(void)addDataSource:(id)datasource
{
[self.multicastDatasource addDelegate:datasource];
UITableView *text = (UITableView *) self;
text.dataSource = self.multicastDatasource;
}
@end
For ex...
Import your viewcontroller class in NSObject+RRProperty.h file to access its methods to set multicast
delegate/datasource.
These assets can be App Icons, Launch Images, images used throughout the app, full size images, random
sized images etc.
Similar to AppIcons we have to mention in project settings about using image assets for launch screen image.
By default project settings are like:
Once we change these settings, Xcode will asks us to migrate to assets and create LaunchImage file in assets
automatically as:
I filled these images for iPhones of 4" screen to 5.5" and for all iPads as:
Notes:
1 non-retina iPads: I left blank 1x iPad Portrait and Landscape because non-retina iPads will use 2x launch
images by scaling
2 12.9" iPad Pro: there is no square for this iPad because this iPad will also use 2x iPad images by scaling them
3 Retina HD 5.5": iPads should have 1920x1080px for portrait and 1080x1920px for landscape but Xcode will give
waring and launch image will not be shown on those devices
4 SplitView: as we are using LaunchImage Asset instead of LaunchScreen XIB, our app will not support SplitView
on iPads and landscape 5.5" iPhones
5 Reinstall: if our app is already installed on device and we try to run with these newly added launch image assets,
then sometimes device will not show launch images while launching app. In this case just delete app from device,
clean+build project and run it, it'll show new launch images
It is there by default, but if it's not then make sure this settings is as in Target->General settings:
Objective-C Implementation
#import <objc/runtime.h>
- (UIActivityIndicatorView *)activityIndicator {
return (UIActivityIndicatorView *)objc_getAssociatedObject(self, &ActivityIndicatorKey);
}
- (void)showActivityIndicator {
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc]
initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleGray];
[self setActivityIndicator:activityIndicator];
activityIndicator.center = self.center;
activityIndicator.autoresizingMask = UIViewAutoresizingFlexibleTopMargin |
UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleBottomMargin;
[activityIndicator startAnimating];
- (void)hideActivityIndicator {
UIActivityIndicatorView * activityIndicator = [self activityIndicator];
if (activityIndicator != nil) {
[[self activityIndicator] removeFromSuperview];
}
}
@end
Swift Code
extension UIView {
private struct AssociatedKeys {
static var activityIndicator = "UIView.ActivityIndicatorView"
}
func showActivityIndicator() {
activityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle: .gray)
activityIndicatorView.center = center
activityIndicatorView.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin,
.flexibleTopMargin, .flexibleBottomMargin]
activityIndicatorView.startAnimating()
addSubview(activityIndicatorView)
}
func hideActivityIndicator() {
activityIndicatorView.removeFromSuperview()
}
}
1. fullScreen
2. pageSheet
3. formSheet
4. currentContext
5. custom
6. overFullScreen
7. overCurrentContext
8. popover
9. none
To setup a project, just create a normal iOS project and add 2 ViewControllers. Put a UIButton in you initial
ViewController and connect it to 2nd ViewController via a Target -> Action mechanism. To distinguish both
ViewControllers, set background property of UIView in ViewController some other color. If all goes well, your
Interface Builder should look something this,
Now, we won't see all of the effects in this example as some of them requires little bit of code.
Let's start with fullscreen. This effect is selected by default when you select Present Modally in Kind tab. When
you build and run, the 2nd ViewController would occupy the full screen of you iPad.
For formSheet style, the 2nd ViewController is placed in center of device and the size is smaller to that of device.
Also when device is in landscape mode and keyboard is visible position of view is adjusted upwards to show the
ViewController.
Anchor is the UI element to which you want your popover arrow to point. Directions are the directions you allow
your popover Anchor to point in.
Those tweaks will enable you to modify the operating system's behavior to act the way you would like it to.
$THEOS/bin/nic.pl
Fill in the details and you will get the following files created:
%hook SBScreenShotter
- (void)saveScreenshot:(BOOL)screenshot
{
%orig;
NSLog(@"saveScreenshot: is called");
}
%end
Note you can choose wether or not the original function should be called, for example:
will override the function without calling the original one, thus casing screenshots not being saved.
[assetWriter startWriting];
[assetWriter startSessionAtSourceTime:kCMTimeZero];
[assetWriterInput requestMediaDataWhenReadyOnQueue:exportingQueue usingBlock:^{
for (int i = 0; i < images.count; ++i) {
while (![assetWriterInput isReadyForMoreMediaData]) {
CVPixelBufferRelease(buffer);
}
[assetWriterInput markAsFinished];
[assetWriter finishWritingWithCompletionHandler:^{
if (assetWriter.error) {
// show error message
} else {
// outputURL
}
}];
}];
if (outBuffer) {
[context render:ciImage toCVPixelBuffer:*outBuffer];
}
return kCVReturnSuccess;
}
Codable use to support both encoding and decoding, declare conformance to Codable, which combines the
Encodable and Decodable protocols. This process is known as making your types codable.
The upMovie contains the name “Up” and it’s movieGenere is comedy, adventure and animation witch contains 4
rating out of 5.
Encode
JSONEncoder is an object that encodes instances of a data type as JSON objects. JSONEncoder supports the Codable
object.
// Encode data
let jsonEncoder = JSONEncoder()
do {
let jsonData = try jsonEncoder.encode(upMovie)
let jsonString = String(data: jsonData, encoding: .utf8)
print("JSON String : " + jsonString!)
}
catch {
}
JSONEncoder will give us the JSON data which is used to retrieve JSON string.
{
"name": "Up",
"moviesGenere": [
"comedy",
"adventure",
"animation"
Decode
JSONDecoder is an object that decodes instances of a data type from JSON objects. We can get the object back from
the JSON string.
do {
// Decode data to object
By decoding the JSONData we will receive the Movie object back. So we can get all the values which is saved in that
object.
Name : Up
Rating : 4
In the cellForRowAt: function of the tableView we would download the image and set in the following way:
The url should point to the image that you want to download and the placeHolder image should be a stored image.
We then call the af_setImage method on the imageView which downloads the image at the given url and during the
download the placeholder image will be shown. As soon as the image is downloaded the requested image is
displayed
Section 207.2: Check that the cell is still visible after download
Sometimes the download takes longer than the cell is being displayed. In this case it can happen, that the
downloaded image is shown in the wrong cell. To fix this we can not use the UIImageView Extension.
We still will be using Alamofire however we will use the completion handler to display the image.
In this scenario we still need a tableView with a cell which has a imageView in it. In the cellForRowAt: method we
would download the image with the following code:
In this example we first set the image to the placeholder image. Afterwards we download the image with the
request method of Alamofire. We pass the url as the first argument and since we just want to get the image we will
use the .get HTTP method. Since we are downloading an image we want the response to be an image therefore we
use the .responseImage method.
After the image has been downloaded the closure gets called and first of all we make sure that the downloaded
image actually exists. Then we make sure that the cell is still visible by checking that the cellForRow(at: indexPath)
doesn't return nil. If it does nothing happens, if it doesn't we assign the recently downloaded image.
This last if statement ensures that the cell is still visible if the user already scrolled over the cell the updateCell will
be nil and the if statement returns nil. This helps us prevent displaying the wrong image in a cell.
Name your file “YourProjectName-Bridging-Header.h”. Example: In my app Station, the file is named “Station-
Bridging-Header”.
Navigate to your project build settings and find the “Swift Compiler – Code Generation” section. You may find
it faster to type in “Swift Compiler” into the search box to narrow down the results. Note: If you don’t have a
“Swift Compiler – Code Generation” section, this means you probably don’t have any Swift classes added to
your project yet. Add a Swift file, then try again.
Next to “Objective-C Bridging Header” you will need to add the name/path of your header file. If your file
resides in your project’s root folder simply put the name of the header file there. Examples:
“ProjectName/ProjectName-Bridging-Header.h” or simply “ProjectName-Bridging-Header.h”.
Open up your newly created bridging header and import your Objective-C classes using #import statements.
Any class listed in this file will be able to be accessed from your swift classes.
You can only offer In-App Purchases for digital items, and not for physical goods or services. For more information
about all of this, check out Apple’s full documentation on Creating In-App Purchase Products. Now, while viewing
your app’s entry in iTunes Connect, click on the Features tab and then select In-App Purchases. To add a new IAP
product, click the + to the right of In-App Purchases.
Reference Name: A nickname identifying the IAP within iTunes Connect. This name does not appear
anywhere in the app. The title of the comic you’ll be unlocking with this purchase is “Girlfriend of
Drummer“, so enter that here.
Product ID: This is a unique string identifying the IAP. Usually it’s best to start with the Bundle ID and then
append a unique name specific to this purchasable item. For this tutorial, make sure you append
“GirlfriendOfDrummerRage“, as this will be used later within the app to look up the comic to unlock. So, for
example: com.theNameYouPickedEarlier.Rage.GirlFriendOfDrummerRage.
Cleared for Sale: Enables or disables the sale of the IAP. You want to enable it!
Price Tier: The cost of the IAP. Choose Tier 1.
Now scroll down to the Localizations section and note that there is a default entry for English (U.S.). Enter
“Girlfriend of Drummer” for both the Display Name and the Description. Click Save. Great! You’ve created your first
IAP product.
Fill out the information and click Save when you’re done. You can make up a first and last name for your test user,
but the email address chosen must be a real email address as a verification will be sent to the address by Apple.
Once you receive that email, be sure to click the link in it to verify your address. The email address you enter should
also NOT already be associated with an Apple ID account. Hint: if you have a gmail account, you can simply use an
address alias instead of having to create a brand new account
You can show the Onboarding flow by simply setting the UIApplication.shared.keyWindow.rootViewController
You also have to set the frame of the Main view before you transition back to it, as you're instantiating it for the first
time.
// MARK: - Onboarding
extension AppDelegate {
func showOnboarding() {
if let window = UIApplication.shared.keyWindow, let onboardingViewController =
UIStoryboard(name: "Onboarding", bundle: nil).instantiateInitialViewController() as?
OnboardingViewController {
onboardingViewController.delegate = self
window.rootViewController = onboardingViewController
}
}
func hideOnboarding() {
if let window = UIApplication.shared.keyWindow, let mainViewController = UIStoryboard(name:
"Main", bundle: nil).instantiateInitialViewController() {
mainViewController.view.frame = window.bounds
UIView.transition(with: window, duration: 0.5, options: .transitionCrossDissolve,
animations: {
window.rootViewController = mainViewController
}, completion: nil)
}
}
}
Presenting modally allows the simple option of dismissal at the end of the journey, with little of the cruft of
swapping controllers.
Custom transitions are also supported in the standard way, since this uses the ViewController.present() API:
// MARK: - Onboarding
extension AppDelegate {
func showOnboarding() {
if let window = window, let onboardingViewController = UIStoryboard(name: "Onboarding",
bundle: nil).instantiateInitialViewController() as? OnboardingViewController {
onboardingViewController.delegate = self
window.makeKeyAndVisible()
window.rootViewController?.present(onboardingViewController, animated: false,
completion: nil)
}
}
func hideOnboarding() {
if let window = UIApplication.shared.keyWindow {
window.rootViewController?.dismiss(animated: true, completion: nil)
}
}
}
4oby Chapter 2
Abhijit Chapter 192
abjurato Chapter 149
Adam Eberbach Chapters 11 and 38
Adam Preble Chapter 27
Adnan Aftab Chapter 79
Adriana Carelli Chapters 151 and 46
Ahmed Khalaf Chapter 28
AJ9 Chapter 14
ajmccall Chapter 65
Aju Chapter 15
Akilan Arasu Chapter 2
alaphao Chapters 67 and 20
Alex Chapters 92 and 40
Alex Kallam Chapter 74
Alex Koshy Chapters 2, 14, 74, 34, 95 and 38
Alex Rouse Chapter 61
Alexander Tkachenko Chapter 64
Ali Abbas Chapter 178
Ali Beadle Chapter 1
Ali Elsokary Chapter 34
Alistra Chapter 89
Alvin Abia Chapter 122
Amanpreet Chapter 107
amar Chapters 67, 96 and 97
Anand Nimje Chapters 1, 74, 38, 40, 76 and 117
Anatoliy Chapter 1
Andreas Chapters 151, 25 and 45
Andres Canella Chapter 2
Andres Kievsky Chapter 14
Andrii Chernenko Chapter 2
Anh Pham Chapters 11 and 20
Ankit chauhan Chapter 190
ApolloSoftware Chapter 79
Arefly Chapters 5 and 96
Ashish Kakkad Chapters 107, 113 and 206
Ashutosh Dave Chapter 1
askielboe Chapter 142
AstroCB Chapter 2
azimov Chapters 47, 56 and 119
backslash Chapter 52
Badal Shah Chapters 67, 30 and 144
balagurubaran Chapter 77
Bean Chapters 67 and 53
Bence Pattogato Chapter 74
BennX Chapter 131
bentford Chapter 2
Beto Caldas Chapter 189
beyowulf Chapters 59, 55 and 57