0903 Learning Ios
0903 Learning Ios
0903 Learning Ios
#ios
Table of Contents
About 1
Remarks 2
Notes 2
Versions 2
Examples 3
Hello World 11
Adding a label 14
Adding Code 15
Going on 17
Xcode Interface 17
Navigator Area 19
The Editors 19
Chapter 2: 3D Touch 32
Examples 32
Chapter 3: Accessibility 35
Introduction 35
Examples 35
Screen Change 35
Layout Change 36
Announcement 36
Ordering Elements 36
Accessibility Container 36
Modal View 37
Hiding Elements 37
Examples 39
Chapter 5: AFNetworking 41
Examples 41
Chapter 6: AirDrop 42
Examples 42
AirDrop 42
Examples 43
Chapter 8: Alamofire 45
Syntax 45
Parameters 45
Examples 45
Making a Request 45
Automatic Validation 45
Response Handling 45
Manual Validation 46
Response Handler 46
Examples 47
Parameters 52
Remarks 53
Examples 53
Examples 56
Introduction 57
Examples 57
AppDelegate Roles: 58
Introduction 61
Examples 61
Examples 62
Examples 64
Introduction 66
Syntax 66
Examples 66
Proportional Layout 76
Pinning 83
Center in container 84
Center Constraints 85
Remarks 102
Examples 102
Objective-C 102
Swift 102
Objective C 102
Swift 103
Syntax 104
Parameters 104
Examples 104
Examples 105
Introduction 108
Examples 108
Swift 109
Objective-C 110
Swift 110
Examples 112
Examples 114
Syntax 116
Examples 116
Remarks 118
Examples 118
Objective-C 118
Swift 118
OBJECTIVE-C 118
SWIFT 119
Objective C 120
Swift 120
Introduction 121
Examples 121
AlamofireImage 121
Syntax 122
Parameters 122
Remarks 122
Examples 122
Examples 129
Shadows 129
Related 135
Notes 135
Basics 135
Setup 136
Translate 137
Scale 138
Rotate 138
Examples 143
Syntax 144
Remarks 144
Examples 144
Examples 151
Remarks 154
Examples 154
Introduction 156
Examples 156
Examples 158
Changing the status bar style for the entire application 158
SWIFT: 158
Step 1: 158
Step 2: 158
OBJECTIVE-C: 159
Remarks 162
Caveats 162
Examples 162
Examples 165
Objective-C 165
Objective-C 166
Swift 166
Swift 3 166
Examples 167
Remarks 170
Examples 170
Swift 171
Swift 172
Objective-C 172
Note 172
Swift 172
Introduction 174
Examples 174
Examples 176
Development 176
Distribution 176
Introduction 177
Syntax 177
Parameters 177
Remarks 177
Examples 178
Running code concurrently -- Running code while running other code 178
Introduction 180
Remarks 180
Examples 181
Remarks 186
Examples 186
Swift 186
Objective-C 186
Swift 186
Objective-C 186
Swift 187
Swift 187
Objective-C 187
Swift 188
Swift 188
Swift 188
Swift 188
Remarks 190
Examples 190
Chapter 44: Convert HTML to NSAttributed string and vice verse 192
Examples 192
Objective C code to convert HTML string to NSAttributedString and Vice Versa 192
Examples 193
Introduction 194
Examples 194
Examples 195
Swift 195
Objective-C 195
Swift 196
Objective-C 196
Syntax 197
Remarks 197
Examples 198
Examples 205
Accessing Barometer to get relative altitude 205
Examples 206
Core-Spotlight 206
Examples 216
Chapter 52: Create .ipa File to upload on appstore with Applicationloader 222
Examples 222
create .ipa file to upload app to appstore with Application Loader 222
Examples 228
Introduction 229
Examples 229
Examples 232
Examples 235
Intercepting calls from your app even from the background 235
Examples 238
Result 239
Samples 239
UIKit+IBExtensions.h 241
UIKit+IBExtensions.m 241
Examples 245
Introduction 253
Examples 253
Examples 254
Introduction 255
Examples 255
Custom UITextField to Disallow All Actions like Copy, Paste, etc 256
Remarks 257
Examples 257
Examples 280
Introduction 283
Remarks 283
Examples 283
Examples 285
Remarks 290
Examples 290
Introduction 295
Examples 295
Introduction 295
Examples 299
Swift 299
Objective-C 299
Swift 299
Objective-C 299
Swift 300
Swift 301
Examples 302
Connect the UISwitch to an action we can animate switching between a horizontal or vertica 302
Examples 304
Swift 304
Objective-C 304
Swift 304
Objective-C 304
Note 304
Swift 305
Objective-C 305
Swift 305
Swift 306
Swift 306
Swift 306
Objective-C 306
Swift 306
Objective-C 306
Swift 307
Swift 307
Objective-C 307
Chapter 71: Extension for rich Push Notification - iOS 10. 308
Introduction 308
Examples 308
Implementation 308
Examples 311
Examples 314
Examples 319
fastlane tools 319
Remarks 321
Examples 321
Introduction 323
Examples 323
Examples 325
Examples 328
Generation 328
Swift 328
Objective-C 328
Swift 328
Objective-C 328
Note 328
Swift 329
Objective-C 329
Swift 329
GKEntity 330
GKComponent 331
GKComponentSystem 331
Introduction 333
Examples 333
Examples 338
Introduction 341
Examples 341
Examples 346
Syntax 357
Parameters 357
Remarks 357
Examples 358
Swift: 358
Objective-C: 358
Examples 361
HealthKit 361
Parameters 364
Remarks 364
Examples 364
Remarks 366
Examples 366
Examples 368
Examples 373
Examples 376
SRXMPPDemo 376
Download the example and all the classes here - https://github.com/SahebRoy92/SRXMPPDemo 376
Examples 380
Speech to text: Recognize speech from a bundle contained audio recording 380
Examples 382
Introduction 384
Examples 384
Objective C 384
Swift 384
Remarks 386
Examples 386
Syntax 388
Remarks 388
Examples 388
Swift 389
Swift 389
Adding a Password to the Keychain 389
Swift 389
Swift 389
Swift 389
Swift 390
Swift 390
Swift 390
Swift 391
Swift 391
Swift 391
Swift 391
Swift 392
Swift 392
Swift 392
Swift 392
Keychain Add, Update, Remove and Find operations using one file. 392
Swift 395
Swift 395
Swift 396
Swift 396
Swift 396
Examples 397
Introduction 399
Examples 399
Examples 400
Examples 401
Note: This only works for the built-in keyboard provided by iOS 401
SWIFT: 401
OBJECTIVE-C: 401
Notes 407
Examples 413
Examples 415
Swift 2 418
Swift 3 418
Objective-C 418
.satellite 419
Swift 2 419
Swift 3 419
Objective-C 420
.satelliteFlyover 420
Swift 2 421
Swift 3 421
Objective-C 421
.hybrid 421
Swift 2 421
Swift 3 421
Objective-C 421
.hybridFlyover 422
Swift 2 422
Swift 3 422
Objective-C 423
Objective-C 425
Swift 425
Objective-C 426
Swift 426
Adjust the map view's visible rect in order to display all annotations 426
Chapter 101: ModelPresentationStyles 427
Introduction 427
Remarks 427
Examples 427
Remarks 438
Examples 438
Introduction 440
Remarks 440
Examples 440
Introduction 441
Examples 441
Introduction 446
Remarks 446
Examples 447
Dog.swift 447
DoggyView.swift 447
DoggyService.swift 447
DoggyPresenter.swift 448
DoggyListViewController.swift 449
Examples 451
Examples 455
Examples 457
Introduction 458
Remarks 458
Examples 458
Remarks 459
Examples 459
Examples 462
Remarks 464
Examples 464
Swift 464
Objective-C 464
Swift 464
Objective-C 464
To String 465
Swift 465
Objective-C 465
To Array 465
Swift 465
Objective-C 465
Swift 465
Objective-C 465
Swift 466
Objective-C 466
Syntax 467
Remarks 467
Examples 468
Swift 468
Swift 3 469
Objective-C 469
Swift 469
Swift 3 469
Objective-C 469
Swift 470
Objective-C 470
Swift 470
Objective-C 470
Swift 470
Objective-C 471
Swift 3 471
Swift 472
Objective-C 472
Convert NSDate that is composed from hour and minute (only) to a full NSDate 472
Objective-C 473
NSDateFormatter 473
Swift 473
Swift 3 473
Objective-C 473
2. Set the date format in which you want your string 473
Swift 474
Objective-C 474
Swift 474
Swift 3 474
Objective-C 474
Note 474
Checking whether the current date contains the symbol for AM or PM 475
Objective-C 475
Objective-C 475
Reference 476
Objective-C 476
Get Historic Time from NSDate (eg: 5s ago, 2m ago, 3h ago) 476
Objective-C 476
Examples 478
Examples 480
Introduction 482
Parameters 482
Remarks 482
Examples 482
Swift 3 484
Objective-C 484
Swift 3 484
Objective-C 485
Swift 485
Objective-C 485
Objective-C 485
Swift 485
Objective-C 486
Syntax 487
Examples 487
Objective-C 489
Swift 489
Objective-C 489
Swift 489
Objective-C 490
Swift 490
Objective-C 490
Swift 490
Objective-c 491
OR - Condition 491
Parameters 492
Remarks 492
Examples 492
Examples 496
How to get last string component from URL (NSURL) in Swift 496
Examples 497
Remarks 499
Examples 500
Introduction 507
Remarks 507
Examples 507
Remarks 509
Examples 509
Swift 509
Objective-C 510
Note 510
Swift 511
Objective-C 511
Swift 511
Objective-C 511
Swift 3 512
Objective-C 512
Swift 3 512
Objective-C 512
Swift 512
Objective-C 513
Swift 513
Objective-C 513
Swift 514
Objective-C 514
Introduction 516
Syntax 516
Parameters 516
Remarks 516
Examples 516
Introduction 518
Examples 518
Examples 519
Swift 521
Objective-C 522
Swift 522
Objective-C 523
Chapter 127: Passing Data between View Controllers (with MessageBox-Concept) 528
Introduction 528
Examples 528
Examples 529
Examples 533
Example: 533
Introduction 540
Examples 540
Syntax 553
Parameters 553
Examples 553
Swift 553
Objective-C 554
Swift 555
Objective-C 556
Swift 556
Objective-C 556
Swift 557
Objective-C 557
Note 557
Generating a .pem certificate from your .cer file, to pass on to the server developer 559
Objective-C 560
Swift 560
Enabling the APNs access for App ID in Apple Developer Center 560
Enabling the APNs access in Xcode 562
Swift 562
Introduction 566
Examples 566
Step 1 567
Step 2 567
Step 3 568
Remarks 570
Examples 570
Parameters 571
Examples 571
Introduction 572
Examples 572
Examples 581
Examples 583
Introduction 585
Examples 585
Examples 588
An Overview 588
PrepareForSegue: 588
Parameters 588
ShouldPerformSegueWithIdentifier: 589
Parameters 589
PerformSegueWithIdentifier: 590
Parameters 590
Examples 591
Examples 593
Introduction 595
Remarks 595
Examples 596
Lock 596
Rotation 596
Introduction 597
Examples 597
Remarks 598
Examples 598
Note 599
Note 599
Remarks 601
Examples 601
Trait Collections 601
Remarks 604
Examples 604
Examples 609
Examples 611
Introduction 613
Remarks 613
Examples 615
Examples 617
Introduction 618
Examples 618
Initialize 618
Examples 619
Note: 622
Chapter 153: Swift: Changing the rootViewController in AppDelegate to present main or logi 623
Introduction 623
Remarks 623
Approaches: 623
Examples 624
Remarks 626
Examples 626
Syntax 631
Examples 631
UILabel 634
UIStackView 634
UITableView 634
UITableViewCell 634
UICollectionView 634
UITextField 634
UITextView 635
UISwitch 635
Alerts 635
Parameters 637
Examples 637
Objective-C 637
Swift 637
Remarks 638
Examples 638
Swift 640
Objective-C 640
Swift 641
Objective-C 641
Swift 641
Objective-C 641
Swift 642
Objective-C 642
Swift 642
Objective-C 642
Swift 643
Objective-C 643
Swift 643
Swift 646
Swift 647
Swift 648
Swift 649
Notes 649
Examples 650
Parameters 653
Remarks 653
Examples 653
Notes 656
Examples 658
Notes 671
Introduction 674
Remarks 674
Examples 675
Get UIButton's size strictly based on its text and font 679
Swift 679
Objective C 679
Swift 680
Objective C 680
Examples 681
Finished 688
Examples 693
styleString 693
_systemDestructiveTintColor() 693
Swift 694
Swift 3 694
Objective-C 694
The new user defined attribute (borderUIColor) will be recognized and applied without prob 695
Examples 703
Introduction 703
Remarks 707
Examples 707
Swift 707
Objective-C 707
Modes 707
Parameters 709
Remarks 709
Examples 709
Introduction 715
Examples 715
Swift 715
Objective-C 716
Introduction 717
Examples 717
Examples 718
Notes 718
UILongPressGestureRecognizer 718
Notes 719
UISwipeGestureRecognizer 719
Notes 720
UIPinchGestureRecognizer 720
Notes 720
UIRotationGestureRecognizer 721
Notes 721
Notes 723
UIPanGestureRecognizer 723
UITapGestureRecognizer 724
Remarks 726
Examples 726
Swift 728
Objective-C 729
Note 729
Swift 729
Swift 729
Objective-C 729
Objective-C 730
Swift 731
Objective-C 732
Swift 732
Swift 3 732
Objective-C: 733
Introduction 734
Examples 734
Examples 736
Objective-C 738
Swift 738
Redraw 741
Center 741
Top 741
Bottom 742
Left 742
Right 743
Notes 745
Objective-C 746
Swift 3 746
Introduction 747
Remarks 747
Swift 747
Objective-C 747
Examples 748
Swift 749
Objective-C 751
Swift 753
Objective-C 755
Swift 758
Objective-C 759
Swift 759
Objective-C 760
Swift 761
Objective-C 765
Swift 770
Objective-C 771
Swift 772
Objective-C 773
Swift 773
Objective-C 777
Swift 783
Objective-C 783
Swift 783
Objective-C 784
Swift 785
Objective-C 786
Introduction 788
Examples 788
Swift 789
Objective-C 790
Swift 791
Objective-C 792
Swift 792
Objective-C 794
Swift 795
Objective-C 797
Introduction 800
Syntax 800
Remarks 800
Examples 800
Get UILabel's size strictly based on its text and font 801
Objective-C 801
Swift 802
Clickable Label 802
Swift 803
Objective-C 803
Notes 804
Swift 813
Swift 813
LineBreakMode 816
Swift 816
Swift 3 816
Objective-C 816
Constants 817
Swift 822
Objective-C 822
Objective-C 823
Swift 824
Objective-C 825
Swift 825
Objective-C 825
Swift 825
Swift 3 825
Objective-C 825
Swift 825
Swift3 826
Objective-C 826
Swift 826
Swift3 826
Objective-C 826
Swift 826
Swift 3 826
Objective-C 826
Swift 827
Objective-C 827
Swift 827
Swift 3 827
Objective-C 827
Swift 828
Objective-C 828
Note 828
Swift 828
Objective-C 828
Note 828
Note 828
Examples 831
Introduction 832
Remarks 832
Examples 832
Remarks 841
Examples 841
Purpose 843
Introduction 844
Syntax 844
Remarks 844
Examples 844
A simple way to create horizontal page view controllers ( infinite pages ) 846
Chapter 180: UIPheonix - easy, flexible, dynamic & highly scalable UI framework 850
Introduction 850
Remarks 850
Examples 850
Examples 853
Swift 853
Objective-C 853
Introduction 855
Examples 855
Examples 857
Storyboard 858
Finished 861
Objective C: 868
Swift: 869
Examples 870
ScrollableController 872
Examples 877
Syntax 880
Parameters 880
Remarks 881
Examples 881
Implementation 885
Introduction 887
Examples 887
Examples 888
UISlider 888
Remarks 890
Examples 890
Remarks 899
Examples 899
Interacting Between Master and Detail View using Delegates in Objective C 899
Examples 903
Introduction 912
Examples 912
SWIFT: 912
OBJECTIVE-C: 912
Syntax 914
Remarks 914
Examples 914
Examples 917
Objective-C: 918
Swift: 918
Choosing image for tab bar and set the tab title here 921
Introduction 924
Syntax 924
Remarks 926
Examples 926
UITableViewDataSource 926
UITableViewDelegate 929
Connecting the table view's data source to your view controller 938
Swift 939
Objective-C 940
Storyboard 944
Finished 944
Notes 944
Introduction 950
Examples 950
Introduction 952
Examples 952
Introduction 955
Syntax 955
Examples 955
Related 957
Notes 957
Related 958
Swift 3 958
Objective-C 958
Swift 959
Objective-C 959
Swift 959
Objective-C 962
Swift 962
Objective-C 962
Swift 962
Objective-C 963
Swift 963
Objective-C 963
Autocapitalization 964
Swift 964
Objective-C 964
KeyboardType 964
Swift 968
Objective-C 968
Swift 968
Objective-C 968
Examples 973
Examples 976
Related 980
Notes 981
Related 981
Syntax 982
Remarks 982
Examples 982
Programmatically 983
Examples 997
Subclassing 997
Remarks 1002
Examples 1002
Remarks 1007
Examples 1007
Objective-C 1012
Swift : 1013
Introduction 1014
Examples 1014
Notes: 1017
Remarks 1019
Examples 1019
Swift 1019
Objective-C 1019
Swift 1019
Objective-C 1020
Apple's IFA vs. IFV (Apple Identifier for Advertisers vs. Identifier for Vendors) 1020
Introduction 1022
Examples 1022
Introduction 1023
Examples 1023
Send messages from JavaScript and Handle them on the native side 1029
Chapter 209: Xcode Build & Archive From Command Line 1031
Syntax 1031
Parameters 1031
Remarks 1031
Examples 1031
Examples 1033
Swift 1034
Objective-C 1034
Swift 1035
Swift 1035
Objective-C 1036
Swift 1036
Objective-C 1036
Swift 1036
Objective-C 1037
Note 1037
Credits 1040
About
You can share this PDF with anyone you feel could benefit from it, downloaded the latest version
from: ios
It is an unofficial and free iOS ebook created for educational purposes. All the content is extracted
from Stack Overflow Documentation, which is written by many hardworking individuals at Stack
Overflow. It is neither affiliated with Stack Overflow nor official iOS.
The content is released under Creative Commons BY-SA, and the list of contributors to each
chapter are provided in the credits section at the end of this book. Images may be copyright of
their respective owners unless otherwise specified. All trademarks and registered trademarks are
the property of their respective company owners.
Use the content presented in this book at your own risk; it is not guaranteed to be correct nor
accurate, please send your feedback and corrections to [email protected]
http://www.riptutorial.com/ 1
Chapter 1: Getting started with iOS
Remarks
Notes
1- You do not need an Apple Developer Account to start developing iOS Apps. The
documentation and tools are free to download with your Apple ID. You can also sign
and install apps on your personal devices using that same Apple ID. If you want to
distribute or sell apps on the App Store, you need to enroll the Apple Developer
Program starting at 99 USD (This is the price at the time of writing and may change).
This will also add code-level support incidents and beta testing for your apps via
TestFlight.
2- Creating an Apple ID without a credit card requires a short process. If you don't mind
associating a payment method as part of the sign up, go to https://appleid.apple.com/
Versions
iPhone OS 2 2008-07-11
iPhone OS 3 2009-06-17
iOS 4 2010-06-08
iOS 5 2011-10-12
http://www.riptutorial.com/ 2
Version Release Date
iOS 6 2012-09-19
iOS 7 2013-09-18
iOS 8 2014-09-17
iOS 9 2015-09-16
Examples
Creating a default Single View Application
To develop an application for iOS, you should start with an application called Xcode. There are
other alternative tools you can use, but Xcode is Apple's official tool. Note, however, that it only
runs on macOS. The latest official version is Xcode 8.3.3 with Xcode 9 (currently in beta) due to
be released later this year.
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.)
http://www.riptutorial.com/ 3
2. Open Xcode. The following window will open:
http://www.riptutorial.com/ 4
http://www.riptutorial.com/ 5
The window presents you with the following options:
• 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.
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:
http://www.riptutorial.com/ 6
http://www.riptutorial.com/ 7
This wizard is used to select your project template. There are 5 options:
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.
This is a normal application development template. This is good for beginners to learn
application flow.
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.
http://www.riptutorial.com/ 8
http://www.riptutorial.com/ 9
The wizard helps you to define project properties:
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.
http://www.riptutorial.com/ 10
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.
Hello World
After setting up Xcode, it is not difficult to get your first iOS up and running.
In the following example we will:
http://www.riptutorial.com/ 11
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.
http://www.riptutorial.com/ 12
Choose an existing folder or create a new one where you will save your Xcode projects. This will
be the default in the future. We created one here called "Xcode Projects". Then click Create. You
can select Source Control if you like (used when syncing to sites like GitHub), but we won't be
needing it in this example.
http://www.riptutorial.com/ 13
Adding a label
This is the file structure of an Xcode project.
http://www.riptutorial.com/ 14
Type "label" in the search field of the Object Library in the bottom right of Xcode. Then drag the
UILabel onto the storyboard View Controller. Place it generally in the region of the top left corner.
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:
http://www.riptutorial.com/ 15
Adding Code
Select ViewController.swift in the Project Navigator.
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.
http://www.riptutorial.com/ 16
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% / 75% / 50% / 33% / 25% scale respectively..
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.
Xcode Interface
In the Xcode, you have three separate areas of working - Navigators (in red), Debug area(in
green) and Utilities(in blue).
http://www.riptutorial.com/ 17
http://www.riptutorial.com/ 18
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 window.
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:
http://www.riptutorial.com/ 19
• Interface Builder. Graphically create and edit user interface files.
http://www.riptutorial.com/ 20
• Project editor. View and edit how your apps should be built, such as by specifying build
options, target architectures, and app entitlements.
http://www.riptutorial.com/ 21
Configure the editor area for a given task with the editor configuration buttons on the right side of
the toolbar:
• 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.
http://www.riptutorial.com/ 22
Resources and Elements in Utilities Area
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.
http://www.riptutorial.com/ 23
The first panel (highlighted in red) is the Inspector bar, use it to choose the inspector best suited
to your current task. Two inspectors are always visible in the inspector bar (additional inspectors
are available in some editors):
• 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.
http://www.riptutorial.com/ 24
• 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.
Use the Library bar (the second highlighted in red) to access ready-to-use libraries of resources
for your project:
• 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 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.
http://www.riptutorial.com/ 25
Create your first program in Swift 3
Here I am presenting how to create first basic program in Swift 3 language. First you need to have
any basic programming language knowledge or not having then be ready to learn it from
beginning.
Xcode 8.2 has new Swift 3 language features with new iOS 10 compatible APi's.
http://www.riptutorial.com/ 26
Then choose Create new Project and after that you will see next screen
http://www.riptutorial.com/ 27
This is also very important part inside Xcode for selecting our project type. We need to choose our
project according to types of OS. There are five types of options available on the top side:
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:
http://www.riptutorial.com/ 28
Then we need to give Product Name, this will represent your Bundle name and application name.
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:
http://www.riptutorial.com/ 29
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.
http://www.riptutorial.com/ 30
After that your output will be shown on terminal which is on bottom right hand side.
Congratulations, This is your first Hello World program inside Xcode.
http://www.riptutorial.com/ 31
Chapter 2: 3D Touch
Examples
3D Touch with Swift
3D touch has been introduced with iPhone 6s Plus. There are two behaviors added with this new
interface layer: Peek and Pop.
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)
}
datailVC.peekActive = true
previewingContext.sourceRect = cell.frame
// Do the stuff
http://www.riptutorial.com/ 32
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
Objective-C
http://www.riptutorial.com/ 33
//Checking for 3-D Touch availability
if ([self.traitCollection respondsToSelector:@selector(forceTouchCapability)] &&
(self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable))
{
[self registerForPreviewingWithDelegate:self sourceView:self.view];
}
//Peek
- (UIViewController *)previewingContext:(id<UIViewControllerPreviewing>)previewingContext
viewControllerForLocation:(CGPoint)location {
http://www.riptutorial.com/ 34
Chapter 3: Accessibility
Introduction
Accessibility in iOS allows users with hearing disabilities and visual impairments to access iOS
and your application by supporting various features like VoiceOver, Voice Control, White on Black,
Mono Audio, Speech to Text and so on. Providing Accessibility in the iOS app means making the
app usable for everyone.
Examples
Make a View Accessible
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.
Accessibility Frame
The accessibility frame is used by VoiceOver for hit testing touches, drawing the VoiceOver
cursor, and calculating where in the focused element to simulate a tap when the user double-taps
the screen. Note that the frame is in screen coordinates!
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.
Screen Change
VoiceOver works great most of the time, breezily reading aloud screens full of content and
intuitively following the user. Alas, no general solution is perfect. Sometimes only you, the app
developer, know where VoiceOver should be focused for an optimal user experience. Fortunately,
VoiceOver listens to system accessibility notifications for clues about where focus belongs. To
move the VoiceOver cursor manually, post an accessibility screen changed notification:
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, firstElement);
When this notification is posted, a short series of tones notify users of the change. The second
http://www.riptutorial.com/ 35
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.
Layout Change
In many cases, content within a single screen will update with new or different content. For
example, imagine a form that reveals additional options based on the user’s answer to a previous
question. In this case, a “layout change” notification lets you either announce the change or focus
on a new element. This notification accepts the same parameters as the screen change
notification.
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, firstElement);
Announcement
Announcements are useful for alerting users to events that don’t require any interaction, such as
“screen locked” or “finished loading.” Use a more specific announcement to notify users of screen
changes or more minor layout changes.
Ordering Elements
VoiceOver navigates from top-left to bottom-right, irrespective of the view hierarchy. This is usually
how content is arranged in left-to-right languages since sighted individuals tend to scan the screen
in an “F-shaped pattern”. VoiceOver users will expect to navigate the same way as typical users.
Predictability and consistency are very important to accessibility. Please refrain from making
customizations that “improve” on default behavior (eg. ordering the tab bar first in the swipe order).
That said, if you have received feedback that the order of elements in your app is surprising, there
are a couple of ways you can improve the experience.
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.
Accessibility Container
VoiceOver can navigate many apps on iOS because most UIKit classes implement
UIAccessibilityProtocol. Features that don’t represent onscreen elements using UIView, including
http://www.riptutorial.com/ 36
apps that leverage Core Graphics or Metal to perform drawing, must describe these elements for
accessibility. As of iOS 8.0, this can be done by assigning a property on the UIView containing
inaccessible elements:
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 may need
to issue a screen change notification for the elements to be detected by VoiceOver.
Modal View
Modal views completely capture the user’s attention until a task is complete. iOS clarifies this to
users by dimming and disabling all other content when a modal view, such as an alert or popover,
is visible. An app that implements a custom modal interface needs to hint to VoiceOver that this
view deserve the user’s undivided attention by setting accessibilityViewIsModal. Note that this
property should only be set on the view containing modal content, not elements contained within a
modal 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.
Hiding Elements
Most UIKit classes, including UIView, adhere to UIAccessibilityProtocol and return correct values
by default. It’s easy to take for granted that a UIView set to hidden is also absent from the
accessibility hierarchy and won’t be navigated by VoiceOver. While this default behavior is usually
sufficient, there are times where a view will be present in the view hierarchy but not visible or
navigable. For example, a collection of buttons may be overlapped by another view, rendering
them invisible to a sighted user. VoiceOver, however, will still try to navigate them since they are
technically not hidden from UIKit and therefore are still present in the accessibility hierarchy. In
such cases, you must hint to VoiceOver that the parent view isn’t accessible. You can do this by
explicitly hiding the view from UIKit by setting hidden when the view goes offscreen:
myViewFullofButtons.hidden = YES;
Alternatively, you can leave the parent view visible and simply hide its children from the
accessibility hierarchy:
http://www.riptutorial.com/ 37
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.
http://www.riptutorial.com/ 38
Chapter 4: ADDING A SWIFT BRIDGING
HEADER
Examples
How to create a Swift Bridging Header Manually
• Add a new file to Xcode (File > New > File), then select “Source” and click “Header File“.
• 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.
Add a new Swift file to your Xcode project. Name it as you please and you should get an alert box
asking if you would like to create a bridging header. Note: If you don’t receive a prompt to add a
bridging header, you probably declined this message once before and you will have to add the
header manually (see below)
http://www.riptutorial.com/ 39
Read ADDING A SWIFT BRIDGING HEADER online:
http://www.riptutorial.com/ios/topic/10851/adding-a-swift-bridging-header
http://www.riptutorial.com/ 40
Chapter 5: AFNetworking
Examples
Dispatching completion block on a custom thread
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:
http://www.riptutorial.com/ 41
Chapter 6: AirDrop
Examples
AirDrop
Objective-C
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)
http://www.riptutorial.com/ 42
Chapter 7: AirPrint tutorial in iOS
Examples
AirPrint printing Banner Text
Objective-C
#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];
http://www.riptutorial.com/ 43
/* Set this UISimpleTextPrintFormatter on the controller */
controller.printFormatter = _textFormatter;
/* 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(completed && error)
NSLog( @"Printing failed due to error in domain %@ with error code %lu. Localized
description: %@, and failure reason: %@", error.domain, (long)error.code,
error.localizedDescription, error.localizedFailureReason );
};
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;
}
http://www.riptutorial.com/ 44
Chapter 8: Alamofire
Syntax
• response()
• responseData()
• responseString(encoding: NSStringEncoding)
• responseJSON(options: NSJSONReadingOptions)
• responsePropertyList(options: NSPropertyListReadOptions)
Parameters
Parameter Details
Method .OPTIONS, .GET, .HEAD, .POST, .PUT, .PATCH, .DELETE, .TRACE, .CONNECT
URLString URLStringConvertible
encoding ParameterEncoding
Examples
Making a Request
import Alamofire
Alamofire.request(.GET, "https://httpbin.org/get")
Automatic Validation
Alamofire.request("https://httpbin.org/get").validate().responseJSON { response in
switch response.result {
case .success:
print("Validation Successful")
case .failure(let error):
print(error)
}
}
Response Handling
http://www.riptutorial.com/ 45
Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
.responseJSON { response in
print(response.request) // original URL request
print(response.response) // URL response
print(response.data) // server data
print(response.result) // result of response serialization
Manual Validation
Response Handler
Alamofire.request(.GET, "https://httpbin.org/get")
.validate()
.responseString { response in
print("Response String: \(response.result.value)")
}
.responseJSON { response in
print("Response JSON: \(response.result.value)")
}
http://www.riptutorial.com/ 46
Chapter 9: App Submission Process
Introduction
This tutorial covers all the necessary steps required to upload an iOS app to the App Store.
Examples
Setup provisioning profiles
In previous versions, setting up provisioning profiles was done manually. You generate distribution
profile, download it and then distribute your app. This had to be done for every development
machine which was extremely time consuming. However, in most situations nowadays, Xcode 8
will do most of this work for you. Make sure you sign in with the account which will be used for
distributing the app and then simply select "Automatically manage code signing" in Targets ->
General.
Once the provisioning profiles are all set, next step in the process of submitting the app is to
archive your code. From the dropdown of devices and simulators select option "Generic iOS
device". Then, under "Product" menu select option "Archive".
http://www.riptutorial.com/ 47
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.
http://www.riptutorial.com/ 48
Once it's done, you can find your archive in the Xcode organizer. This is where all your previous
versions and archive builds are saved and organized in case you do not delete them. You will
immediately notice a large blue button saying "Upload to App Store..." however in 9/10 cases this
will not work due to various reasons (Xcode bugs mostly). Workaround is to export your archive
and upload it using another Xcode tool called Application Loader. However, since Application
loader uploads IPA files to the App Store, archive needs to be exported to the correct format. This
is a trivial task which might take ~ half an hour. Click on the "Export" button in the right side panel.
If you are uploading app to the App Store, select the first option and click Next. Sign in and
validate your code once again and go grab a cup of coffee. Once the exporting process is done,
you will be asked where to save the generated IPA file. Usually, desktop is the most convenient
choice.
http://www.riptutorial.com/ 49
Upload IPA file using Application Loader
Once the IPA file is generated, open Xcode, navigate to developer tools and open Application
Loader.
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 hour to appear in your build list on iTunes Connect.
http://www.riptutorial.com/ 50
Read App Submission Process online: http://www.riptutorial.com/ios/topic/8765/app-submission-
process
http://www.riptutorial.com/ 51
Chapter 10: App Transport Security (ATS)
Parameters
Parameter Details
http://www.riptutorial.com/ 52
Parameter Details
Similar to NSExceptionAllowsInsecureHTTPLoads,
NSThirdPartyExceptionAllowsInsecureHTTPLoads
but for domains that you have no control over
Similar to NSExceptionRequiresForwardSecrecy,
NSThirdPartyExceptionRequiresForwardSecrecy
but for domains that you have no control over
Remarks
The App Transport Security is a security feature in iOS and macOS. It prevents apps from
establishing unsecured connections. By default, apps can only use secure HTTPS connections.
If an app needs to connect to a server via HTTP, exceptions must be defined in the Info.plist.
(see the examples for more information about that)
Note: In 2017, Apple will enforce ATS. That means, that you can no longer upload apps that have
ATS-exceptions defined in the Info.plist. If you can provide good arguments, why you have to
use HTTP, you can contact Apple and they might allow you to define exceptions. (Source: WWDC
2016 - Session 706)
More information on the App Transport Security configuration can be found in the CocoaKeys
Documentation.
Examples
Endpoints require SSL
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>testdomain.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
http://www.riptutorial.com/ 53
<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.
Apple introduced ATS with iOS 9 as a new security feature to improve privacy and security
between apps and web services. ATS by default fails all non HTTPS requests. While this can be
really nice for production environments, it can be a nuisance during testing.
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.
Similar to enabling all HTTP content, all configuration happens under the App Transport Security
Settings. Add the Exception Domains dictionary (NSExceptionDomains) to the top level ATS settings.
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.
http://www.riptutorial.com/ 54
Read App Transport Security (ATS) online: http://www.riptutorial.com/ios/topic/5435/app-transport-
security--ats-
http://www.riptutorial.com/ 55
Chapter 11: App wide operations
Examples
Get the top most UIViewController
A common approach to get the top most UIViewController is to get the RootViewController of your
active UIWindow. I wrote an extension for this:
extension UIApplication {
return base!
}
Using the NotificationCenter of iOS, which can be very powerful, you are able to intercept certain
app-wide events:
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.
http://www.riptutorial.com/ 56
Chapter 12: AppDelegate
Introduction
AppDelegate is a protocol which defines methods that are called by the singleton UIApplication
object in response to important events in the lifetime of an app.
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.
Examples
All States of Application through AppDelegate methods
For Getting updated or to do something before app goes live to user you can use below method.
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.
}
http://www.riptutorial.com/ 57
While app resign active
- (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:.
}
AppDelegate Roles:
Asks the delegate to open a resource specified by a URL, and provides a dictionary of launch
options.
Example of usage:
http://www.riptutorial.com/ 58
Example of usage:
Registration:
http://www.riptutorial.com/ 59
Read AppDelegate online: http://www.riptutorial.com/ios/topic/8740/appdelegate
http://www.riptutorial.com/ 60
Chapter 13: Application rating/review request
Introduction
Now from iOS 10.3 , there is no need to navigate application to apple store for rating/review. Apple
has introduced SKStoreReviewController class in storekit framework. In which developer just need
to call requestReview() class method of SKStoreReviewController class and the system handles
the entire process for you.
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
Examples
Rate/Review iOS Application
Just type below one line code from where you want user to rate/review your application.
SKStoreReviewController.requestReview()
http://www.riptutorial.com/ 61
Chapter 14: ARC (Automatic Reference
Counting)
Examples
Enable/Disable ARC on a file
ARC can be disabled for individual files by adding the -fno-objc-arc compiler flag for each file.
Conversely it can be added in Targets ▸ Build Phases ▸ Compile Sources
http://www.riptutorial.com/ 62
automatic-reference-counting-
http://www.riptutorial.com/ 63
Chapter 15: attributedText in UILabel
Introduction
The current styled text that is displayed by the label.
You can add HTML text in UILabel using attributedText property or customized single UILabel text
with different property
Examples
HTML text in UILabel
NSString * htmlString = @"<html><body> <b> Example bold text in HTML </b> </body></html>";
NSAttributedString * attrStr = [[NSAttributedString alloc] initWithData:[htmlString
dataUsingEncoding:NSUnicodeStringEncoding] options:@{ NSDocumentTypeDocumentAttribute:
NSHTMLTextDocumentType } documentAttributes:nil error:nil];
The first step you need to preform is to create a NSMutableAttributedString object. The reason we
create a NSMutableAttributedString instead of NSAttributedString is because it enables us to
append string to it.
http://www.riptutorial.com/ 64
blue:(197.0/255.0) alpha:1]
range: rangeWorld];
Output :
http://www.riptutorial.com/ 65
Chapter 16: Auto Layout
Introduction
Auto Layout dynamically calculates the size and position of all the views in your view hierarchy,
based on constraints placed on those views. Source
Syntax
• NSLayoutConstraint(item: Any, attribute: NSLayoutAttribute, relatedBy: NSLayoutRelation,
toItem: Any?, attribute: NSLayoutAttribute, multiplier: CGFloat, constant: CGFloat) // Create
a contraint programmatically
Examples
UILabel & Parentview size According to Text in UILabel
http://www.riptutorial.com/ 66
Step 2 :- Set constrain to Label 1
http://www.riptutorial.com/ 67
Step 3 :- Set constraint to Label 2
http://www.riptutorial.com/ 68
Step 4 :- Most tricky give a bottom to UILabel from UIView .
http://www.riptutorial.com/ 69
Step 5 :- (Optional) Set constrain to UIButton
http://www.riptutorial.com/ 70
Output :-
http://www.riptutorial.com/ 71
Note :- Make sure you have set Number of lines =0 in Label property.
http://www.riptutorial.com/ 72
I hope this info enough to understand Autoresize UIView according to UILabel's height and
Autoresize UILabel According to text.
HVFL is a language designed to constrain UI elements in a simple and quick fashion. Generally,
VFL has an advantage over traditional UI customization in the Interface Builder because it's much
more readable, accessible and compact.
Here's an example of VFL, in which three UIViews are constrained from left to right, filling up
superView.width, with aGradeView
"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?
http://www.riptutorial.com/ 73
I'll cover that at the end of the post.
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];
// 2. forbid Autoresizing
blueView.translatesAutoresizingMaskIntoConstraints = NO;
redView.translatesAutoresizingMaskIntoConstraints = NO;
// 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];
http://www.riptutorial.com/ 74
NSLayoutConstraint *redW = [NSLayoutConstraint constraintWithItem:redView
attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:blueView
attribute:NSLayoutAttributeWidth multiplier:0.5 constant:0];
[self.view addConstraint:redW];
When we are working on a framework, if the constraints are not too complex, we'd better use
Interface Builder or NSLayoutConstraint in code to make it smaller enough, instead of import
Masonry or SnapKit.
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];
http://www.riptutorial.com/ 75
attribute:NSLayoutAttributeRight multiplier:1 constant:-20];
[self.view addConstraint:blueRight];
// 3.2 redView
NSLayoutConstraint *redTop = [NSLayoutConstraint constraintWithItem:redView
attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:blueView
attribute:NSLayoutAttributeBottom multiplier:1 constant:20];
[self.view addConstraint:redTop];
Proportional Layout
Constraint created as
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
http://www.riptutorial.com/ 76
http://www.riptutorial.com/ 77
calculations done by UIKit itself.
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;
}
Problem: When you use many labels inside a view, you maybe get a warning:
http://www.riptutorial.com/ 78
How can we fix this warning?
Solution: We calculate and set the priorities in order. The priorities must be different from labels. It
means which is important will get higher priority. For example, in my case, I set the vertical
priorities for my labels look like this:
I set the highest priority for 1st label and the lowest for 4th label.
http://www.riptutorial.com/ 79
http://www.riptutorial.com/ 80
In a ViewController, I think you're hard to see the effect of those priorities. However, it's very
clearly with UITableViewCell + estimate cell height.
Without Auto Layout, animation is accomplished changing a view's frame over time. With Auto
Layout, the constraints dictate the view frame, so you have to animate the constraints instead.
This indirection makes animation harder to visualize.
http://www.riptutorial.com/ 81
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.
10. Opt out from Auto Layout and set views manually. You can do this overriding
layoutSubviews/layout without calling the super class’s implementation.
http://www.riptutorial.com/ 82
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.
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
http://www.riptutorial.com/ 83
Width and Height
Anchor Style
NSLayoutConstraint 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])
http://www.riptutorial.com/ 84
How to use Auto Layout
Auto layout is used to arrange views so that they look good on any device and orientation.
Constraints are the rules that tell how everything should be laid down. They include pinning edges,
centering, and setting sizes, among other things.
Auto layout is enabled by default, but you can double check this. If you click Main.storyboard in the
Project Navigator and then show the File inspector. Make sure that Auto Layout and Size Classes
are checked:
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.
Center Constraints
Select your button (or whatever view you want to center) on the storyboard. Then click the align
button on the bottom right. Select Horizontally in Container and Vertically in Container. Click
"Add 2 Constraints".
http://www.riptutorial.com/ 85
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.
http://www.riptutorial.com/ 86
You can also "update frames as necessary" by pressing together + + = (Command + Option
and equals) after selecting the view, this might save some time.
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
http://www.riptutorial.com/ 87
{
[super viewDidLoad];
UIButton *yourButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 100, 18)];
[yourButton setTitle:@"Button" forState:UIControlStateNormal];
Swift
We have to create a view which will have a image prefix to a text. text could be of variable
length.We have to achieve a result where in Image + text is always in center of a parent view.
http://www.riptutorial.com/ 88
Step 1: First create a single view project and name it something of your choice and open the story
board fist view.Drag a view with some reasonable size and set its background color to yellow.I
have resized my viewcontroller to 3.5″.The resultant view should look some thing like this
http://www.riptutorial.com/ 89
Step 2: Now we will add constraints to the yellow view .To begin with we will add width and height
constraints (Wait a minute didn’t we say that view will have dynamic width?Ok we will get back to it
later) Add the following constraints as per the image below do not bother with width value any
value will do just fine for width just keep it large enough so that we can add autolayouts properly.
http://www.riptutorial.com/ 90
After adding these two constraints you will see that XCode is giving you errors as in below image
lets see them and understand them.
http://www.riptutorial.com/ 91
We have two errors (red means error)As discussed above lets revisit the ambiguity part
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
http://www.riptutorial.com/ 92
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
http://www.riptutorial.com/ 93
What we have done is,We have added a “Vertical Center” and “Horizontal Center” these constrain
tell autolayout that our yellow view will always be in center Horizontally: so X in determined same
is with vertical constraint and Y is determined.(you might have to adjust frame).
Step 3: By now our base yellow view is ready. We will add the prefix image as subview of our
http://www.riptutorial.com/ 94
yellow view with following constraints.You can choose any image of your choice.
Since we have fixed dimension for our prefix image we will have fixed width height for this
imageview. Add the constraints and proceed to next step.
Step4: Add a UILabel as the sub view of our yellow view and add following constraints
http://www.riptutorial.com/ 95
As you can see i have given only relative constraints to our UILabel.Its 8 points from prefix image
and 0,0,0 top trailing and bottom from yellow view.Since we want the width to be dynamic we will
not give width or height 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
http://www.riptutorial.com/ 96
to Size inspector and reduce the priority of width constraint to 1 so that it will be over ruled. Follow
the image given below.
Step 6: We want out UILabel to expand according to text and push our yellow view.So we have
reduced the priority of yellow view width.Now we will increase the priority of text compression
resistance of our UILabel.We want our view to reduce as well so we will increase the priority of
content hugging of UILabel.Follow the image below
http://www.riptutorial.com/ 97
As you can see we have increased content hugging priority to 500 and compression resistance
priority to 751 which will successfully over rule the width constraint’s 1 priority.
Now build and run you will see some thing as following.
http://www.riptutorial.com/ 98
Space Views Evenly
http://www.riptutorial.com/ 99
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
Anchor Style
http://www.riptutorial.com/ 100
view.addLayoutGuide(leadingSpace)
view.addLayoutGuide(trailingSpace)
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.
http://www.riptutorial.com/ 101
Chapter 17: AVPlayer and
AVPlayerViewController
Remarks
import AVKit, import AVFoundation.
Examples
Playing Media Using AVPlayerViewController
Objective-C
NSURL *url = [[NSURL alloc] initWithString:@"YOUR URL"]; // url can be remote or local
Swift
playerViewController.player!.play()
}
Objective C
http://www.riptutorial.com/ 102
Swift
AVPlayer Example
http://www.riptutorial.com/ 103
Chapter 18: AVSpeechSynthesizer
Syntax
• AVSpeechSynthesizer() // Creates a speech synthesiser
• speaker.speakUtterance(speech) // Converts the text to speech
Parameters
Parameter Details
Examples
Creating a basic text to speech
Use the speakUtterance: method of AVSpeechSynthesizer to convert text to speech. You need to pass
an AVSpeechUtterance object to this method, which contains the text that you want to be spoken.
Objective C
Swift
http://www.riptutorial.com/ 104
Chapter 19: AWS SDK
Examples
Upload an image or a video to S3 using AWS SDK
Before starting with the example I'd recommend to create a Singleton with a delegate class
member so you could achieve a use case of uploading a file in the background and let the user
keep using your app while the files are being uploaded even when the app is the background.
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
http://www.riptutorial.com/ 105
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....
let image = UIImage()
let fileURL = NSURL(fileURLWithPath:
NSTemporaryDirectory()).URLByAppendingPathComponent(fileName)
let filePath = fileURL.path!
let imageData = UIImageJPEGRepresentation(image, 1.0)
imageData!.writeToFile(filePath, atomically: true)
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:
http://www.riptutorial.com/ 106
resultBlock : (NSError?) -> Void)
{
// Actual implementation .....
// ...
// ...
}
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 :)
http://www.riptutorial.com/ 107
Chapter 20: Background Modes
Introduction
Being responsive is a need for every app. Users want to have apps which have their content ready
when they open it, so developers should use Background Modes to make their apps more user
friendly.
Examples
Turning on the Background Modes capability
http://www.riptutorial.com/ 108
Background Fetch
Background fetch is a new mode that lets your app appear always up-to-date with the latest
information while minimizing the impact on battery. You could download feeds within fixed time
intervals with this capability.
To get started:
Swift
UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplicationBackgroundFetchIntervalMinimum)
http://www.riptutorial.com/ 109
Objective-C
[[UIApplication shared]
setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum]
Swift
func application(_ application: UIApplication, performFetchWithCompletionHandler
completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
// your code here
}
http://www.riptutorial.com/ 110
http://www.riptutorial.com/ 111
Chapter 21: Background Modes and Events
Examples
Play Audio in Background
Add a key named Required background modes in property list (.plist) file ..
as following picture..
AppDelegate.h
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
AppDelegate.m
in application didFinishLaunchingWithOptions
http://www.riptutorial.com/ 112
UInt32 size = sizeof(CFStringRef);
CFStringRef route;
AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &size, &route);
NSLog(@"route = %@", route);
If you want changes as per events you have to add following code in AppDelegate.m
- (void)remoteControlReceivedWithEvent:(UIEvent *)theEvent {
if (theEvent.type == UIEventTypeRemoteControl) {
switch(theEvent.subtype) {
case UIEventSubtypeRemoteControlPlay:
[[NSNotificationCenter defaultCenter] postNotificationName:@"TogglePlayPause"
object:nil];
break;
case UIEventSubtypeRemoteControlPause:
[[NSNotificationCenter defaultCenter] postNotificationName:@"TogglePlayPause"
object:nil];
break;
case UIEventSubtypeRemoteControlStop:
break;
case UIEventSubtypeRemoteControlTogglePlayPause:
[[NSNotificationCenter defaultCenter] postNotificationName:@"TogglePlayPause"
object:nil];
break;
default:
return;
}
}
}
http://www.riptutorial.com/ 113
Chapter 22: Basic text file I/O
Examples
Read and write from Documents folder
Swift 3
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)")
http://www.riptutorial.com/ 114
} catch let error as NSError {
print("Failed writing to URL: \(fileURL), Error:\(error.localizedDescription)")
}
// 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)")
http://www.riptutorial.com/ 115
Chapter 23: Block
Syntax
• As a variable:
• As a property:
• As a method parameter:
- (void)methodWithBlock:(returnType (^)(parameterTypes))blockName;
• As a typedef:
Examples
UIView Animations
[UIView animateWithDuration:1.0
animations:^{
someView.alpha = 0;
otherView.alpha = 1;
}
completion:^(BOOL finished) {
[someView removeFromSuperview];
}];
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.
Block will capture variables that appeared in the same lexical scope. Normally these variables are
captured as "const" value:
http://www.riptutorial.com/ 116
int val = 10;
void (^blk)(void) = ^{
val = 20; // Error! val is a constant value and cannot be modified!
};
In order to modify the variable, you need to use the __block storage type modifier.
typedef void(^myCustomCompletion)(BOOL);
2- Create custom method which takes your custom completion block as a parameter.
http://www.riptutorial.com/ 117
Chapter 24: CAAnimation
Remarks
CAAnimation is an abstract animation class. It provides the basic support for the CAMediaTiming
and CAAction protocols. To animate Core Animation layers or Scene Kit objects, create instances
of the concrete subclasses CABasicAnimation, CAKeyframeAnimation, CAAnimationGroup,
or CATransition.
Examples
Animate a view from one position to another.
Objective-C
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position.x"];
animation.fromValue = @0;
animation.toValue = @320;
animation.duration = 1;
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"
OBJECTIVE-C
http://www.riptutorial.com/ 118
transition.subtype = @"fromLeft";
transition.duration = 0.8;
transition.repeatCount = 5;
[_label.layer addAnimation:transition forKey:@"transition"];
SWIFT
Revolve View
Shake View
Objective-C
Swift 3
http://www.riptutorial.com/ 119
Push View Animation
Objective C
Swift
http://www.riptutorial.com/ 120
Chapter 25: Cache online images
Introduction
Examples
AlamofireImage
Caching Online Images Using AlamofireImage. It works on top of Alamofire in Swift. Install
AlamofireImage using cocoapods
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])
}
}
http://www.riptutorial.com/ 121
Chapter 26: CAGradientLayer
Syntax
• CAGradientLayer() // Returns an initialized CALayer object.
• CAGradientLayer(layer: layer) // Override to copy or initialize custom fields of the specified
layer.
Parameters
Parameter Details
An optional array of NSNumber objects defining the location of each gradient stop.
locations
Animatable.
The end point of the gradient when drawn in the layer’s coordinate space.
endPoint
Animatable.
The start point of the gradient when drawn in the layer’s coordinate space.
startPoint
Animatable.
Remarks
• Use startPoint and endPoint to change the orientation of the CAGradientLayer.
• Use the locations to affect the spread/positions of the colors.
Examples
Animating a color change in CAGradientLayer.
http://www.riptutorial.com/ 122
// Set current color value.
animation.fromValue = oldColors
// 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 :
http://www.riptutorial.com/ 123
Creating a CAGradientLayer
http://www.riptutorial.com/ 124
// Initialize gradient layer.
let gradientLayer: CAGradientLayer = CAGradientLayer()
// Set colors.
gradientLayer.colors = [topColor, bottomColor]
Result :
http://www.riptutorial.com/ 125
let middleColor: CGColor = UIColor.yellow.cgColor
// Set colors.
gradientLayer.colors = [topColor, middleColor, bottomColor]
Result :
// Set colors.
gradientLayer.colors = [topColor, bottomColor]
http://www.riptutorial.com/ 126
// Set end point.
gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
Result :
// Set colors.
gradientLayer.colors = [topColor, middleColor, bottomColor]
http://www.riptutorial.com/ 127
Result :
http://www.riptutorial.com/ 128
Chapter 27: CALayer
Examples
Shadows
self.layer.shadowOpacity = 0.2;
• shadowRadius - this is the blur radius (equivalent of the blur property in Sketch or Photoshop)
self.layer.shadowRadius = 6;
• 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
Rounded corners
layer.masksToBounds = true;
layer.cornerRadius = 8;
http://www.riptutorial.com/ 129
Creating particles with CAEmitterLayer
The CAEmitterLayer class provides a particle emitter system for Core Animation. The particles
are defined by instances of CAEmitterCell.
The particles are drawn above the layer’s background color and border.
emitter.emitterCells = cells
layer.addSublayer(emitter)
For example we will create view that contains emitter layer and animates particles.
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()
http://www.riptutorial.com/ 130
emitter.emitterPosition = CGPoint(x: frame.size.width / 2.0, y: -20)
emitter.emitterShape = kCAEmitterLayerLine
emitter.emitterSize = CGSize(width: frame.size.width, height: 1)
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
}
You can add an image to a view's layer simply by using its contents property:
If you wish to add the image in its own layer, you can do it like this:
http://www.riptutorial.com/ 131
let myLayer = CALayer()
let myImage = UIImage(named: "star")?.CGImage
myLayer.frame = myView.bounds
myLayer.contents = myImage
myView.layer.addSublayer(myLayer)
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
http://www.riptutorial.com/ 132
kCAGravityResizeAspect
kCAGravityResizeAspectFill
kCAGravityCenter
kCAGravityTop
kCAGravityBottom
http://www.riptutorial.com/ 133
kCAGravityLeft
kCAGravityRight
kCAGravityTopLeft
kCAGravityTopRight
http://www.riptutorial.com/ 134
kCAGravityBottomLeft
kCAGravityBottomRight
Related
• Content mode property of a view
• Drawing a UIImage in drawRect with CGContextDrawImage
• CALayer Tutorial: Getting Started
Notes
• This example comes originally from this Stack Overflow answer.
Basics
http://www.riptutorial.com/ 135
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: CATransform3DMake
Translation. 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
http://www.riptutorial.com/ 136
// do the transform
transformExample()
}
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
The translation transform moves the layer. The basic syntax is
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
http://www.riptutorial.com/ 137
• 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.
Scale
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
http://www.riptutorial.com/ 138
CATransform3DMakeRotation(angle: CGFloat, x: CGFloat, y: CGFloat, z: CGFloat)
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
In order to combine multiple transforms we could use concatination like this
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
http://www.riptutorial.com/ 139
This time we combine all three of the previous transforms.
// translate
var transform = CATransform3DMakeTranslation(90, 50, 0)
// rotate
transform = CATransform3DRotate(transform, radians, 0.0, 0.0, 1.0)
// scale
transform = CATransform3DScale(transform, 0.5, 3.0, 1.0)
Notes
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.
http://www.riptutorial.com/ 140
• About the anchorPoint
• Translate rotate translate?
See also
• Border, rounded corners, and shadow on a CALayer
• Using a border with a Bezier path for a layer
Disable Animations
CALayer property animations are enabled by default. When this is undesirable, they can be disabled
as follows.
Swift
CATransaction.begin()
CATransaction.setDisableActions(true)
CATransaction.commit()
Objective-C
[CATransaction begin];
[CATransaction setDisableActions:YES];
[CATransaction commit];
Creating a CALayer
You can create a CALayer and set its frame like this:
Swift:
Objective-C:
http://www.riptutorial.com/ 141
Swift:
existingLayer.addSublayer(layer)
Objective-C:
[existingLayer addSublayer:layer];
Note:
Swift:
@import QuartzCore
Objective-C
#import <QuartzCore/QuartzCore.h>
http://www.riptutorial.com/ 142
Chapter 28: Carthage iOS Setup
Examples
Carthage Installation Mac
Carthage Setup
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
http://www.riptutorial.com/ 143
Chapter 29: CAShapeLayer
Syntax
1. shapeLayer.fillColor
2. shapeLayer.fillRule
3. shapeLayer.lineCap
4. shapeLayer.lineDashPattern
5. shapeLayer.lineDashPhase
6. shapeLayer.lineJoin
Remarks
The CAShapeLayer class draws a cubic Bezier spline in its coordinate space. The shape is
composited between the layer's contents and its first sublayer.
Examples
Basic CAShapeLayer Operation
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];
http://www.riptutorial.com/ 144
Type 2:
Other Operation
//Subpaths
//UIBezierPath can have any number of “path segments” (or subpaths) so you can effectively
draw as many shapes or lines as you want in a single path object
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.
http://www.riptutorial.com/ 145
[linePath addLineToPoint:CGPointMake(120 , 0)];
shapeLayer.path = linePath.CGPath;
[[self.view layer] addSublayer:shapeLayer];
//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);
http://www.riptutorial.com/ 146
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.
http://www.riptutorial.com/ 147
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.
Draw Rectangle
CGPathCloseSubpath(path);
mask.path = path;
CGPathRelease(path);
self.view.layer.mask = mask;
http://www.riptutorial.com/ 148
Draw Circle
CAShapeLayer Animation
http://www.riptutorial.com/ 149
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
pathAnimation.duration = 1.5f;
pathAnimation.repeatCount = 10;
pathAnimation.autoreverses = YES;
[circle addAnimation:pathAnimation
forKey:@"strokeEnd"];
http://www.riptutorial.com/ 150
Chapter 30: Categories
Remarks
Categories can be used to override methods of a class. Even if the method is actually private. The
overridden method cannot be accessed from the category or anywhere else. So it's important to
make sure when adding methods to an existing class, that those methods don't exist already.
Examples
Create a Category
Categories provide the ability to add some extra functionality to an object without subclassing or
changing the actual object.
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."
http://www.riptutorial.com/ 151
Declare the Category Method :-
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{
http://www.riptutorial.com/ 152
#import "UIFont+CustomFonts.h"
http://www.riptutorial.com/ 153
Chapter 31: CGContext Reference
Remarks
The CGContextRef opaque type represents a Quartz 2D drawing destination. A graphics context
contains drawing parameters and all device-specific information needed to render the paint on a
page to the destination, whether the destination is a window in an application, a bitmap image, a
PDF document, or a printer.
Examples
Draw line
CGContextSetLineWidth(context, 5.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGContextMoveToPoint(context, 200, 400);
CGContextAddLineToPoint(context, 100, 100);
CGContextStrokePath(context);
CGColorSpaceRelease(colorspace);
Draw Text
http://www.riptutorial.com/ 154
CGPathRelease(framePath);
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextSetTextMatrix(currentContext, CGAffineTransformIdentity);
CGContextTranslateCTM(currentContext, 200, 300);
CGContextScaleCTM(currentContext, 2, -2);
CTFrameDraw(frameRef, currentContext);
CFRelease(frameRef);
CFRelease(stringRef);
CFRelease(framesetter);
http://www.riptutorial.com/ 155
Chapter 32: Chain Blocks in a Queue (with
MKBlockQueue)
Introduction
MKBlockQueue allows you to create a chain of blocks and execute them one after the other in a
queue. Compared with NSOperation, with MKBlockQueue you decide yourself when a block is
complete and when you want the queue to continue. You can also pass data from one block to the
next.
https://github.com/MKGitHub/MKBlockQueue
Examples
Example Code
// 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
http://www.riptutorial.com/ 156
// test calling on main thread, async, with delay
DispatchQueue.main.asyncAfter(deadline:(.now() + .seconds(1)), execute:
{
print("Block 2 started with dictionary: \(copyOfDictionary)")
copyOfDictionary["Block2Key"] = "Block2Value"
// block 3
let b3:MKBlockQueueBlockType =
{
(blockQueueObserver:MKBlockQueueObserver, dictionary:inout Dictionary<String, Any>) in
copyOfDictionary["Block3Key"] = "Block3Value"
// run queue
print("Queue starting with dictionary: \(myDictionary)")
myBlockQueue.run(with:&myDictionary)
http://www.riptutorial.com/ 157
Chapter 33: Change Status Bar Color
Examples
Changing the status bar style for the entire application
SWIFT:
Step 1:
In your Info.plist add the following attribute:
NO
Step 2:
In your AppDelegate.swift file, in didFinishLaunchingWithOptions method, add this code:
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.
http://www.riptutorial.com/ 158
• 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
In Objective-C:
- (UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
In Swift:
In Objective-C:
- (UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
In Swift:
http://www.riptutorial.com/ 159
return .lightContent
}
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.
If you are using UIViewControllerContainment there are a few other methods that are worth looking
at.
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()
}
}
http://www.riptutorial.com/ 160
If you cannot change ViewController's code
If you are using library that contains (for example) AwesomeViewController with a wrong status
bar color you can try this:
http://www.riptutorial.com/ 161
Chapter 34: Checking for Network
Connectivity
Remarks
The source code for Reachability.h and Reachability.m can be found on Apple's developer
documentation site.
Caveats
Unlike other platforms, Apple is yet to provide a standard set of APIs to determine an iOS device's
network status and offer only these code examples linked above. The source file change over
time, but once imported into an app project, they are seldom updated by the developers.
For this reason most app developers tend to use one of the many Github/Cocoapod maintained
libraries for reachability.
Apple also recommends, for requests made at the user’s behest, that you always attempt a
connection first, before using Reachability/SCNetworkReachability to diagnose the failure or to
wait for the connection to return.
Examples
Creating a Reachability listener
Apple's Reachability class periodically checks the network status and alerts observers to changes.
uses NSNotification messages to alert observers when the network state has
Reachability
changed. Your class will need to become an observer.
http://www.riptutorial.com/ 162
Alert when network becomes unavailable
- (void)reachabilityChanged:(NSNotification *)note {
Reachability* reachability = [note object];
NetworkStatus netStatus = [reachability currentReachabilityStatus];
if (netStatus == NotReachable) {
NSLog(@"Network unavailable");
}
}
- (void)reachabilityChanged:(NSNotification *)note {
Reachability* reachability = [note object];
NetworkStatus netStatus = [reachability currentReachabilityStatus];
switch (netStatus) {
case NotReachable:
NSLog(@"Network unavailable");
break;
case ReachableViaWWAN:
NSLog(@"Network is cellular");
break;
case ReachableViaWiFi:
NSLog(@"Network is WIFI");
break;
}
}
Swift
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)
http://www.riptutorial.com/ 163
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;
}
}
http://www.riptutorial.com/ 164
Chapter 35: Checking iOS version
Examples
iOS 8 and later
Swift 3:
Compare versions
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;
}
if #available(iOS 9, *) {
http://www.riptutorial.com/ 165
// iOS 9
} else {
// iOS 8 or earlier
}
Objective-C
NSString *version = [[UIDevice currentDevice] systemVersion]
Swift
let version = UIDevice.currentDevice().systemVersion
Swift 3
let version = UIDevice.current.systemVersion
http://www.riptutorial.com/ 166
Chapter 36: CLLocation
Examples
Get User Location Using CLLocationManager
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
http://www.riptutorial.com/ 167
//let kCLLocationAccuracyBest: CLLocationAccuracy
//let kCLLocationAccuracyNearestTenMeters: CLLocationAccuracy
//let kCLLocationAccuracyHundredMeters: CLLocationAccuracy
//let kCLLocationAccuracyKilometer: CLLocationAccuracy
//let kCLLocationAccuracyThreeKilometers: CLLocationAccuracy
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.
Example :
E.g. In the above example code above, location changes of less than 5 metres won’t be sent to
http://www.riptutorial.com/ 168
the callback, but instead be ignored.
http://www.riptutorial.com/ 169
Chapter 37: CloudKit
Remarks
Supported Types
• NSData
• NSDate (Date)
• NSNumber (Int / Double)
• NSString (String)
• NSArray (Array)
• CLLocation
• CKReference
• CKAsset
More Details
CloudKit Dashboard
Examples
Registering app for use with CloudKit
What you need is to get an entitlements file so the app can access your iCloud and write records
using CloudKit.
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".
http://www.riptutorial.com/ 170
4- Make sure these items are checked:
If all of the items are checked, then your app is ready to use CloudKit.
All the records create using CloudKit-related code can be previewed, edited and even removed in
CloudKit Dashboard. To access CloudKit Dashboard, go here.
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 can handle it way better than the dashboard, but the functionality is also there if
you prefer. The most use of this page is for previewing types.
Swift
http://www.riptutorial.com/ 171
let timestamp = String(format: "%f", NSDate.timeIntervalSinceReferenceDate())
let timestampParts = timestamp.componentsSeparatedByString(".")
let recordID = CKRecordID(recordName: timestampParts[0])
Swift
Objective-C
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.
http://www.riptutorial.com/ 172
database.saveRecord(record, completionHandler: { (_, error) -> Void in
print(error ?? "")
})
http://www.riptutorial.com/ 173
Chapter 38: Codable
Introduction
Codable is added with Xcode 9, iOS 11 and Swift 4. Codable is used to make your data types
encodable and decodable for compatibility with external representations such as JSON.
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.
Examples
Use of Codable with JSONEncoder and JSONDecoder in Swift 4
Let’s Take an Example with Structure of Movie, here we have defined the structure as Codable.
So, We can encode and decode it easily.
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 {
}
http://www.riptutorial.com/ 174
JSONEncoder will give us the JSON data which is used to retrieve JSON string.
{
"name": "Up",
"moviesGenere": [
"comedy",
"adventure",
"animation"
],
"rating": 4
}
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
http://www.riptutorial.com/ 175
Chapter 39: Code signing
Examples
Provisioning Profiles
In order to build an IPA file in XCode, you require to sign your application with a certificate and
provisioning profile. These can be created at
https://developer.apple.com/account/ios/profile/create
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).
http://www.riptutorial.com/ 176
Chapter 40: Concurrency
Introduction
Related topic: Grand Central Dispatch
Syntax
• dispatch_async - Runs a block of code in a separate queue, and doesn't stop the current
queue. If the queue is on a different thread than the one dispatch_async was called on, the
code in the block will run while code after the dispatch_async also runs
• dispatch_sync - Runs a block of code in a separate queue, and does stop the current queue.
If the queue is on a different thread than the one dispatch_async was called on, the code in
the block will run, and execution on the thread where the method was called will only resume
after it finishes
Parameters
The queue that the code in the dispatch block will run in. A queue is like (but
not exactly the same as) a thread; code in different queues can run in parallel.
Use dispatch_get_main_queue to get the queue for the main thread To create a
new queue, which in turn creates a new thread, use
dispatch_queue_create("QUEUE_NAME", DISPATCH_QUEUE_CONCURRENT). The first
parameter is the name of the queue, which is displayed in the debugger if you
queue
pause while the block is still running. The second parameter doesn't matter
unless you want to use the same queue for multiple dispatch_async or
dispatch_sync calls. It describes what happens when another block is put on the
same queue; DISPATCH_QUEUE_CONCURRENT will cause both blocks to run at the same
time, while DISPATCH_QUEUE_SERIAL will make the second block wait for the first
block to finish
Code in this block will run in the queue queue; put code you want to run on the
separate queue here. A helpful tip: If you're writing this in Xcode and the block
block argument has the blue outline around it, double click on the argument and Xcode will
automatically make an empty block (this applies to all block arguments in any
function or method)
Remarks
Whenever you do something on a separate thread, which happens when using queues, it's
important to maintain thread safety. Some methods, in particular ones for UIViews, may not work
and/or crash on threads other than main thread. Also, make sure not to change anything
(variables, properties, etc.) that is also being used on the main thread, unless you are accounting
http://www.riptutorial.com/ 177
for this change
Examples
Executing on the main thread
When performing tasks asynchronously there typically becomes a need to ensure a piece of code
is run on the main thread. For example you may want to hit a REST API asynchronously, but put
the result in a UILabel on the screen. Before updating the UILabel you must ensure that your code
is run on the main thread:
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.
Say you want to perform in action (in this case, logging "Foo"), while doing something else
(logging "Bar"). Normally, if you don't use concurrency, one of these actions is going to be fully
executed, and the other run will run only after it's completely finished. But with concurrency, you
can make both actions run at the same time:
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
http://www.riptutorial.com/ 178
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")
}
http://www.riptutorial.com/ 179
Chapter 41: Configure Beacons with
CoreBluetooth
Introduction
Hot to read and write data to a bluetooth low energy device.
Remarks
func SearchBLE(){
cb_manager.scanForPeripherals(withServices:[service_uuid], options: nil)
StopSearchBLE()
}
• discoverServices(nil) - NIL means that all services will be returned, which is not a good
option.( READ Remarks 3)
• If you haven't found the SERVICE UUID run your code and looking for in console
http://www.riptutorial.com/ 180
• I found have 3 services: Battery, Device information (Firmware) and FFF0
• This uuid service isn't a standard one, a list with standards can find here
• FFF0 is the SERVICE UUID in this case
protocol DataConvertible {
init?(data: Data)
var data: Data { get }
}
extension DataConvertible {
init?(data: Data) {
guard data.count == MemoryLayout<Self>.size else { return nil }
self = data.withUnsafeBytes { $0.pointee }
}
Examples
Showing names of all Bluetooth Low Energy (BLE)
• For this example I have a controlled room with a single BLE device enable.
• Your class should extend CBCentralManagerDelegate.
• Implement the method: centralManagerDidUpdateState(_ central: CBCentralManager).
• Use global queue to not freeze the screen while searching for a device.
• Instantiate CBCentralManager and wait for callback centralManagerDidUpdateState
response.
http://www.riptutorial.com/ 181
class BLEController: CBCentralManagerDelegate{
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()
}
}
http://www.riptutorial.com/ 182
• I'm in a controlled room with a single minew beacon that use IBEACON protocol.
• BLEController needs to extend CBPeripheralDelegate
• I'll use the first BLE to connect after the search has stop.
• Modify the method StopSearchBLE()
• In the documention of your BLE device, you should look for the SERVICE UUID and MAJOR
UUID CHARACTERISTIC
http://www.riptutorial.com/ 183
print("major: \(major)")
}
• 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).
http://www.riptutorial.com/ 184
cb_manager.cancelPeripheralConnection(peripheral)
}
}
• 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.
http://www.riptutorial.com/ 185
Chapter 42: Contacts Framework
Remarks
Useful Links
• Apple Documentation
Examples
Authorizing Contact Access
import Contacts
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
}
Objective-C
http://www.riptutorial.com/ 186
case CNAuthorizationStatus.Authorized:
//access contacts
break;
case CNAuthorizationStatus.Denied:
//request permission
break;
case CNAuthorizationStatus.NotDetermined:
//request permission
break;
}
Requesting Permission
Swift
Accessing Contacts
Applying a filter
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
Objective-C
http://www.riptutorial.com/ 187
Swift
Fetching contacts
Swift
do {
let contacts = try contactStore.unifiedContactsMatchingPredicate(predicate, keysToFetch:
keys)
} catch let error as NSError {
//...
}
print(contacts[0].givenName)
print(contacts[1].familyName)
let image = contacts[2].imageData
Adding a Contact
Swift
import Contacts
contact.givenName = "John"
contact.familyName = "Appleseed"
contact.phoneNumbers = [CNLabeledValue(
label:CNLabelPhoneNumberiPhone,
value:CNPhoneNumber(stringValue:"(408) 555-0126"))]
http://www.riptutorial.com/ 188
homeAddress.street = "1 Infinite Loop"
homeAddress.city = "Cupertino"
homeAddress.state = "CA"
homeAddress.postalCode = "95014"
contact.postalAddresses = [CNLabeledValue(label:CNLabelHome, value:homeAddress)]
http://www.riptutorial.com/ 189
Chapter 43: Content Hugging/Content
Compression in Autolayout
Remarks
Content Compression Resistance Priority
This value determines how resistant a view is to being expanded. You can imagine
“hugging” here to mean “size to fit” – the bounds of the view will “hug” or be close to
the intrinsic content size. A higher value here means the view will be less likely to grow
and more likely to stay the same.
Examples
Definition: Intrinsic Content Size
Before Auto Layout, you always had to tell buttons and other controls how big they should be,
either by setting their frame or bounds properties or by resizing them in Interface Builder. But it
turns out that most controls are perfectly capable of determining how much space they need,
based on their content.
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.
http://www.riptutorial.com/ 190
Reference: https://www.raywenderlich.com/115444/auto-layout-tutorial-in-ios-9-part-2-constraints
http://www.riptutorial.com/ 191
Chapter 44: Convert HTML to NSAttributed
string and vice verse
Examples
Objective C code to convert HTML string to NSAttributedString and Vice
Versa
//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 ];
http://www.riptutorial.com/ 192
Chapter 45: Convert NSAttributedString to
UIImage
Examples
NSAttributedString to UIImage Conversion
Objective-C
// draw in context
[text drawAtPoint:CGPointMake(0.0, 0.0)];
// transfer image
UIImage *image = [UIGraphicsGetImageFromCurrentImageContext()
imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
UIGraphicsEndImageContext();
return image;
}
http://www.riptutorial.com/ 193
Chapter 46: Core Data
Introduction
Core Data is the model layer of your application in the broadest sense possible. It's the Model in
the Model-View-Controller pattern that permeates the iOS SDK.
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.
Examples
Operations on core data
To Get context:
To fetch data:
To add data:
To save context:
http://www.riptutorial.com/ 194
Chapter 47: Core Graphics
Examples
Creating a Core Graphics Context
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
UIGraphicsBeginImageContextWithOptions(size, false, 0)
UIGraphicsEndImageContext()
Objective-C
UIGraphicsEndImageContext();
1. A CGSize object which stores the whole size of the context (the canvas)
http://www.riptutorial.com/ 195
2. A boolean value which if it is true, the context will be opaque
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.
Swift
Objective-C
http://www.riptutorial.com/ 196
Chapter 48: Core Location
Syntax
1. desiredAccuracy
2. distanceFilter
3. requestLocation()
4. startUpdatingLocation()
5. allowDeferredLocationUpdates(untilTraveled:timeout:)
6. startMonitoringSignificantLocationChanges()
7. allowDeferredLocationUpdates(untilTraveled:timeout:)
8. authorizedAlways
9. authorizedWhenInUse
10. locationManager(_:didChangeAuthorization:)
Remarks
http://www.riptutorial.com/ 197
Examples
Link CoreLocation Framework
http://www.riptutorial.com/ 198
http://www.riptutorial.com/ 199
. The value will be used in the alert controller's message label.
http://www.riptutorial.com/ 200
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.
http://www.riptutorial.com/ 201
Add own custom location using GPX file
To check for location services we need real device but for testing purpose we can also
use simulator and add our own location by following below steps:
<?xml version="1.0"?>
<gpx version="1.1" creator="Xcode">
http://www.riptutorial.com/ 202
<!--
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.
To use standard location services while the application is in the background you need first turn on
Background Modes in the Capabilities tab of the Target settings, and select Location updates.
<key>NSLocationAlwaysUsageDescription</key>
<string>I want to get your location Information in background</string>
<key>UIBackgroundModes</key>
<array>
<string>location</string>
</array>
Objective C
[_locationManager startUpdatingLocation];
Swift
self.locationManager.delegate = self
http://www.riptutorial.com/ 203
if #available (iOS 9.0,*) {
self.locationManager.allowsBackgroundLocationUpdates = true
}
self.locationManager.startUpdatingLocation()
http://www.riptutorial.com/ 204
Chapter 49: Core Motion
Examples
Accessing Barometer to get relative altitude
Swift
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.
http://www.riptutorial.com/ 205
Chapter 50: Core SpotLight in iOS
Examples
Core-Spotlight
Objective-C
1. Create a new iOS project and add CoreSpotlight and MobileCoreServices framework to your
project.
http://www.riptutorial.com/ 206
http://www.riptutorial.com/ 207
2. Create the actual CSSearchableItem and associating the uniqueIdentifier, domainIdentifier
and the attributeSet. Finally index the CSSearchableItem using [[CSSearchableIndex
defaultSearchableIndex]...] as show below.
http://www.riptutorial.com/ 208
http://www.riptutorial.com/ 209
3. OK!Test the index!
http://www.riptutorial.com/ 210
http://www.riptutorial.com/ 211
http://www.riptutorial.com/ 212
http://www.riptutorial.com/ 213
http://www.riptutorial.com/ 214
http://www.riptutorial.com/ 215
Chapter 51: CoreImage Filters
Examples
Core Image Filter Example
Objective-C
http://www.riptutorial.com/ 216
CGImageRef cgimg = [context createCGImage:outputImage fromRect:[outputImage extent]];
UIImage *newImg = [UIImage imageWithCGImage:cgimg];
[myImageView1 setImage:newImg];
CGImageRelease(cgimg);
http://www.riptutorial.com/ 217
[filter setValue:beginImage forKey:kCIInputImageKey];
[filter setValue:[NSNumber numberWithFloat:8.0] forKey:@"inputLevels"];
CIImage *outputImage = [filter outputImage];
[imageView2 setImage:newImg];
CGImageRelease(cgimg);
[self.view addSubview:imageView1];
[self.view addSubview:imageView2];
/* CIAccordionFoldTransition,
CIAdditionCompositing,
CIAffineClamp,
CIAffineTile,
CIAffineTransform,
CIAreaAverage,
CIAreaHistogram,
CIAreaMaximum,
CIAreaMaximumAlpha,
CIAreaMinimum,
CIAreaMinimumAlpha,
CIAztecCodeGenerator,
http://www.riptutorial.com/ 218
CIBarsSwipeTransition,
CIBlendWithAlphaMask,
CIBlendWithMask,
CIBloom,
CIBoxBlur,
CIBumpDistortion,
CIBumpDistortionLinear,
CICheckerboardGenerator,
CICircleSplashDistortion,
CICircularScreen,
CICircularWrap,
CICMYKHalftone,
CICode128BarcodeGenerator,
CIColorBlendMode,
CIColorBurnBlendMode,
CIColorClamp,
CIColorControls,
CIColorCrossPolynomial,
CIColorCube,
CIColorCubeWithColorSpace,
CIColorDodgeBlendMode,
CIColorInvert,
CIColorMap,
CIColorMatrix,
CIColorMonochrome,
CIColorPolynomial,
CIColorPosterize,
CIColumnAverage,
CIComicEffect,
CIConstantColorGenerator,
CIConvolution3X3,
CIConvolution5X5,
CIConvolution7X7,
CIConvolution9Horizontal,
CIConvolution9Vertical,
CICopyMachineTransition,
CICrop,
CICrystallize,
CIDarkenBlendMode,
CIDepthOfField,
CIDifferenceBlendMode,
CIDiscBlur,
CIDisintegrateWithMaskTransition,
CIDisplacementDistortion,
CIDissolveTransition,
CIDivideBlendMode,
CIDotScreen,
CIDroste,
CIEdges,
CIEdgeWork,
CIEightfoldReflectedTile,
CIExclusionBlendMode,
CIExposureAdjust,
CIFalseColor,
CIFlashTransition,
CIFourfoldReflectedTile,
CIFourfoldRotatedTile,
CIFourfoldTranslatedTile,
CIGammaAdjust,
CIGaussianBlur,
CIGaussianGradient,
http://www.riptutorial.com/ 219
CIGlassDistortion,
CIGlassLozenge,
CIGlideReflectedTile,
CIGloom,
CIHardLightBlendMode,
CIHatchedScreen,
CIHeightFieldFromMask,
CIHexagonalPixellate,
CIHighlightShadowAdjust,
CIHistogramDisplayFilter,
CIHoleDistortion,
CIHueAdjust,
CIHueBlendMode,
CIKaleidoscope,
CILanczosScaleTransform,
CILenticularHaloGenerator,
CILightenBlendMode,
CILightTunnel,
CILinearBurnBlendMode,
CILinearDodgeBlendMode,
CILinearGradient,
CILinearToSRGBToneCurve,
CILineOverlay,
CILineScreen,
CILuminosityBlendMode,
CIMaskedVariableBlur,
CIMaskToAlpha,
CIMaximumComponent,
CIMaximumCompositing,
CIMedianFilter,
CIMinimumComponent,
CIMinimumCompositing,
CIModTransition,
CIMotionBlur,
CIMultiplyBlendMode,
CIMultiplyCompositing,
CINoiseReduction,
CIOpTile,
CIOverlayBlendMode,
CIPageCurlTransition,
CIPageCurlWithShadowTransition,
CIParallelogramTile,
CIPDF417BarcodeGenerator,
CIPerspectiveCorrection,
CIPerspectiveTile,
CIPerspectiveTransform,
CIPerspectiveTransformWithExtent,
CIPhotoEffectChrome,
CIPhotoEffectFade,
CIPhotoEffectInstant,
CIPhotoEffectMono,
CIPhotoEffectNoir,
CIPhotoEffectProcess,
CIPhotoEffectTonal,
CIPhotoEffectTransfer,
CIPinchDistortion,
CIPinLightBlendMode,
CIPixellate,
CIPointillize,
CIQRCodeGenerator,
CIRadialGradient,
http://www.riptutorial.com/ 220
CIRandomGenerator,
CIRippleTransition,
CIRowAverage,
CISaturationBlendMode,
CIScreenBlendMode,
CISepiaTone,
CIShadedMaterial,
CISharpenLuminance,
CISixfoldReflectedTile,
CISixfoldRotatedTile,
CISmoothLinearGradient,
CISoftLightBlendMode,
CISourceAtopCompositing,
CISourceInCompositing,
CISourceOutCompositing,
CISourceOverCompositing,
CISpotColor,
CISpotLight,
CISRGBToneCurveToLinear,
CIStarShineGenerator,
CIStraightenFilter,
CIStretchCrop,
CIStripesGenerator,
CISubtractBlendMode,
CISunbeamsGenerator,
CISwipeTransition,
CITemperatureAndTint,
CIToneCurve,
CITorusLensDistortion,
CITriangleKaleidoscope,
CITriangleTile,
CITwelvefoldReflectedTile,
CITwirlDistortion,
CIUnsharpMask,
CIVibrance,
CIVignette,
CIVignetteEffect,
CIVortexDistortion,
CIWhitePointAdjust,
CIZoomBlur*/
http://www.riptutorial.com/ 221
Chapter 52: Create .ipa File to upload on
appstore with Applicationloader
Examples
create .ipa file to upload app to appstore with Application Loader
If you want to upload .ipa file to itunesconnect without integrating developer account in Xcode
and you want to use application loader. then you can generate .ipa with iTunes .
http://www.riptutorial.com/ 222
Step 3 :- After complited process right click to your Archive -> and select show in Finder
http://www.riptutorial.com/ 223
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 6 :- Go to Product Folder -> Application Folder -> You will find yourprojectname.app
http://www.riptutorial.com/ 224
Step 7 :- Now to convert .app to .ipa just drag and drop into itunes . check below image ,
http://www.riptutorial.com/ 225
Step 8 :- Now put this .ipa file in safe place and use when upload with application loader .
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 ,
http://www.riptutorial.com/ 226
IPA is invalid, it does not include a payload directory.
http://www.riptutorial.com/ 227
Chapter 53: Create a Custom framework in
iOS
Examples
Create Framework in Swift
to add created framework to another project, first you should create a workspace
add "target project" and "framework project" to workspace, then :
http://www.riptutorial.com/ 228
Chapter 54: Create a video from images
Introduction
Create a video from images using AVFoundation
Examples
Create Video from UIImages
http://www.riptutorial.com/ 229
assetWriterInputPixelBufferAdaptorWithAssetWriterInput:assetWriterInput
sourcePixelBufferAttributes:attributes];
[assetWriter startWriting];
[assetWriter startSessionAtSourceTime:kCMTimeZero];
[assetWriterInput requestMediaDataWhenReadyOnQueue:exportingQueue usingBlock:^{
for (int i = 0; i < images.count; ++i) {
while (![assetWriterInput isReadyForMoreMediaData]) {
[NSThread sleepForTimeInterval:0.01];
// can check for attempts not to create an infinite loop
}
CVPixelBufferRelease(buffer);
}
[assetWriterInput markAsFinished];
[assetWriter finishWritingWithCompletionHandler:^{
if (assetWriter.error) {
// show error message
} else {
// outputURL
}
}];
}];
http://www.riptutorial.com/ 230
if (outBuffer) {
[context render:ciImage toCVPixelBuffer:*outBuffer];
}
return kCVReturnSuccess;
}
http://www.riptutorial.com/ 231
Chapter 55: Creating an App ID
Examples
Creating In-App Purchase Products
• When offering IAP within an an app, you must first add an entry for each individual purchase
within iTunes Connect. If you’ve ever listed an app for sale in the store, it’s a similar process
and includes things like choosing a pricing tier for the purchase. When the user makes a
purchase, the App Store handles the complex process of charging the user’s iTunes
account. There are a whole bunch of different types of IAP you can add:
○ Consumable: These can be bought more than once and can be used up. These are
things such as extra lives, in-game currency, temporary power-ups, and the like.
○ Non-Consumable: Something that you buy once, and expect to have permanently
such as extra levels and unlockable content.
○ Non-Renewing Subscription: Content that’s available for a fixed period of time.
○ Auto-Renewing Subscription: A repeating subscription such as a monthly
raywenderlich.com subscription.
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.
http://www.riptutorial.com/ 232
When a user purchases a rage comic in your app, you’ll want them to always have access to it, so
select Non-Consumable, and click Create. Next, fill out the details for the IAP as follows:
• 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.
http://www.riptutorial.com/ 233
There’s one more step required before you can delve into some code. When testing in-app
purchases in a development build of an app, Apple provides a test environment which allows you
to ‘purchase’ your IAP products without creating financial transactions.
In iTunes Connect, click iTunes Connect in the top left corner of the window to get back to the
main menu. Select Users and Roles, then click the Sandbox Testers tab. Click + next to the
“Tester” title.
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
http://www.riptutorial.com/ 234
Chapter 56: CTCallCenter
Examples
Intercepting calls from your app even from the background
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");
http://www.riptutorial.com/ 235
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
CallKit - ios 10
//Header File
<CallKit/CXCallObserver.h>
self.callObserver = callObserver;
http://www.riptutorial.com/ 236
Read CTCallCenter online: http://www.riptutorial.com/ios/topic/3007/ctcallcenter
http://www.riptutorial.com/ 237
Chapter 57: Custom fonts
Examples
Applying custom fonts to controls within a Storyboard
The following example shows how to apply custom fonts to a Navigation Bar and includes fixes for
some quirky behaviors found in Xcode. One also may apply the custom fonts to any other
UIControls such as UILabels, UIButtons, and more by using the attributes inspector after the
custom font is added to the project. Please note the external links to working samples and videos
near the bottom.
(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
http://www.riptutorial.com/ 238
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.
1. Sometimes the storyboard xml gets corrupt. This requires you to review the structure in
Storyboard as Source Code mode (right click the storyboard file > Open As ...)
2. In some cases the navigationItem tag associated with user defined runtime attribute was set
as an xml child of the view tag instead of the view controller tag. If so remove it from
between the tags for proper operation.
3. Toggle the NavBar Tint to ensure the custom font is used.
4. Verify the size parameter of the font unless using a dynamic font style
5. View hierarchy will override the settings. It appears that one font per stack is possible.
Result
Samples
• Video Showing Multiple Fonts In Advanced Project
• Simple Source Download
• Advanced Project Download ~ Shows Multiple NavBar Fonts & Custom Font Workaround
• Video Showing Multiple Fonts & Custom Fonts
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.
http://www.riptutorial.com/ 239
2. Import the font files to your Xcode project
3. In the app-info.plist,add a key named Fonts provided by application.It's an array type , add
all your font file names to the array,note:including the file extension.
4. In the storyboard , on the NavigationBar go to the Attribute Inspector,click the right icon
button of the Font select area.In the popup panel , choose Font to Custom, and choose the
Family of you embeded font name.
To workaround this:
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
http://www.riptutorial.com/ 240
Custom Fonts with Storyboard
Custom Fonts for UI components from storyboard can be easily achieved with User Defined
Runtime Attributes in storyboard and Categories.
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 UILabel, UIButton etc. for which you want to set custom font.
All the categories will be having a custom property say fontName. This will be
using from the storyboard later for setting custom font (as in step 4).
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"
http://www.riptutorial.com/ 241
@implementation UILabel (IBExtensions)
- (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
This will set your custom font while running the app.
Notes:
http://www.riptutorial.com/ 242
• Lato-Regular is the custom font I have used.
• Same name in the .ttf file added in bundle should be used without extension in storyboard.
• Font size will be same as it is defined in the UI element's attribute inspector.
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]
http://www.riptutorial.com/ 243
Read Custom fonts online: http://www.riptutorial.com/ios/topic/1504/custom-fonts
http://www.riptutorial.com/ 244
Chapter 58: Custom Keyboard
Examples
Custom KeyBoard Example
http://www.riptutorial.com/ 245
Add the target like this:
http://www.riptutorial.com/ 246
Your project file directory should look something like this
http://www.riptutorial.com/ 247
Here myKeyBoard is the name of the added Target
Add new Cocoatouch file of type of type UIView and add an interface file
http://www.riptutorial.com/ 248
make the keyBoardView.xib a subclass of keyBoardView
http://www.riptutorial.com/ 249
Make connections to from the keyBoardView.xib to keyBoardView.h file
#import <UIKit/UIKit.h>
@end
@property (nonatomic, strong) UIButton *nextKeyboardButton and all the code associated with it
- (void)viewDidLoad {
http://www.riptutorial.com/ 250
[super viewDidLoad];
self.keyboard=[[[NSBundle mainBundle]loadNibNamed:@"keyBoardView" owner:nil
options:nil]objectAtIndex:0];
self.inputView=self.keyboard;
[self addGestureToKeyboard];
-(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.
http://www.riptutorial.com/ 251
You can also watch this Youtube Video
http://www.riptutorial.com/ 252
Chapter 59: Custom methods of selection of
UITableViewCells
Introduction
Advance ways to manage selections of UITableViewCell. Examples when simple didSelect...
form UITableViewDelegate is not enough to achieve something.
Examples
Distinction between single and double selection on row.
An example of implementation which give a possibility to detect if user single or double tap on
UITableViewCell.
http://www.riptutorial.com/ 253
Chapter 60: Custom methods of selection of
UITableViewCells
Examples
Distinction between single and double selection on row.
An example of implementation UITableView which allows to detect if cell has been tapped single
or double time.
http://www.riptutorial.com/ 254
Chapter 61: Custom UITextField
Introduction
Using custom UITextField, we can manipulate the behavior of text field!
Examples
Custom UITextField for Filtering Input Text
Here is an example of custom UITextField that takes only numerical text and discards all other.
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
http://www.riptutorial.com/ 255
Custom UITextField to Disallow All Actions like Copy, Paste, etc
If we want to disable all the actions like Copy, Paste, Replace, Select, etc from UITextField then
we can use following custom text field:
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return enableLongPressActions
}
}
Using enableLongPressActions property, we can enable all actions any time later, if needed.
http://www.riptutorial.com/ 256
Chapter 62: Custom UIViews from XIB files
Remarks
From Apple: Creating a Custom View That Renders in Interface Builder
• Note: Keep in mind that if you'd use fancy 'custom' fonts in your XIB elements (such UILabel,
UITextField etc) then the initial loading time of your XIB will be longer depending on the font
chosen and system version.
Examples
How to make custom reusable UIView using XIB
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
http://www.riptutorial.com/ 257
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.
Wiring elements
http://www.riptutorial.com/ 258
Give your XIB a name (yes, we are doing a Pokemon example ).
Remember to check your target and hit "Create".
http://www.riptutorial.com/ 259
Design your view
• Size: Freeform
• Status Bar: None
• Top Bar: None
• Bottom Bar: None
http://www.riptutorial.com/ 260
http://www.riptutorial.com/ 261
For this example we'll be using width 321 and height 256.
http://www.riptutorial.com/ 262
http://www.riptutorial.com/ 263
Here we'll be adding an Image View (256x256) and a Switch.
http://www.riptutorial.com/ 264
http://www.riptutorial.com/ 265
Xcode Menu Bar > File > New > File.
Select iOS / Source / Cocoa Touch Class. Hit "Next".
Give the class a name, which must be the same name as the XIB file (Pokemon).
Select UIView as the subclass type, then hit "Next".
http://www.riptutorial.com/ 266
On the next window, select your target and hit "Create".
http://www.riptutorial.com/ 267
Connect Pokemon.xib to Pokemon.swift via "File’s Owner" attribute
http://www.riptutorial.com/ 268
POKEMONS!!!
Yes! Drag and drop some Pokemons into your project to finish up our "infrastructure".
Here we are adding two PGN files, 256x256, transparent.
http://www.riptutorial.com/ 269
Show me code already.
import UIKit
// MARK: - Initializers
http://www.riptutorial.com/ 270
super.init(frame: frame)
setupView()
}
// 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.
http://www.riptutorial.com/ 271
http://www.riptutorial.com/ 272
before the class name):
// MARK: - Properties
// MARK: - Initializers
...
http://www.riptutorial.com/ 273
http://www.riptutorial.com/ 274
Give it a different size, say 150x150.
Choose another Pokemon image, observe:
http://www.riptutorial.com/ 275
http://www.riptutorial.com/ 276
The button will allow Pokemons to be enabled/disabled.
// MARK: - Actions
// MARK: - Initializers
...
Final result:
http://www.riptutorial.com/ 277
http://www.riptutorial.com/ 278
Now you can create complex custom views and reuse them anywhere you want.
This will increase productivity while isolating code into self-contained UI elements.
http://www.riptutorial.com/ 279
Chapter 63: Cut a UIImage into a circle
Examples
Cut a image into a circle - Objective C
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
http://www.riptutorial.com/ 280
//Set the SCALE factor for the graphics context
//All future draw calls will be scaled by this factor
CGContextScaleCTM (context, scaleFactorX, scaleFactorY);
return newImage;
}
SWIFT 3 Example
Finally the function which does the heavy lifting circularScaleAndCropImage is as defined below
http://www.riptutorial.com/ 281
//Set the SCALE factor for the graphics context
//All future draw calls will be scaled by this factor
context?.scaleBy(x: scaleFactorX, y: scaleFactorY)
// Draw the IMAGE
let myRect = CGRect(x: CGFloat(0), y: CGFloat(0), width: imageWidth, height:
imageHeight)
image.draw(in: myRect)
let newImage: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
http://www.riptutorial.com/ 282
Chapter 64: CydiaSubstrate tweak
Introduction
Learn how to create cydia substrate tweaks for jailbroken iPhones.
Those tweaks will enable you to modify the operating system's behavior to act the way you would
like it to.
Remarks
Installing Theos
https://github.com/theos/theos/wiki/Installation
Examples
Create new tweak using Theos
$THEOS/bin/nic.pl
Fill in the details and you will get the following files created:
http://www.riptutorial.com/ 283
-rw-r--r--@ 1 gkpln3 staff 214B Jun 12 15:09 Makefile
-rw-r--r--@ 1 gkpln3 staff 89B Jun 11 22:58 TorchonFocus.plist
-rw-r--r-- 1 gkpln3 staff 2.7K Jun 12 16:10 Tweak.xm
-rw-r--r-- 1 gkpln3 staff 224B Jun 11 16:17 control
drwxr-xr-x 3 gkpln3 staff 102B Jun 11 16:18 obj
drwxr-xr-x 16 gkpln3 staff 544B Jun 12 16:12 packages
%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:
%hook SBScreenShotter
- (void)saveScreenshot:(BOOL)screenshot
{
NSLog(@"saveScreenshot: is called");
}
%end
will override the function without calling the original one, thus casing screenshots not being saved.
http://www.riptutorial.com/ 284
Chapter 65: Debugging Crashes
Examples
Finding information about a crash
When your app crashes, Xcode will enter the debugger and show you more information about the
crash:
http://www.riptutorial.com/ 285
http://www.riptutorial.com/ 286
, you will get a textual representation of the stack trace that you can copy and paste:
(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.
• NSInvalidArgumentException,
which means the app passed an invalid argument to a method
• NSRangeException, which means the app tried to access an out-of-bounds index of an object
such as an NSArray or an NSString
• NSInternalInconsistencyException means an object discovered it was in an unexpected state.
• NSUnknownKeyException usually means you have a bad connection in an XIB. Try some of the
answers to this question.
Debugging EXC_BAD_ACCESS
EXC_BAD_ACCESS means the process tried to access memory in an invalid way, like dereferencing a
NULL pointer or writing to read-only memory. This is the hardest kind of crash to debug, because it
usually does not have an error message, and some crashes can be very difficult to reproduce
and/or occur in code completely unrelated to the problem. This error is very rare in Swift, but if it
occurs, you can often get easier-to-debug crashes by reducing compiler optimizations.
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
http://www.riptutorial.com/ 287
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:
http://www.riptutorial.com/ 288
http://www.riptutorial.com/ 289
Chapter 66: Deep Linking in iOS
Remarks
Useful Apple documentation with examples and clarification.
Examples
Opening an app based on its URL scheme
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.
Let's say you're working on an app called MyTasks, and you want to allow inbound URLs to create a
new task with a title and a body. The URL you're designing might look something like this:
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.
http://www.riptutorial.com/ 290
Step One: Register a URL scheme in
Info.plist:
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
http://www.riptutorial.com/ 291
incoming URL and see if there's an action we can take!
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
}
Setting up deep-linking for your app is easy.You just need a small url using which you want to
open your app.
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.
http://www.riptutorial.com/ 292
[scheme]://[host]/[path] --> DeepLinking://path/Page1
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.
http://www.riptutorial.com/ 293
9. Now click the Run button (if you want you can add breakpoint to your
didFinishLaunchingWithOptions and openURL methods to observe values)
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 :)
http://www.riptutorial.com/ 294
Chapter 67: DispatchGroup
Introduction
Related topics:
Concurrency
Examples
Introduction
Suppose you have multiple threads running. Each thread is doing one task. You want to get
notified either on the mainThread OR another thread, when all the task-threads are completed.
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..
http://www.riptutorial.com/ 295
"https://google.ca")!)) { (data, response, error) in
//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)
}
http://www.riptutorial.com/ 296
//Process Response..
//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.
http://www.riptutorial.com/ 297
The amount of enter must equal the amount of leave.
http://www.riptutorial.com/ 298
Chapter 68: Dynamic Type
Remarks
// Accessibility sizes
UIContentSizeCategoryAccessibilityMedium
UIContentSizeCategoryAccessibilityLarge
UIContentSizeCategoryAccessibilityExtraLarge
UIContentSizeCategoryAccessibilityExtraExtraLarge
UIContentSizeCategoryAccessibilityExtraExtraExtraLarge
Examples
Get the Current Content Size
Swift
UIApplication.sharedApplication().preferredContentSizeCategory
Objective-C
[UIApplication sharedApplication].preferredContentSizeCategory;
This returns a content size category constant, or an accessibility content size category constant.
You can register for notifications of when the device text size is changed.
Swift
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(updateFont), name:
name:UIContentSizeCategoryDidChangeNotification, object: nil)
http://www.riptutorial.com/ 299
Objective-C
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateFont)
name:UIContentSizeCategoryDidChangeNotification object:nil];
The notification userInfo object contains the new size under UIContentSizeCategoryNewValueKey.
WKWebView resizes the fonts on web content so that a full-sized web page will fit on the device's
form factor. If you want the web text in both portrait and landscape to be similar in size to the
user's preferred reading size, you need to set it explicitly.
Swift
// build HTML header for dynamic type and responsive design
func buildHTMLHeader() -> String {
http://www.riptutorial.com/ 300
+ "p, li { font: -apple-system-body; font-family: Georgia, serif; font-
size:calc(\(bodySize * landscapeMultiplier)px + 1.0vw); font-weight: normal; color:
\(fontColor) }"
+ "h1 { font: -apple-system-headine; font-family: Verdana, sans-serif; font-
size:calc(\(h1Size * landscapeMultiplier)px + 1.0vw); font-weight: bold; color:
\(headFontColor) } "
+ "h2 { font: -apple-system-headine; font-family: Verdana, sans-serif; font-
size:calc(\(h2Size * landscapeMultiplier)px + 1.0vw); font-weight: bold; color:
\(headFontColor) } "
+ "h3, h4 { font: -apple-system-headine; font-family: Verdana, sans-serif; font-
size:calc(\(h3Size * landscapeMultiplier)px + 1.0vw); font-weight: bold; color:
\(headFontColor) } } </style>"
+ "</head><body>"
+ "<meta name=\"viewport\" content=\"width: device-width\">"
return patternText
}
UILabel, UITextField,& UITextView classes have a new property starting from iOS 10 for
automatically resizing their font when a user changes their preferred reading size named
adjustsFontForContentSizeCategory.
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.
}
http://www.riptutorial.com/ 301
Chapter 69: Dynamically updating a
UIStackView
Examples
Connect the UISwitch to an action we can animate switching between a
horizontal or vertical layout of the image views
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:
http://www.riptutorial.com/ 302
http://www.riptutorial.com/ios/topic/5884/dynamically-updating-a-uistackview
http://www.riptutorial.com/ 303
Chapter 70: EventKit
Examples
Requesting Permission
Your app can't access your reminders and your calendar without permission. Instead, it must show
an alert to user, requesting him/her to grant access to events for the app.
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
Objective-C
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.
Checking Availability
http://www.riptutorial.com/ 304
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
Requesting Permission
Put the following code in NotDetermined case:
Swift
http://www.riptutorial.com/ 305
To access the array of EKCalendars, we use the calendarsForEntityType method:
Swift
Swift
Objective-C
Adding an event
Objective-C
http://www.riptutorial.com/ 306
Setting related calendar, title and dates
Swift
event.calendar = calendar
event.title = "Event Title"
event.startDate = startDate //assuming startDate is a valid NSDate object
event.endDate = endDate //assuming endDate is a valid NSDate object
try {
do eventStore.saveEvent(event, span: EKSpan.ThisEvent)
} catch let error as NSError {
//error
}
Objective-C
NSError *error;
BOOL *result = [eventStore saveEvent:event span:EKSpanThisEvent error:&error];
if (result == NO){
//error
}
http://www.riptutorial.com/ 307
Chapter 71: Extension for rich Push
Notification - iOS 10.
Introduction
iOS 10 gave us UserNotifications.framework, the new API for local/remote notifications. It offers
viewing media attachments or responding to messages right from the notification.
Notification content consists of: title, subtitle, body and attachment. Attachment can contain
images/gifs/videos up to 50 mb.
Examples
Notification Content Extension
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.
Implementation
http://www.riptutorial.com/ 308
http://www.riptutorial.com/ 309
3. In your info.plist file set the identifier for UNNotificationExtensionCategory key:
5. Add new category key and set its value to what we typed in the Info.plist (step 3):
Push:
{
aps: {
alert: { … },
category: 'io.swifting.notification-category'
}
}
Local:
http://www.riptutorial.com/ 310
Chapter 72: Face Detection Using
CoreImage/OpenCV
Examples
Face and Feature Detection
Objective-C
#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"]];
http://www.riptutorial.com/ 311
// 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
http://www.riptutorial.com/ 312
[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];
// round the corners
mouth.layer.cornerRadius = faceWidth*0.2;
// add the new view to the window
[self.view addSubview:mouth];
}
}
// }
}
http://www.riptutorial.com/ 313
Chapter 73: FacebookSDK
Examples
FacebookSDK Integration
You can install the SDK manually or via CocoaPods. The latter option is highly recommended.
target 'MyApp' do
use_frameworks!
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.
http://www.riptutorial.com/ 314
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>
<key>FacebookDisplayName</key>
<string>{FBAppName}</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>fbapi</string>
<string>fb-messenger-api</string>
<string>fbauth2</string>
<string>fbshareextension</string>
</array>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>facebook.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
<key>fbcdn.net</key>
<dict>
http://www.riptutorial.com/ 315
<key>NSIncludesSubdomains</key>
<true/>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
<key>akamaihd.net</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
</dict>
</dict>
</plist>
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.
Sometimes we want to design our own UI for "Sign In With Facebook" button instead of the
original button that comes with FacebookSDK.
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:
http://www.riptutorial.com/ 316
let loginButton = FBSDKLoginButton()
loginButton.delegate = self
// Your Custom Permissions Array
loginButton.readPermissions =
[
"public_profile",
"email",
"user_about_me",
"user_photos"
]
// Hiding the button
loginButton.hidden = true
self.view.addSubview(loginButton)
// Simulating a tap for the actual Facebook SDK button
loginButton.sendActionsForControlEvents(UIControlEvents.TouchUpInside)
Objective-C:
[FBButton sendActionsForControlEvents:UIControlEventTouchUpInside];
You're done.
After the user signed in to Facebook at your app, now it's time to fetch the data you requested at
the FBButton.readPermissions.
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
http://www.riptutorial.com/ 317
if error == nil
{
print("Facebook Graph phaze")
http://www.riptutorial.com/ 318
Chapter 74: Fastlane
Examples
fastlane tools
fastlane is an open source build automation tool for Android and iOS for developers. It reduce your
build generation time. It is a command line tool that uses Ruby, so you need Ruby on your
computer. Most Macs already have Ruby installed by default.
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
Android Tools
http://www.riptutorial.com/ 319
• supply: Upload your Android app and its metadata to Google Play
• screengrab: Automate taking localized screenshots of your Android app on every device
http://www.riptutorial.com/ 320
Chapter 75: FCM Messaging in Swift
Remarks
FCM : https://firebase.google.com/docs/cloud-messaging/ios/client
Examples
Initialize FCM in Swift
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 =
http://www.riptutorial.com/ 321
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
http://www.riptutorial.com/ 322
Chapter 76: FileHandle
Introduction
Read file in chunks from document directory
Examples
Read file from document directory in chunks
I get the file path from document directory and read that file in chunks of 1024 and save (append)
to NSMutableData object or you can directly write to socket.
do {
//here I write chunk data to ReadData or you can directly write to socket.
ReadData.append(datas!)
print("Running: \(ReadData.length)")
}
http://www.riptutorial.com/ 323
}catch let error as NSError {
print("Error : \(error.localizedDescription)")
}
}
}
After file reading complete you will get file Data in ReadData variable Here outputFileHandle is a
object of FileHandle
var outputFileHandle:FileHandle?
http://www.riptutorial.com/ 324
Chapter 77: GameCenter Leaderboards
Examples
GameCenter Leaderboards
Prerequisites:
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
http://www.riptutorial.com/ 325
let vc:UIViewController = self.view!.window!.rootViewController!
vc.presentViewController(viewController!, animated: true, completion: nil)
} else {
3. Now the user is using the app and suddenly the user has a new high score, we report the
high score by calling the function below.
which is defined as a string and used to enter your leaderboardID that you made in
Identifier
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() {
http://www.riptutorial.com/ 326
func gameCenterViewControllerDidFinish(gameCenterViewController:
GKGameCenterViewController) {
http://www.riptutorial.com/ 327
Chapter 78: GameplayKit
Examples
Generating random numbers
Although GameplayKit (which is introduced with iOS 9 SDK) is about implementing game logic, it
could also be used to generate random numbers, which is very useful in apps and games.
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
First, import GameplayKit:
Swift
import GameplayKit
Objective-C
#import <GameplayKit/GameplayKit.h>
Swift
Objective-C
http://www.riptutorial.com/ 328
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
Objective-C
This code will give us a number between 0 and 10, including themselves.
After that the object can be used like every regular GKRandomSource since it does implement the
GKRandom protocol too.
Swift
Objective-C outdated
For example, to generate a random number between 3 and 10, you use this code:
http://www.riptutorial.com/ 329
Swift
Objective-C outdated
An entity represents an object of a game like a player figure or an enemy figure. Since this object
does not do much without arms and legs we can add the components to this. To create this
system apple has the GKEntity and GKComponent classes.
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.
http://www.riptutorial.com/ 330
var player = Player()
player.addComponent(PlayerSpriteComponent())
player.update(deltaTime: 1.0) // will call the update method of the PlayerSpriteComponent
added to it
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.
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())
http://www.riptutorial.com/ 331
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.
http://www.riptutorial.com/ 332
Chapter 79: GCD (Grand Central Dispatch)
Introduction
Grand Central Dispatch (GCD) is Apple's answer to multithreading. It is a lightweight framework
for performing tasks synchronously or asynchronously in queues and handles CPU threads for you
behind the scenes.
Examples
Create a dispatch queue
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
Dispatch Group
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.
A Scenario when this could be useful is if you have multiple webservice calls that all need to finish
before continuing. For example, you need to download multiple sets of data that needs to be
processed by some function. You have to wait for all webservices to complete before calling the
function to process all the received data.
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
http://www.riptutorial.com/ 333
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 dont 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()
Example output:
For more info, refer to the Apple Docs or the related topic
Dispatch Semaphore
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
http://www.riptutorial.com/ 334
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
}
}
}
Swift 3
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)
print("serial long task \(i) done! total time taken: \(timeTaken)")
}
}
}
Example output:
Concurrent Queue
func concurrentQueues () {
let concurrentQueue = DispatchQueue(label: "com.example.concurrent", attributes:
http://www.riptutorial.com/ 335
.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.
The main queue is the dispatch queue in which all the UI updates take place and the code
involving UI changes are placed.
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
http://www.riptutorial.com/ 336
});
SWIFT 3
DispatchQueue.main.async {
DispatchQueue.main.sync {
http://www.riptutorial.com/ 337
Chapter 80: Graph (Coreplot)
Examples
Making graphs with CorePlot
Core Plot provides a podspec, so you can use cocoapods as your library manager which should
make installing and updating much simpler
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...)
http://www.riptutorial.com/ 338
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
// Therefore this class implements the CPTPlotDataSource protocol
-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plotnumberOfRecords
{
return 9; // Our sample graph contains 9 'points'
}
// This method is here because this class also functions as datasource for our graph
// Therefore this class implements the CPTPlotDataSource protocol
-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum
recordIndex:(NSUInteger)index
{
// We need to provide an X or Y (this method will be called for each) value for every
index
int x = index - 4;
// This method is actually called twice per point in the plot, one for the X and one for
the Y value
if(fieldEnum == CPTScatterPlotFieldX)
{
// Return x value, which will, depending on index, be between -4 to 4
return [NSNumber numberWithInt: x];
} else
{
// Return y value, for this example we'll be plotting y = x * x
return [NSNumber numberWithInt: x * x];
}
}
http://www.riptutorial.com/ 339
Read Graph (Coreplot) online: http://www.riptutorial.com/ios/topic/7302/graph--coreplot-
http://www.riptutorial.com/ 340
Chapter 81: Guideline to choose best iOS
Architecture Patterns
Introduction
Demystifying MVC, MVP, MVVM and VIPER or any other design patterns to choose the best
approach to building an app
Examples
MVC pattern
import UIKit
}
// layout code goes here
}
// Assembling of MVC
let model = Person(firstName: "David", lastName: "Blaine")
let view = GreetingViewController()
view.person = model
MVP Patterns
import UIKit
http://www.riptutorial.com/ 341
protocol GreetingView: class {
func setGreeting(greeting: String)
}
protocol GreetingViewPresenter {
init(view: GreetingView, person: Person)
func showGreeting()
}
MVVM Pattern
import UIKit
http://www.riptutorial.com/ 342
var greeting: String? { get }
var greetingDidChange: ((GreetingViewModelProtocol) -> ())? { get set } // function to
call when greeting did change
init(person: Person)
func showGreeting()
}
VIPER Pattern
import UIKit
http://www.riptutorial.com/ 343
}
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()
}
http://www.riptutorial.com/ 344
}
http://www.riptutorial.com/ 345
Chapter 82: Handle Multiple Environment
using Macro
Examples
Handle multiple environment using multiple target and macro
For example, we have two environments: CI - Staging and want to add some customizations for
each environment. Here I will try to customize server URL, app name.
First, we create two targets for 2 environments by duplicating the main target:
http://www.riptutorial.com/ 346
http://www.riptutorial.com/ 347
http://192.168.10.10:8080/
• If we run/archive using CI target, the SERVER_URL is http://ci.api.example.com/
• If we run/archive using STAGING target, the SERVER_URL is http://stg.api.example.com/
If you want to do more customize, for example: Change app name for each target:
http://www.riptutorial.com/ 348
http://www.riptutorial.com/ 349
http://www.riptutorial.com/ 350
http://www.riptutorial.com/ 351
http://www.riptutorial.com/ 352
http://www.riptutorial.com/ 353
http://www.riptutorial.com/ 354
http://www.riptutorial.com/ 355
http://www.riptutorial.com/ios/topic/6849/handle-multiple-environment-using-macro
http://www.riptutorial.com/ 356
Chapter 83: Handling URL Schemes
Syntax
1. // canOpenURL method verifies if there is any app which can handle indicated URL scheme.
2. // Swift
3. // Objective-C
4. // openURL method tries to open a resource located by URL. YES/true if it was opened
otherwise NO/false.
5. // Swift
6. // Objective-C
Parameters
Parameter Meaning
Remarks
In iOS9 and above your app must list any URL schemes it will want to query. This is done by
adding LSApplicationQueriesSchemes to Info.plist
iOS has built-in support for the tel, http/https ,sms, mailto, facetime schemes. It also supports
http–based URLs for Youtube, Maps and iTunes apps.
http: http://www.google.com
facetime: facetime://[email protected]
http://www.riptutorial.com/ 357
mailto: mailto://[email protected]
Youtube: https://www.youtube.com/watch?v=-eCaif2QKfA
Maps:
iTunes: https://itunes.apple.com/us/artist/randy-newman/id200900
Note: Not all special characters are supported in tel scheme (for example * or #). This is done
because of security concerns to prevent users from unauthorized redirect of calls, so in this case
Phone app won't be opened.
Examples
Using built-in URL scheme to open Mail app
Swift:
if let url = URL(string: "mailto://[email protected]") {
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.openURL(url)
} else {
print("Cannot open URL")
}
}
Objective-C:
NSURL *url = [NSURL URLWithString:@"mailto://[email protected]"];
if ([[UIApplication sharedApplication] canOpenURL:url]) {
[[UIApplication sharedApplication] openURL:url];
} else {
NSLog(@"Cannot open URL");
}
These are URL schemes supported by native apps on iOS, OS X, and watchOS 2 and later.
Objective-C
http://www.riptutorial.com/ 358
NSString *stringURL = @"http://stackoverflow.com/";
NSURL *url = [NSURL URLWithString:stringURL];
[[UIApplication sharedApplication] openURL:url];
Swift:
Objective-C
Swift:
HTML
<a href="tel:1-408-555-5555">1-408-555-5555</a>
Objective-C
Swift:
HTML
http://www.riptutorial.com/ 359
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%20were%
Note: Compose email dialog can also be presented within app using MFMailComposeViewController.
http://www.riptutorial.com/ 360
Chapter 84: Healthkit
Examples
HealthKit
Objective-C
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;
}
http://www.riptutorial.com/ 361
- (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 occured 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 {
http://www.riptutorial.com/ 362
NSLog(@"birthdate %@", birthDate);
NSLog(@"gender 2131321 %@", [[GSHealthKitManager sharedManager] readGender]);
Log Output
http://www.riptutorial.com/ 363
Chapter 85: iBeacon
Parameters
Parameters Details
Remarks
Beacons are IOT objects. We are focusing on those which conform to iBeacon protocol a Apple
standard. Each beacon is a one way device which transmits 3 things
1. UUID
2. Major
3. Minor
We can scan iBeacons by setting up our CLLocation manager object to scan for beacons for
particular UUID. All beacons with the given UUID will be scanned.
CLLocation manager also gives call on enter and exit of beacon region.
Examples
iBeacon Basic Operation
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!)
}
http://www.riptutorial.com/ 364
2. Location manager enter and exit region
Ranging iBeacons
http://www.riptutorial.com/ 365
Chapter 86: IBOutlets
Remarks
IBOutlet is neither a reserved word nor a variable or class, is syntactic sugar for Interface Builder.
After the Objective-C source code is pre-processed it is resolved to nothing.
#ifndef IBOutlet
#define IBOutlet
#endif
Examples
Using an IBOutlet in a UI Element
In general, IBOutlets are used to connect an user interface object to another object, in this case a
UIViewController. The connection serves to allow for the object to be affected my code or events
programmatically. This can be done simply by using the assistant from a storyboard and control-
clicking from the element to the view controller's .h property section, but it can also be done
programmatically and manually connecting the IBOutlet code to the "connections" tab of the object
the utility bar on the right. Here is an objective-c example of a UIViewController with a label outlet:
//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";
http://www.riptutorial.com/ 366
@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.
http://www.riptutorial.com/ 367
Chapter 87: In-App Purchase
Examples
Most basic steps for purchasing/subscribing a user to an IAP
First
import StoreKit
import StoreKit
http://www.riptutorial.com/ 368
product_id = "YOUR_PRODUCT_ID"
super.viewDidLoad()
SKPaymentQueue.defaultQueue().addTransactionObserver(self)
// Hide ads
adView.hidden = true
} else {
print("Should show ads...")
http://www.riptutorial.com/ 369
if (validProduct.productIdentifier == self.product_id) {
print(validProduct.localizedTitle)
print(validProduct.localizedDescription)
print(validProduct.price)
buyProduct(validProduct);
} else {
print(validProduct.productIdentifier)
}
} else {
print("nothing")
}
}
{
print("Received Payment Transaction Response from Apple");
case .Restored:
print("Already Purchased");
SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
http://www.riptutorial.com/ 370
if (SKPaymentQueue.canMakePayments()) {
SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
}
Set Up in iTunesConnect
In iTunesConnect, select the app which you want to add an IAP to.
Click the plus. You will then need to select which type of IAP you want to make.
Then you will need to fill out all of the information for your IAP.
http://www.riptutorial.com/ 371
If you have any trouble you can consult the IAP Set Up Guide.
http://www.riptutorial.com/ 372
Chapter 88: Initialization idioms
Examples
Set to tuples to avoid code repetition
Avoid code repetition in constructors by setting a tuple of variables with a one liner:
http://www.riptutorial.com/ 373
It's also possible to both set a value and initialize it:
Move every outlet to an NSObject. Then drag an Object from the library to the controller scene of
the storyboard and hook the elements there.
This is similar in syntax to the example that initializes using positional constants, but requires the
Then extension from https://github.com/devxoul/Then (attached below).
import Foundation
extension Then
{
public func then(@noescape block: inout Self -> Void) -> Self {
var copy = self
block(©)
return copy
}
}
http://www.riptutorial.com/ 374
extension NSObject: Then {}
internal func Init<Type>(value : Type, block: @noescape (object: Type) -> Void) -> Type
{
block(object: value)
return value
}
Usage:
Init(UILabel(frame: CGRect.zero)) {
$0.backgroundColor = UIColor.blackColor()
}
http://www.riptutorial.com/ 375
Chapter 89: iOS - Implementation of XMPP
with Robbie Hanson framework
Examples
iOS XMPP Robbie Hanson Example with Openfire
SRXMPPDemo
Download the example and all the classes here -
https://github.com/SahebRoy92/SRXMPPDemo
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 -
http://www.riptutorial.com/ 376
• Install XAMPP is relatively easy.
• After installation just start the XAMPP and start Database(SQL) and Apache Server.
c. Openfire -
http://www.riptutorial.com/ 377
• Open Browser and Paste this URL - [
http://localhost:9090/setup/index.jsp](http://localhost:9090/setup/index.jsp)
• Do normal setup
○ Select Language >
○ Server settings, leave as it is, just do continue >
○ Database Settings, leave as it is as "Standard Database Connection as selected >
○ Database Settings - Standard Connection". Now remember the name of the DB you
set was ChatDB.
○ Select Database Driver Presets as *"MySQL". Leave JDBC Driver Class as it is. Now
in the Database URL you can see, brackets mentioning hostname and Database
Name. Just change Hostname to "localhost", and database name to "ChatDB", or
any other name of DB you have set earlier, while seting up XAMPP. Leave the
Username and password as blank.Fill up details like the image here
.
○ 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.
Thats it, you are ready to use this example project and start coding and making it into a better
http://www.riptutorial.com/ 378
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.
http://www.riptutorial.com/ 379
Chapter 90: iOS 10 Speech Recognition API
Examples
Speech to text: Recognize speech from a bundle contained audio recording
//import Speech
//import AVFoundation
// 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")
}
http://www.riptutorial.com/ 380
// here you are calling requestSpeechAuth function on UIButton press
@IBAction func playButtonPress(_ sender: AnyObject)
{
requestSpeechAuth()
}
http://www.riptutorial.com/ 381
Chapter 91: iOS Google Places API
Examples
Getting Nearby Places from Current Location
Prerequisites
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 {
let center =
CLLocationCoordinate2DMake((currentLocation.location?.coordinate.latitude)!,
(currentLocation.location?.coordinate.longitude)!)
let northEast = CLLocationCoordinate2DMake(center.latitude + 0.001, center.longitude +
0.001)
let southWest = CLLocationCoordinate2DMake(center.latitude - 0.001, center.longitude -
0.001)
let viewport = GMSCoordinateBounds(coordinate: northEast, coordinate: southWest)
let config = GMSPlacePickerConfig(viewport: viewport)
http://www.riptutorial.com/ 382
placePicker = GMSPlacePicker(config: config)
} else {
print("Place name: nil")
print("Address: nil")
}
})
}
}
http://www.riptutorial.com/ 383
Chapter 92: iOS TTS
Introduction
Find how to produce synthesized speech from text on an iOS device
Examples
Text To Speech
Objective C
Swift
• 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;
http://www.riptutorial.com/ 384
AVSpeechBoundaryWord).
http://www.riptutorial.com/ 385
Chapter 93: Key Value Coding-Key Value
Observation
Remarks
KVC :- Key-Value Coding
Normally instance variables are accessed through properties or accessors but KVC gives another
way to access variables in form of strings. In this way your class acts like a dictionary and your
property name for example “age” becomes key and value that property holds becomes value for
that key.
For example, you have employee class with "age" property. Normally we access like this.
emp.age = @”20″;
NSString age = emp.age;
The mechanism through which objects are notified when there is change in any of property is
called KVO. Ex.:keyboard notification
Examples
Use of context for KVO Observation
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.
http://www.riptutorial.com/ 386
For more information.
Most KVO and KVC functionality is already implemented by default on all NSObject subclasses.
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.
http://www.riptutorial.com/ 387
Chapter 94: Keychain
Syntax
• kSecClassGenericPassword // A value key representing a non-internet password
• kSecClassInternetPassword // A value key representing an internet password
• kSecClassCertificate // A value key representing a certificate
• kSecClassCertificate // A value key representing a key
• kSecClassIdentity // A value key representing an identity, which is a certificate plus a key
Remarks
iOS stores private information such as passwords, encryption keys, certificates, and identities in a
secure storage area called the Keychain. This storage area is managed completely by a co-
processor called the Secure Enclave, which is embedded inside the application processor.
Because the Keychain is sandboxed on iOS, keychain items may only be retrieved by the
application that put them there in the first place.
In some cases you must turn on Keychain Sharing in Xcode capabilities in order to avoid errors.
In order to interact with the keychain, we use a c framework called Keychain Services. For more
information, see Apple's Keychain Services Programming Guide.
Because Keychain Services is below the Foundation level, it is restricted to using CoreFoundation
types. As a result, most objects are internally represented as CFDictionarys holding CFStrings as
their keys and a variety of CoreFoundation types as their values.
While Keychain Services is included as a part of the Security framework, importing Foundation is
usually a good option since it includes some helper functions in the backend.
Additionally, if you don't want to deal with Keychain Services directly, Apple provides the Generic
Keychain Swift sample project that provides Swift types that use Keychain Services behind the
scenes.
Examples
Removing a Password from the Keychain
We need only one thing in order to delete an item from the Keychain: a CFDictionary with attributes
describing the items to be deleted. Any items that match the query dictionary will be deleted
permanently, so if you are only intending to delete a single item be sure to be specific with your
query. As always, we can use an NSDictionary in Objective-C or in Swift we can use a Dictionary
and then cast to CFDictionary.
A query dictionary, in this context exclusively includes a class key to describe what the item is and
http://www.riptutorial.com/ 388
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
// Label
dict[kSecAttrLabel as String] = "com.me.myapp.myaccountpassword" as CFString
// Username
dict[kSecAttrAccount as String] = "My Name" as CFString
Swift
let status = SecItemDelete(dict as CFDictionary)
Every Keychain Item is most often represented as a CFDictionary. You can, however, simply use
NSDictionary in Objective-C and take advantage of bridging, or in Swift you may use Dictionary and
explicitly cast to CFDictionary.
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.
http://www.riptutorial.com/ 389
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>
This places the new attributes dict inside result. SecItemAdd takes in the dictionary we constructed,
as well as a pointer to where we would like our result. The function then returns an OSStatus
indicating success or an error code. Result codes are described here.
To construct a query, we need to represent it as a CFDictionary. You may also use NSDictionary in
Objective-C or Dictionary in Swift and cast to CFDictionary.
http://www.riptutorial.com/ 390
We need a class key:
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.
As usual, we first need a CFDictionary to represent the item we want to update. This must contain
http://www.riptutorial.com/ 391
all of the old values for the item, including the old private data. Then it takes a CFDictionary of any
attributes or the data itself that you would like to change.
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)
Keychain Add, Update, Remove and Find operations using one file.
http://www.riptutorial.com/ 392
Keychain.h
#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
withData:(NSData *)data
withCompletion:(KeychainOperationBlock)completionBlock
{
NSMutableDictionary * dict =[self prepareDict:key];
[dict setObject:data forKey:(__bridge id)kSecValueData];
[dict setObject:keychainService forKey:(id)kSecAttrService];
http://www.riptutorial.com/ 393
}
}
if (status == errSecDuplicateItem) {
[self updateKey:key withData:data withCompletion:^(BOOL successfulOperation, NSData
*updateData, OSStatus updateStatus) {
if (completionBlock) {
completionBlock(successfulOperation, updateData, updateStatus);
}
DLog(@"Found duplication item -- updating key with data");
}];
}
}
-(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);
}
http://www.riptutorial.com/ 394
if (completionBlock) {
completionBlock(errSecSuccess == status, nil, status);
}
}
return dict;
}
@end
Keychain allows to save items with special SecAccessControl attribute which will allow to get item
from Keychain only after user will be authenticated with Touch ID (or passcode if such fallback is
allowed). App is only notified whether the authentication was successful or not, whole UI is
managed by iOS.
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
http://www.riptutorial.com/ 395
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")
}
http://www.riptutorial.com/ 396
Chapter 95: Load images async
Examples
Easiest way
The most simple way to create this is to use Alamofire and its UIImageViewExtension. What we
need is a tableview with a cell that has an imageView in it and lets call it imageView.
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
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
http://www.riptutorial.com/ 397
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.
http://www.riptutorial.com/ 398
Chapter 96: Localization
Introduction
Localization is feature provided by iOS which translates your app into multiple language.For
Localisation,Internationalization is necessary.Internationalization is process of making iOS
app able to adapt different culture,language and regions.
Examples
Localization in iOS
Create an individual Localizable.strings file for each language. The right side would be different
for each language. Think of it as a key-value pair:
"str" = "str-language";
http://www.riptutorial.com/ 399
Chapter 97: Make selective UIView corners
rounded
Examples
Objective C code to make selected corner of a UiView rounded
First import #import <QuartzCore/QuartzCore.h> into your ViewController class. Here is how I set my
view in code
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;
}
http://www.riptutorial.com/ 400
Chapter 98: Managing the Keyboard
Examples
Moving view up or down when keyboard is present
SWIFT:
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:
To do the same thing in Objective-C, this code can be used:
http://www.riptutorial.com/ 401
- (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
{
CGSize keyboardSize = [[[notification userInfo]
objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
-(void)keyboardWillHide:(NSNotification *)notification
{
[UIView animateWithDuration:0.3 animations:^{
CGRect f = self.view.frame;
f.origin.y = 0.0f;
self.view.frame = f;
}];
}
http://www.riptutorial.com/ 402
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.
http://www.riptutorial.com/ 403
• 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>
http://www.riptutorial.com/ 404
// The view controller will adopt this protocol (delegate)
// and thus must contain the keyWasTapped method
@protocol KeyboardDelegate<NSObject>
- (void)keyWasTapped:(NSString *)character;
@end
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.
http://www.riptutorial.com/ 405
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.
http://www.riptutorial.com/ 406
keyboardView.delegate = self; // the view controller will be notified by the keyboard
whenever a key is tapped
- (void)keyWasTapped:(NSString *)character {
[self.textField insertText:character];
}
@end
• Note that the view controller adopts the KeyboardDelegate protocol that we defined above.
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
This example comes originally from this Stack Overflow answer.
http://www.riptutorial.com/ 407
When I first started managing the keyboard I would use separate Notifications in each
ViewController.
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() {
http://www.riptutorial.com/ 408
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.
http://www.riptutorial.com/ 409
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)
}
In summary, I've found using a Singleton + Delegate to manage the keyboard is both more
efficient and easier to use than using Notifications
If you want to hide a keyboard by tap outside of it, it's possible to use this hacky trick (works only
with Objective-C):
- (void)viewDidLoad {
[super viewDidLoad];
http://www.riptutorial.com/ 410
override func viewDidLoad() {
super.viewDidLoad()
txtSomeField.delegate = self
}
}
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)
}
http://www.riptutorial.com/ 411
userInfo[UIKeyboardFrameEndUserInfoKey]?.CGRectValue.size.height {
tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardHeight, 0)
}
}
}
//Objective-C
- (void)viewDidLoad {
[super viewDidLoad];
- (void)keyboardWillShow:(NSNotification *)notification {
if (userInfo) {
CGRect keyboardEndFrame;
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardEndFrame.size.height, 0);
- (void)keyboardWillHide:(NSNotification *)notification {
http://www.riptutorial.com/ 412
Chapter 99: MKDistanceFormatter
Examples
String from distance
Objective-C
CLLocationDistance distance=42;
MKDistanceFormatter *formatter=[[MKDistanceFormatter alloc]init];
NSString *answer=[formatter stringFromDistance:distance];
// answer = "150 feet"
Distance units
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
Unit style
http://www.riptutorial.com/ 413
formatter.unitStyle = .Full
var answer = formatter.stringFromDistance(distance)
// "150 feet"
formatter.unitStyle = .Abbreviated
answer = formatter.stringFromDistance(distance)
// "150 ft"
Objective-C
formatter.unitStyle=MKDistanceFormatterUnitStyleFull;
NSString *answer=[formatter stringFromDistance:distance];
// "150 feet"
formatter.unitStyle=MKDistanceFormatterUnitStyleAbbreviated;
NSString *answer=[formatter stringFromDistance:distance];
// "150 ft"
http://www.riptutorial.com/ 414
Chapter 100: MKMapView
Examples
Scroll to coordinate and zoom-level
When you show a location to your users, you might want the MKMapView to display a coordinate at a
zoom-level instead of setting a region to show. This functionality is not implemented by default, so
you need to extend MKMapView with a methods that do the complex calculation from a coordinate
and zoom-level to a MKCoordinateRegion.
http://www.riptutorial.com/ 415
let maxLng = pixelSpaceXToLongitude(pixelX: topLeftPixelX + scaledMapWidth)
let longitudeDelta = maxLng - minLng
let minLat = pixelSpaceYToLatitude(pixelY: topLeftPixelY)
let maxLat = pixelSpaceYToLatitude(pixelY: topLeftPixelY + scaledMapHeight)
let latitudeDelta = -1.0 * (maxLat - minLat)
return MKCoordinateSpan(latitudeDelta: latitudeDelta, longitudeDelta: longitudeDelta)
}
/**
Sets the center of the `MKMapView` to a `CLLocationCoordinate2D` with a custom zoom-
level. There is no nee to set a region manually. :-)
After you implemented this extension, you can set the center coordinate as following:
zoomLevel is a Double value, usually between 0 and 21 (which is a very high zoom-level), but values
up to 28 are allowed.
http://www.riptutorial.com/ 416
if (annotationView)
{
// Do something with annotation view
// for e.g change image of annotation view
annotationView.image = [UIImage imageNamed:@"SelectedPin.png"];
}
}
[mapView removeAnnotations:mapView.annotations]
if (allAnnotations.count > 0)
{
//getting first annoation
id <MKAnnotation> annotation=[allAnnotations firstObject];
//removing annotation
[mapView removeAnnotation:annotation];
Add MKMapView
Swift
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
Change map-type
iPhone OS 3
.standard
http://www.riptutorial.com/ 417
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;
http://www.riptutorial.com/ 418
iPhone OS 3
.satellite
Displays satellite imagery of the area.
Swift 2
mapView.mapType = .Satellite
Swift 3
http://www.riptutorial.com/ 419
mapView.mapType = .satellite
Objective-C
_mapView.mapType = MKMapTypeSatellite;
iOS 9
.satelliteFlyover
Displays a satellite image of the area with flyover data where available.
http://www.riptutorial.com/ 420
Swift 2
mapView.mapType = .SatelliteFlyover
Swift 3
mapView.mapType = .satelliteFlyover
Objective-C
_mapView.mapType = MKMapTypeSatelliteFlyover;
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
Swift 3
mapView.mapType = .hybrid
Objective-C
_mapView.mapType = MKMapTypeHybrid;
http://www.riptutorial.com/ 421
iOS 9
.hybridFlyover
Displays a hybrid satellite image with flyover data where available.
Swift 2
mapView.mapType = .HybridFlyover
Swift 3
http://www.riptutorial.com/ 422
mapView.mapType = .hybridFlyover
Objective-C
_mapView.mapType = MKMapTypeHybridFlyover;
OpenStreetMap Tile-Overlay
In some cases, you might not want to use the default maps, Apple provides.
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:
http://www.riptutorial.com/ 423
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:
http://www.riptutorial.com/ 424
If you want to display another map, you just have to change the URL-template. There is a list of
tile-servers in the OSM Wiki.
Objective-C
[self.map setShowsUserLocation:YES];
Swift
self.map?.showsUserLocation = true
http://www.riptutorial.com/ 425
http://www.riptutorial.com/ 426
Chapter 101: ModelPresentationStyles
Introduction
Modal Presentation styles are used when you are transitioning from one view controller to another.
There are 2 ways of achieving this customization. One is through code and another through
Interface Builder(using segues). This effect is achieved by settingmodalPresentationStyle variable
to an instance of UIModalPresentationStyle enum. modalPresentationStyle property is a class
variable of UIViewController and is used to specify how a ViewController is presented on screen.
Remarks
Always remember the following mention from Apple.
Examples
Exploring ModalPresentationStyle using Interface Builder
This will be a very basic app which will illustrate different ModalpresentationStyle in iOS. According
to documentation found here, There are 9 different values for UIModalPresentationStyle which are
as follows,
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,
http://www.riptutorial.com/ 427
http://www.riptutorial.com/ 428
(For details on why iPad, refer to Remarks section). Once you are done setting up your project,
select the segue and go to the attributes inspector. You should be able to see something like 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.
http://www.riptutorial.com/ 429
http://www.riptutorial.com/ 430
tab. In this option, when device is in portrait mode, the 2nd ViewController is similar to full screen
but in landscape mode, 2nd ViewController is much narrow the device width. Also, any content not
covered by 2nd ViewController will be dimmed.
http://www.riptutorial.com/ 431
http://www.riptutorial.com/ 432
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.
http://www.riptutorial.com/ 433
http://www.riptutorial.com/ 434
tab. The 2nd ViewController is presented as a small popover(size can be set). The background
content is dimmed. Any tap outside the popover would dismiss the popover. Your Attributes
Inspector should look something like this,
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.
http://www.riptutorial.com/ 435
http://www.riptutorial.com/ 436
http://www.riptutorial.com/ios/topic/10122/modelpresentationstyles
http://www.riptutorial.com/ 437
Chapter 102: MPMediaPickerDelegate
Remarks
Please see the Apple Documentation for more information regarding privacy.
Make sure the Music app is available in your iPhone. It will not work in the simulator.
Examples
Load music with MPMediaPickerControllerDelegate and play it with
AVAudioPlayer
iOS 10.0.1
import UIKit
import AVFoundation
import MediaPlayer
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
{
http://www.riptutorial.com/ 438
avMusicPlayer = try AVAudioPlayer(contentsOf: path as URL)
avMusicPlayer.enableRate = true
avMusicPlayer.rate = 1.0
avMusicPlayer.numberOfLoops = 0
avMusicPlayer.currentTime = 0
}
catch
{
avMusicPlayer = nil
}
}
}
http://www.riptutorial.com/ 439
Chapter 103: MPVolumeView
Introduction
The MPVolumeView class is volume view to presents the user with a slider control for setting the
system audio output volume, and a button for choosing the audio output route.
Remarks
MPVolumeView only shows up when building and running on an actual iOS device and will not
work in a simulator.
Examples
Adding a MPVolumeView
!!!A very important note is that the MPVolumeView only works on an actual device and not on a
simulator.
http://www.riptutorial.com/ 440
Chapter 104: Multicast Delegates
Introduction
Pattern for adding multicasting capabilities to existing iOS controls. Adding multicasting allows for
improved clarity and code re-use.
Examples
Multicast delegates for any controls
Forward messages one object to another by delegates, multicasting these messages to multiple
observers..
#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
http://www.riptutorial.com/ 441
{
return _delegates;
}
- (void)removeDelegate:(id)delegate
{
if ([_delegates containsObject:delegate])
[_delegates removeObject:delegate];
}
- (void)addDelegate:(id)delegate
{
if (![_delegates containsObject:delegate])
[_delegates addObject: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)
http://www.riptutorial.com/ 442
{
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
{
http://www.riptutorial.com/ 443
return objc_getAssociatedObject(self, (__bridge const void *)(key));
}
- (RRMulticastDelegate *)multicastDelegate
{
id multicastDelegate = [self objectForKey:MULTICASTDELEGATE];
if (multicastDelegate == nil) {
multicastDelegate = [[RRMulticastDelegate alloc] init];
return multicastDelegate;
}
- (RRMulticastDelegate *)multicastDatasource
{
id multicastDatasource = [self objectForKey:MULTICASTDATASOURCE];
if (multicastDatasource == nil) {
multicastDatasource = [[RRMulticastDelegate alloc] init];
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.
http://www.riptutorial.com/ 444
Read Multicast Delegates online: http://www.riptutorial.com/ios/topic/10081/multicast-delegates
http://www.riptutorial.com/ 445
Chapter 105: MVP Architecture
Introduction
MVP is an architectural pattern, a derivation of the Model–View–Controller. It's represented by
three distinct components: Model, View and the Presenter. It was engineered to facilitate
automated unit testing and improve the separation of concerns in presentation logic.
In examples you'll find a simple project built with MVP pattern in mind.
Remarks
Components:
• Model is an interface responsible for the domain data (to be displayed or otherwise acted
upon in the GUI)
• View is responsible for the presentation layer (GUI)
• Presenter is the "middle-man" between Model and View. It reacts to the user’s actions
performed on the View, retrieves data from the Model, and formats it for display in the View
Component duties:
• View in MVC is tightly coupled with the Controller, the View part of the MVP consists of both
UIViews and UIViewController
• MVP View is as dumb as possible and contains almost no logic (like in MVVM), MVC View
http://www.riptutorial.com/ 446
has some business logic and can query the Model
• MVP View handles user gestures and delegates interaction to the Presenter, in MVC the
Controller handles gestures and commands Model
• MVP pattern highly supports Unit Testing, MVC has limited support
• MVC Controller has lots of UIKit dependencies, MVP Presenter has none
Pros:
• MVP makes UIViewController a part of the View component it's dumb, passive and...less
massive ;]
• Most of the business logic is incapsulated due to the dumb Views, this gives an excellent
testability. Mock objects can be introduced to test the domain part.
• Separated entities are easier to keep in head, responsibilities are clearly divided.
Cons
Examples
Dog.swift
import Foundation
struct Dog {
let name: String
let breed: String
let age: Int
}
DoggyView.swift
import Foundation
DoggyService.swift
http://www.riptutorial.com/ 447
import Foundation
class DoggyService {
DispatchQueue.main.asyncAfter(deadline: delay) {
result([firstDoggy,
secondDoggy,
thirdDoggy])
}
}
}
DoggyPresenter.swift
import Foundation
class DoggyPresenter {
// MARK: - Private
fileprivate let dogService: DoggyService
weak fileprivate var dogView: DoggyView?
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)")
})
}
http://www.riptutorial.com/ 448
}
}
}
struct DoggyViewData {
let name: String
let age: String
}
DoggyListViewController.swift
import UIKit
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()
}
http://www.riptutorial.com/ 449
emptyView?.isHidden = true;
tableView?.reloadData()
}
func setEmpty() {
tableView?.isHidden = true
emptyView?.isHidden = false;
}
}
http://www.riptutorial.com/ 450
Chapter 106: MVVM
Examples
MVVM Without Reactive Programming
I'll start with a really short explanation what is and why use Model-View-ViewModel (MVVM)
design pattern in your iOS apps. When iOS first appeared, Apple suggested to use MVC (Model-
View-Controller) as a design pattern. They showed it in all of their examples and all first
developers were happy using it because it nicely separated concerns between business logic and
user interface. As applications became larger and more complex a new problem appeared
appropriately called Massive View Controllers (MVC). Because all business logic was added in the
ViewController, with time they usually became too large and complex. To avoid MVC issue, a new
design pattern was introduced to the world of iOS - Model-View-ViewModel (MVVM) pattern.
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.
http://www.riptutorial.com/ 451
var viewModel: MVVMExampleViewModel?
class MVVMExampleViewModel {
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?
http://www.riptutorial.com/ 452
listener?(value)
}
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() {
http://www.riptutorial.com/ 453
// 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.
http://www.riptutorial.com/ 454
Chapter 107: MyLayout
Introduction
MyLayout is a simple and easy objective-c framework for iOS view layout. MyLayout provides
some simple functions to build a variety of complex interface. It integrates the functions including:
Autolayout and SizeClass of iOS, five layout classes of Android, float and flex-box and bootstrap
of HTML/CSS. you can visit from:
Examples
A Simple Demo to use MyLayout
1. There is a container view S which width is 100 and height is wrap to all subviews height.
there are four subviews A,B,C,D arranged from top to bottom.
2. Subview A's left margin is 20% width of S, right margin is 30% width of S, height is equal to
width of A.
3. Subview B's left margin is 40, width is filled in to residual width of S,height is 40. Subview C's
width is filled in to S, height is
40.
4. Subview D's right margin is 20, width is 50% width of S, height is 40
MyLinearLayout *S = [MyLinearLayout
linearLayoutWithOrientation:MyLayoutViewOrientation_Vert];
http://www.riptutorial.com/ 455
S.subviewSpace = 10;
S.widthSize.equalTo(@100);
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;
C.leftPos.equalTo(@0);
C.rightPos.equalTo(@0);
C.heightSize.equalTo(@40);
[S addSubview:C];
UIView *D = UIView.new;
D.rightPos.equalTo(@20);
D.widthSize.equalTo(S.widthSize).multiply(0.5);
D.heightSize.equalTo(@40);
[S addSubview:D];
http://www.riptutorial.com/ 456
Chapter 108: Navigation Bar
Examples
Customize default navigation bar appearance.
SWIFT Example
navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName:
UIColor.white, NSFontAttributeName:UIFont(name: "HelveticaNeue-CondensedBold", size: 17)!,]
navigationController?.navigationBar.tintColor = .white
navigationController?.navigationBar.barTintColor = .red
navigationController?.navigationBar.isTranslucent = false
navigationController?.navigationBar.barStyle = .black
http://www.riptutorial.com/ 457
Chapter 109: NSArray
Introduction
Here are some useful utility functions/methods that can be used as with Array extension for ease
of developer to perform certain critical operations on array with help of single line code.
Remarks
Once, current document gets approved, will add so many enhancement for other array utilites
also. This is my first document and need your assistance and approval in my effort.
Examples
Convert Array into json string
Call this function with parameter argument as array with type 'any'. It will return you json string.
Json string is used to submit array in web service call as request input parameter in Swift.
//-----------------------
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
}
http://www.riptutorial.com/ 458
Chapter 110: NSAttributedString
Remarks
Set Color of Font Using NSAttributedString
Examples
Removing all attributes
Objective-C
Swift
NSAttributedString (and its mutable sibling NSMutableAttributedString) allows you to create strings
that are complex in their appearance to the user.
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];
http://www.riptutorial.com/ 459
Create a string with strikethrough text
Objective-C
Swift
yourLabel.attributedText = attributeString;
Objective-C
Swift
http://www.riptutorial.com/ 460
let color = UIColor.red;
let textToFind = "redword"
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.
http://www.riptutorial.com/ 461
Chapter 111: NSBundle
Examples
Getting the Main Bundle
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();
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.
http://www.riptutorial.com/ 462
CFRelease(bundleURL);
// Use the bundle ...
// Release the bundle when done.
CFRelease(myBundle);
http://www.riptutorial.com/ 463
Chapter 112: NSData
Remarks
Useful Resources
Apple Documentation (NSData)
NSData.dataWithContentsOfFile()
NSData.bytes
Examples
Creating NSData objects
Using a file
Swift
Objective-C
Objective-C
http://www.riptutorial.com/ 464
Converting NSData to other types
To String
Swift
Objective-C
To Array
Swift
let array = data.bytes as! NSMutableArray //assuming data is a valid NSData object
Objective-C
To Bytes Array
Swift
let bytesArray = data.bytes as! UInt8 //assuming data is a valid NSData object
Objective-C
http://www.riptutorial.com/ 465
can be represented as hexadecimal string, similar to what it outputs in its description method.
Swift
extension NSData {
Objective-C
- (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
http://www.riptutorial.com/ 466
Chapter 113: NSDate
Syntax
• NSDate() // NSDate object init to the current date and time
• NSDate().timeIntervalSince1970 // Current date and time in number of seconds from
00:00:00 UTC on 1 January 1970.
• NSDate().compare(other: NSDate) // Returns a comparison of current date to another date
returns a NSComparisonResult
Remarks
There are different types of date format that you can set: Here is full list of them.
175 AD → 2016 AD →
y A year with at least 1 digit.
“175” “2016”
2016 AD →
yyy A year with at least 3 digits. 5 AD → “005”
“2016”
5 AD → 2016 AD →
yyyy A year with at least 4 digits.
“0005” “2016”
"November" →
M A month with at least 1 digit. July → “7”
"11"
"November" →
MM A month with at least 2 digits. July → “07”
"11"
"November" →
MMM Three letter month abbreviation. July → “Jul”
"Nov"
"November" →
MMMM Full name of month. July → “July”
"November"
http://www.riptutorial.com/ 467
Format Meaning/Description Example1 Example2
Monday → Thursday →
EEEE Full Day name.
“Monday” “Thursday”
Monday →
EEEEEE 2 letter day abbreviation of day name. Thursday → “Th”
“Mo”
10 PM →
a Period of day (AM/PM). 2 AM → “AM”
“PM”
There are many more, for getting different time based on zone(z), for getting time with millisecond
details(S), etc.
Examples
Get Current Date
Getting current date is very easy. You get NSDate object of current date in just single line as
follows:
Swift
http://www.riptutorial.com/ 468
var date = NSDate()
Swift 3
Objective-C
The number of seconds from the current date and time for the new date. Use a negative value to
specify a date before the current date.
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
Swift 3
//Using negative value to get date one week from current date
let lastWeek = Date(timeIntervalSinceNow: -totalSecondsInWeek)
Objective-C
http://www.riptutorial.com/ 469
//Using positive value for future date from today
NSDate *nextWeek = [NSDate dateWithTimeIntervalSinceNow:totalSecondsInWeek];
Date Comparison
Swift
• isEqualToDate(anotherDate: NSDate) -> Bool
• earlierDate(anotherDate: NSDate) -> NSDate
• laterDate(anotherDate: NSDate) -> NSDate
• compare(anotherDate: NSDate) -> NSComparisonResult
Objective-C
• - (BOOL)isEqualToDate:(NSDate *)anotherDate
• - (NSDate *)earlierDate:(NSDate *)anotherDate
• - (NSDate *)laterDate:(NSDate *)anotherDate
• - (NSComparisonResult)compare:(NSDate *)anotherDate
Swift
Objective-C
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)
http://www.riptutorial.com/ 470
result: NSComparisonResult = date1.compare(date2)
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
http://www.riptutorial.com/ 471
// get the user's calendar
let userCalendar = Calendar.current
Swift
let date = NSDate() // current date
let unixtime = date.timeIntervalSince1970
Objective-C
NSDate *date = [NSDate date]; // current date
int unixtime = [date timeIntervalSince1970];
Convert NSDate that is composed from hour and minute (only) to a full
NSDate
There are many cases when one has created an NSDate from only an hour and minute format, i.e:
08:12 that returns from a server as a String and you initiate an NSDate instance by these values
only.
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
http://www.riptutorial.com/ 472
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
NSDateFormatter
Swift 3
Objective-C
http://www.riptutorial.com/ 473
2. Set the date format in which you want your
string
Swift
Objective-C
Swift 3
Objective-C
Note
Creating an NSDateFormatter instance is an expensive operation, so it is recommended
to create it once and reuse when possible.
extension Date {
http://www.riptutorial.com/ 474
func toString() -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMMM dd yyyy"
return dateFormatter.string(from: self)
}
}
Here this will calculate the UTC time offset from current data in desired timezone.
Objective-C
http://www.riptutorial.com/ 475
NSRange containsA = [formatStringForHours rangeOfString:@"a"];
BOOL is24h = containsA.location == NSNotFound;
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
The second option was derived from this answer.
Prior to Json.NET 4.5 dates were written using the Microsoft format: "/Date(1198908717056)/". If
your server sends date in this format you can use the below code to serialize it to NSDate:
Objective-C
This can be used in various chat applications, rss feeds, and social apps where you need to have
latest feeds with timestamps:
Objective-C
http://www.riptutorial.com/ 476
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;
}
http://www.riptutorial.com/ 477
Chapter 114: NSHTTPCookieStorage
Examples
Store and read the cookies from NSUserDefault
import Foundation
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() {
http://www.riptutorial.com/ 478
for c : NSHTTPCookie in savedC! {
}
NSUserDefaults.standardUserDefaults().setValue(allCookiesDic, forKey: "customeWebsite")
NSUserDefaults.standardUserDefaults().synchronize()
if(CookiesSingleton.enableDebug){
print("Cookies Saved")
}
}
http://www.riptutorial.com/ 479
Chapter 115: NSInvocation
Examples
NSInvocation Objective-C
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:)];
http://www.riptutorial.com/ 480
[myInvocation setArgument:&myString atIndex:2];
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];.
Think of it like sending an email. You open up a new email (NSInvocation object), fill in the address
of the person (object) who you want to send it to, type in a message for the recipient (specify a
selector and arguments), and then click "send" (call invoke).
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.
http://www.riptutorial.com/ 481
Chapter 116: NSNotificationCenter
Introduction
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.
Parameters
Parameter Details
The name of the notification for which to register the observer; that is, only
notifications with this name are used to add the block to the operation queue. If
name
you pass nil, the notification center doesn’t use a notification’s name to decide
whether to add the block to the operation queue.
The object whose notifications the observer wants to receive; that is, only
notifications sent by this sender are delivered to the observer. If you pass nil,
obj
the notification center doesn’t use a notification’s sender to decide whether to
deliver it to the observer.
The operation queue to which block should be added. If you pass nil, the block
queue
is run synchronously on the posting thread.
The block to be executed when the notification is received. The block is copied
block by the notification center and (the copy) held until the observer registration is
removed.
Remarks
An NSNotificationCenter object (or simply, notification center) provides a mechanism for
broadcasting information within a program. An NSNotificationCenter object is essentially a
notification dispatch table.
Examples
http://www.riptutorial.com/ 482
Adding/Removing an Observer with a Block
// Add observer
let observer =
NSNotificationCenter.defaultCenter().addObserverForName("nameOfTheNotification", object: nil,
queue: nil) { (notification) in
// Do operations with the notification in this block
}
// Remove observer
NSNotificationCenter.defaultCenter().removeObserver(observer)
Adding an Observer
Naming Convention
Notifications are identified by global NSString objects whose names are composed in this way:
For example:
• NSApplicationDidBecomeActiveNotification
• NSWindowDidMiniaturizeNotification
• NSTextViewDidChangeSelectionNotification
• NSColorPanelColorDidChangeNotification
Swift 2.3
http://www.riptutorial.com/ 483
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.
Removing Observers
Swift 2.3
//Remove observer for single notification
NSNotificationCenter.defaultCenter().removeObserver(self, name: "TestNotification", object:
nil)
Swift 3
//Remove observer for single notification
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue:
"TestNotification"), object: nil)
http://www.riptutorial.com/ 484
NotificationCenter.default.removeObserver(self)
Objective-C
//Remove observer for single notification
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"TestNotification"
object:nil];
Posting a Notification
Swift
NSNotificationCenter.defaultCenter().postNotificationName("TestNotification", object: self)
Objective-C
[[NSNotificationCenter defaultCenter] postNotificationName:@"TestNotification" object:nil];
Swift
let userInfo: [String: AnyObject] = ["someKey": myObject]
NSNotificationCenter.defaultCenter().postNotificationName("TestNotification", object: self,
userInfo: userInfo)
Objective-C
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:myObject forKey:@"someKey"];
[[NSNotificationCenter defaultCenter] postNotificationName: @"TestNotification" object:nil
userInfo:userInfo];
Observing a Notification
Swift
http://www.riptutorial.com/ 485
func testNotification(notification: NSNotification) {
let userInfo = notification.userInfo
let myObject: MyObject = userInfo["someKey"]
}
Objective-C
- (void)testNotification:(NSNotification *)notification {
NSDictionary *userInfo = notification.userInfo;
MyObject *myObject = [userInfo objectForKey:@"someKey"];
}
http://www.riptutorial.com/ 486
Chapter 117: NSPredicate
Syntax
• Predicate Format String Substitions
○C format string specifiers: %d, %s, %f, etc
○Object substitution: %@
○Keypath substitution: %K
• Predicate Comparison Operators
○=, ==: Left-hand expression equals right-hand expression
○>=, =>: Left-hand expression is greater than or equal to right-hand expression
○<=, =<: Left-hand expression is less than or equal to right-hand expression
○>: Left-hand expression is greater than right-hand expression
○<: Left-hand expression is less than right-hand expression
○!=, <>: Left-hand expression is not equal to right-hand expression
○BETWEEN: Left-hand expression is between or equal to either of the values in the
right-hand expression, which specifies lower and upper bounds - ex: BETWEEN { 0, 5 }
• Predicate Compound Operators
○AND, &&: Logical AND
○OR, ||: Logical OR
○NOT, !: Logical NOT
• Predicate String Comparison Operators
○BEGINSWITH: Left-hand expression begins with right-hand expression
○ENDSWITH: Left-hand expression ends with right-hand expression
○CONTAINS: Left-hand expression contains right-hand expression
○LIKE: Left-hand expression equals right-hand expression, with wildcard substitution
○*: Match zero or more characters
○?: Match one character
Examples
Form validation using NSPredicate
-(BOOL)validateEmail {
http://www.riptutorial.com/ 487
//Email address field should give an error when the email address begins with ".","-","_"
.
NSPredicate *emailPredicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",
emailRegex];
return ([emailPredicate evaluateWithObject:self.text] && self.text.length <= 64 &&
([self.text rangeOfString:@".."].location == NSNotFound));
}
- (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];
http://www.riptutorial.com/ 488
- (BOOL)validateCity {
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", cityRegEx];
return [predicate evaluateWithObject:self.text];
}
- (BOOL)validatePIN {
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", PINRegEx];
Objective-C
Swift
In this example, the predicate will match items that are of the class UILabel.
Objective-C
Swift
http://www.riptutorial.com/ 489
In this example, the predicate will match items that are arrays with length of at least 5.
An NSPredicate can use substitution variables to allow values to be bound on the fly.
Objective-C
Swift
Objective-C
Swift
http://www.riptutorial.com/ 490
let beginsWithRVariables = ["letter": "r"]
let beginsWithR = template.predicateWithSubstitutionVariables(beginsWithRVariables)
Conditional predicate will be cleaner and safer by using the NSCompoundPredicate class which
provides basic boolean operators for the given predicates.
Objective-c
AND - Condition
OR - Condition
NOT - Condition
http://www.riptutorial.com/ 491
Chapter 118: NSTimer
Parameters
Parameter Details
The time, in seconds, to wait beforing firing the timer; or, in repeating timers, the
interval
time between firings.
selector In Swift, a Selector object specifying the method to call on the target
repeats If false, fire the timer only once. If true, fire the timer every interval seconds.
Remarks
An NSTimer allows you to send a message to a target after a specified period of time elapses.
Examples
Creating a Timer
This will create a timer to call the doSomething method on self in 5 seconds.
Swift
Swift 3
Objective-C
http://www.riptutorial.com/ 492
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.
Swift
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.
Invalidating a timer
Swift
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.
http://www.riptutorial.com/ 493
class ViewController: UIViewController {
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.
http://www.riptutorial.com/ 494
Passing of data using Timer
If you you want to pass some data with the timer trigger you can do it with the userInfoparameter.
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]);
}
http://www.riptutorial.com/ 495
Chapter 119: NSURL
Examples
How to get last string component from NSURL String.
Swift 2.3
Swift 3.0
http://www.riptutorial.com/ 496
Chapter 120: NSURLConnection
Examples
Delegate methods
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// The request is complete and data has been received
// You can parse the stuff in your instance variable now
Synchronous Request
http://www.riptutorial.com/ 497
NSError * error = nil;
NSData * data = [NSURLConnection sendSynchronousRequest:urlRequest
returningResponse:&response
error:&error];
if (error == nil)
{
// Parse data here
}
Asynchronous request
http://www.riptutorial.com/ 498
Chapter 121: NSURLSession
Remarks
The NSURLSession class and related classes provide an API for downloading content. This API
provides a rich set of delegate methods for supporting authentication and gives your app the ability
to perform background downloads when your app is not running or, in iOS, while your app is
suspended.
At a high level, NSURLSession is based around the concept of sessions and tasks. A task
represents a single request for a single URL (or a single upload to a single URL). A session is a
group of related requests.
The operating system provides a single preexisting session—the shared session, which basically
works like NSURLConnection. Additionally, you can create your own sessions in your app as
needed.
Different apps use sessions in different ways. Many apps create a single session on launch and
just keep reusing it. Other apps benefit from being able to cancel a group of related tasks (e.g. a
web browser canceling all outstanding requests when you close a tab), and thus create one
session to hold each group of related requests.
The first step when using NSURLSession is to create a session configuration object. The (usually)
reusable object contains various session settings that you can tweak for your particular needs,
such as maximum concurrency, extra headers to send with each request, whether to allow
requests to be sent over the cellular radio (iOS only), timeouts, credential storage, minimum TLS
version, and even proxy settings.
There are three types of session configurations, depending on how you want the resulting session
to behave:
When you create a background configuration, you must provide a session identifier that allows you
to reassociate the background session later (if your app exits or is suspended or terminated by the
OS). You must not have more than one instance of a session with the same identifier active in
your app, so as a rule, these configurations are not reusable. All other session configurations can
be reused to create as many sessions as you want. So if you need to create multiple sessions with
similar settings, you can create the configuration once and reuse it every time you create a new
session.
After you create a session, you can create tasks in that session. There are three types of tasks:
http://www.riptutorial.com/ 499
• Data tasks return data as an NSData object. These are suitable for general use, but are not
supported in background sessions.
• Download tasks return data as a file on disk. These are suitable for larger requests, or for
use in background sessions.
• Upload tasks upload data from an NSData object or from a file on disk. You provide a data
object or file that provides the POST body. The body data/file that you provide on the task
overrides any body data/file provided in the NSURLRequest object (if applicable).
Each of these types lets you obtain the response data in a couple of different ways—either by
using block-based callbacks or by providing a delegate on the session and implementing delegate
methods.
Additionally NSURLSession lets you provide delegate methods for handling authentication,
performing custom TLS certificate handling (both for client certificates and server validation),
changing the caching behavior, and so on.
Examples
Objective-C Create a Session And Data Task
[[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)
http://www.riptutorial.com/ 500
// add tasks here
// 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.
// define url
let url = NSURL(string: "https://urlToGet.com")
http://www.riptutorial.com/ 501
//create a task to get data from a url
let task = NSURLSession.sharedSession().dataTaskWithURL(url!)
{
/*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
}
}
There are two common ways to encode a POST request body: URL encoding (application/x-www-
form-urlencoded) and form data (multipart/form-data). Much of the code is similar, but the way you
construct the body data is different.
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 want to talk to that server at one point with your iOS application.
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]];
http://www.riptutorial.com/ 502
URLWithString:scriptURL]];
NSString * postDataString = [NSString stringWithFormat:@"name=%@&password=%@", [self
nameString], [self URLEncode:passwordString]];
[urlRequest setHTTPMethod:@"POST"];
[urlRequest setHTTPBody:[postDataString dataUsingEncoding:NSUTF8StringEncoding]];
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:
http://www.riptutorial.com/ 503
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler{
// Handler allows us to receive and parse responses from the server
completionHandler(NSURLSessionResponseAllow);
}
// 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
http://www.riptutorial.com/ 504
credentialForTrust:challenge.protectionSpace.serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
}
}
}
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.
//
// Notice that we prepend two additional hyphens to the boundary when
// we actually use it as part of the body data.
//
[body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary]
dataUsingEncoding:NSUTF8StringEncoding]];
// 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.
http://www.riptutorial.com/ 505
[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.
http://www.riptutorial.com/ 506
Chapter 122: NSUserActivity
Introduction
An NSUserActivity object can be used to coordinate significant events in an app with the system. It
is the basis for Handoff between different devices running iOS and macOS. Additionally, it may
also be used to improve public-indexing and augment or create Spotlight Search results for an
app. As of iOS 10, it may also be used to coordinate interactions between your app and Siri using
SiriKit.
Remarks
Activity Types
Supported activity types must be defined in your app's Info.plist file under the
NSUserActivityTypes key. Activities are tied to your Developer Team ID, meaning that activity
coordination is restricted between apps that have the same Team ID (e.g. "Safari" could not
accept a Handoff activity from "Chrome" or vice versa).
If you invalidate an activity, the same instance may not be made current again.
Search Indexing
Activities are not to be used as a general-purpose indexing mechanism within your app. Instead,
they should only be used in response to user-initiated actions. To index all content in your app,
use CoreSpotlight.
Examples
Creating a NSUserActivity
To create a NSUserActivity object, your app must declare the types of activities it supports in its
Info.plist file. Supported activities are defined by your application and should be unique. An
http://www.riptutorial.com/ 507
activity is defined using a reverse-domain style naming scheme (i.e.
"com.companyName.productName.activityName"). Here is what an entry in your Info.plist might
look like:
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").
http://www.riptutorial.com/ 508
Chapter 123: NSUserDefaults
Syntax
• UserDefaults.standard.set(dic, forKey: "LoginSession") //Save value inside userdefaults
Remarks
NSUserDefault which are used to store all type of DataType, and you can get its value anywhere
in the class of app. NSUserDefault
Examples
Use Managers to Save and Read Data
While you can use the NSUserDefaults methods anywhere, it can sometimes be better to define a
manager that saves and reads from NSUserDefaults for you and then use that manager for reading
or writing your data.
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
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.
NSUserDefaults.standardUserDefaults().setInteger(newValue, forKey:
highScoreDefaultKey)
NSUserDefaults.standardUserDefaults().synchronize()
}
get {
//This method includes your implementation for reading the high score
let score =
NSUserDefaults.standardUserDefaults().objectForKey(highScoreDefaultKey)
if (score != nil) {
return score.integerValue;
http://www.riptutorial.com/ 509
} else {
//No high score available, so return -1
return -1;
}
}
}
}
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.
http://www.riptutorial.com/ 510
Note
If you are worried about synchronization, it is better to use a singleton class that
manages the synchronization.
Clearing NSUserDefaults
Swift
NSUserDefaults.standardUserDefaults().removePersistentDomainForName(bundleIdentifier)
Objective-C
NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
Saving Values
NSUserDefaults are written to disk periodically by the system, but there are times when you want
your changes saved immediately, such as when the app transitions into background state. This is
done by calling synchronize.
Swift
NSUserDefaults.standardUserDefaults().synchronize()
Objective-C
Setting values
Swift < 3
setBool(_:forKey:)
setFloat(_:forKey:)
setInteger(_:forKey:)
setObject(_:forKey:)
http://www.riptutorial.com/ 511
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
Swift < 3
Swift 3
Objective-C
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
http://www.riptutorial.com/ 512
}
Objective-C
- (id)initWithCoder:(NSCoder *)coder {
self = [super init];
if (self) {
name = [coder decodeObjectForKey:@"name"];
unitId = [coder decodeIntegerForKey:@"unitId"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder*)coder {
[coder encodeObject:name forKey:@"name"];
[coder encodeInteger:unitId forKey:@"unitId"];
}
Swift
arrayForKey(_:)
boolForKey(_:)
dataForKey(_:)
dictionaryForKey(_:)
floatForKey(_:)
integerForKey(_:)
objectForKey(_:)
stringArrayForKey(_:)
stringForKey(_:)
doubleForKey(_:)
URLForKey(_:)
Objective-C
http://www.riptutorial.com/ 513
-(double)doubleForKey:(nonnull NSString *)defaultName;
-(nullable NSURL *)URLForKey:(nonnull NSString *)defaultName;
Swift
Objective-C
Every application needed to store User Session or User related details inside application in
UserDefaults.So we made whole logic inside a Class for managing UserDefaults better way.
Swift 3
import Foundation
http://www.riptutorial.com/ 514
}
http://www.riptutorial.com/ 515
Chapter 124: Objective-C Associated Objects
Introduction
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.
Syntax
• void objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy)
Parameters
Param Details
This can basically be any pointer that has a constant memory address, but a nice
key
practice is to use here a computed property (getter)
The memory policy for this new value i.e. should it be retained / assigned, copied
policy
etc.. just like any other property you'd declare
Remarks
More details here:
NSHipster
@kostiakoval
kingscocoa
Examples
Basic Associated Object Example
http://www.riptutorial.com/ 516
Assume we need to add an NSString object to SomeClass (we cant subclass).
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));
}
http://www.riptutorial.com/ 517
Chapter 125: OpenGL
Introduction
OpenGL ES is a graphics library that iOS uses to do 3D rendering.
Examples
Example Project
An example project (Git repo) that can be used as a starting point for doing some 3D rendering.
The code for setting up OpenGL and the shaders is quite long and tedious so it wont fit well under
this example format. Later pieces of it can be shown in separate examples detailing what exactly
is going on with each piece of code, but for now here is the Xcode project.
http://www.riptutorial.com/ 518
Chapter 126: Passing Data between View
Controllers
Examples
Using Segues (passing data forward)
To pass data from the current view controller to the next new view controller (not a previous view
controller) using segues, first create a segue with an identifier in the relevant storyboard. Override
your current view controller's prepareForSegue method. Inside the method check for the segue you
just created by its identifier. Cast the destination view controller and pass data to it by setting
properties on the downcast view controller.
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.
http://www.riptutorial.com/ 519
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
To pass data from the current view controller back to the previous view controller, you can use the
delegate pattern.
http://www.riptutorial.com/ 520
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
http://www.riptutorial.com/ 521
}
}
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
// 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)
http://www.riptutorial.com/ 522
delegate?.userDidEnterInformation(textField.text ?? "")
}
}
Objective-C
@implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (IBAction) sendTextBackButton:(id)sender{
[_delegate userDidEnterInformation:textField.text];
}
@end
In contrast to segue that lets you pass data "forward" from current view controller to destination
view controller:
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.
http://www.riptutorial.com/ 523
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:
this topic is a classical issue in iOS development, and its solution is various as other example
already shown. In this example I'll show another daily common use one: passing data using
closure by adapting delegate pattern example on this page into callback closure!
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
http://www.riptutorial.com/ 524
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
http://www.riptutorial.com/ 525
parameter that passing data back!
Instead of using the delegate pattern, that split the implementation in various part of the
UIViewController class, you can even use closures to pass data back and forward. By assuming
that you're using the UIStoryboardSegue, in the prepareForSegue method you can easily setup the
new controller in one step
destinationController.onCompletion = { success in
// this will be executed when `someButtonTapped(_:)` will be called
print(success)
}
}
}
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
You can pass data directly by assigning the property of the next view controller before you push or
present it.
func openSecondViewController() {
http://www.riptutorial.com/ 526
override func viewDidLoad() {
super.viewDidLoad()
// Here we unwrapped the id and will get the data from the previous view controller.
if let id = id {
print("Id was set: \(id)")
}
}
}
http://www.riptutorial.com/ 527
Chapter 127: Passing Data between View
Controllers (with MessageBox-Concept)
Introduction
MessageBox is a simple concept for decoupling entities.
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.
Examples
Simple Example Usage
// 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)
http://www.riptutorial.com/ 528
Chapter 128: PDF Creation in iOS
Examples
Create PDF
[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.";
http://www.riptutorial.com/ 529
CGContextSetTextMatrix(currentContext, CGAffineTransformIdentity);
CGContextTranslateCTM(currentContext, 0, 450);
CGContextScaleCTM(currentContext, 2, -2);
CTFrameDraw(frameRef, currentContext);
CFRelease(frameRef);
CFRelease(stringRef);
CFRelease(framesetter);
}
Show PDF
NSArray *arrayPaths =
NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory,
NSUserDomainMask,
YES);
http://www.riptutorial.com/ 530
NSString *path = [arrayPaths objectAtIndex:0];
[webView setScalesPageToFit: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;
http://www.riptutorial.com/ 531
}
@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");
}
});}
http://www.riptutorial.com/ 532
Chapter 129: plist iOS
Introduction
Plist is used for storage of data in iOS app. Plist save data in form of Array and Dictionaries. In
plist we can save data as: 1. Static data to be used in app. 2. Data that will be coming from server.
Examples
Example:
http://www.riptutorial.com/ 533
http://www.riptutorial.com/ 534
b) Click Property list in Resources
http://www.riptutorial.com/ 535
d) You can create a plist of Arrays and Dictionaries as:
http://www.riptutorial.com/ 536
// Read plist from bundle and get Root Dictionary out of it
http://www.riptutorial.com/ 537
// Your dictionary contains an array of dictionary // Now pull an Array out of it.
You have already created a plist. This plist will remain same in app. If you want to edit the data in
this plist, add new data in plist or remove data from plist, you can't make changes in this file.
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
http://www.riptutorial.com/ 538
Directory.
http://www.riptutorial.com/ 539
Chapter 130: Profile with Instruments
Introduction
Xcode includes a performance tuning application named Instruments that you can use to profile
your application using all sorts of different metrics. They have tools to inspect CPU usage,
memory usage, leaks, file/network activity, and energy usage, just to name a few. It’s really easy
to start profiling your app from Xcode, but it’s sometimes not as easy to understand what you see
when it’s profiling, which deters some developers from being able to use this tool to its fullest
potential.
Examples
Time Profiler
The first instrument you’ll look at is the Time Profiler. At measured intervals, Instruments will halt
the execution of the program and take a stack trace on each running thread. Think of it as
pressing the pause button in Xcode’s debugger.Here’s a sneak preview of the Time Profiler :-
http://www.riptutorial.com/ 540
This screen displays the Call Tree. The Call Tree
http://www.riptutorial.com/ 541
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:
http://www.riptutorial.com/ 542
These are all different templates that come with Instruments.
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
http://www.riptutorial.com/ 543
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:
http://www.riptutorial.com/ 544
http://www.riptutorial.com/ 545
. The red ‘record’ button will stop & start the app currently being profiled when it is clicked (it
toggles between a record and stop icon). The pause button does exactly what you’d expect and
pauses the current execution of the app.
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!
Now, scroll up and down the list a few times so that you’ve got a good amount of data in the Time
Profiler. You should notice the numbers in the middle of the screen changing and the graph filling
in; this tells you that CPU cycles are being used.
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:
http://www.riptutorial.com/ 546
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 time-consuming methods.
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.
http://www.riptutorial.com/ 547
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:
http://www.riptutorial.com/ 548
Now click the small arrow to the left of the applyTonalFilter row at the top of the table. This will
unfold the Call Tree to show the caller of applyTonalFilter. You may need to unfold the next row
too; when profiling Swift, there will sometimes be duplicate rows in the Call Tree, prefixed with
@objc. You’re interested in the first row that’s prefixed with your app’s target name
(InstrumentsTutorial):
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.
http://www.riptutorial.com/ 549
This time you’ll notice two tracks. One is called Allocations, and one is called Leaks. The
Allocations track will be discussed in detail later on; the Leaks track is generally more useful in
Objective-C, and won’t be covered in this tutorial. So what bug are you going to track down next?
There’s something hidden in the project that you probably don’t know is there. You’ve likely heard
about memory leaks. But what you may not know is that there are actually two kinds of leaks:
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:
http://www.riptutorial.com/ 550
Press it and you will see a red flag appear in the track, like so:
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
http://www.riptutorial.com/ 551
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.
It’s possible that this growth is not just due to your app; it could be something in the depths of
UIKit that’s holding onto memory. Give the system frameworks and your app a chance to clear
their memory first before pointing a finger at either one.
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.
http://www.riptutorial.com/ 552
Chapter 131: Push Notifications
Syntax
• UIUserNotificationSettings.types: UIUserNotificationType // A bitmask of the notification
types that your app is allowed to use
• UIUserNotificationSettings.categories: Set // The app’s registered groups of actions
Parameters
Parameter Description
Examples
Registering device for Push Notifications
To register your device for push notifications, add the following code to your AppDelegate file in
didFinishLaunchingWithOptions method:
Swift
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
http://www.riptutorial.com/ 553
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
[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,
http://www.riptutorial.com/ 554
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
http://www.riptutorial.com/ 555
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError
error: NSError) {
print(error)
}
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
In Swift3:
@objc(userNotificationCenter:willPresentNotification:withCompletionHandler:) @available(iOS
10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification:
UNNotification, withCompletionHandler completionHandler: @escaping
(UNNotificationPresentationOptions) -> Void)
{
//To show notifications in foreground.
print("Userinfo2 \(notification.request.content.userInfo)")
}
Objective-C
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
http://www.riptutorial.com/ 556
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
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.
It is always a good practice to test how push notifications work even before you have your server
side ready for them, just to make sure that everything is set up correctly on your side. It is quite
easy to send yourself a push notification using a following PHP script.
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)
http://www.riptutorial.com/ 557
4. cd to the folder in Terminal and run command 'php send_push'
5. Receive the notification on your device
<?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;
http://www.riptutorial.com/ 558
// Close the connection to the server
fclose($fp);
Generating a .pem certificate from your .cer file, to pass on to the server
developer
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.
Use the following piece of code to set the badge number from within your application (suppose
someNumber has been declared before):
http://www.riptutorial.com/ 559
Objective-C
Swift
UIApplication.shared.applicationIconBadgeNumber = someNumber
Objective-C
Swift
UIApplication.sharedApplication().unregisterForRemoteNotifications()
this is similar to going into the setting of your phone and manually switching off Notifications for the
application.
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.
2- Go to "Certificates"
9- From Keychain Access menu, click Certificate Assistant -> Request a Certificate from a
Certificate Authority
http://www.riptutorial.com/ 561
12- Leave CA Email Address empty
15- Download the generated file by Apple and open it while Keychain Access is open
Swift
http://www.riptutorial.com/ 562
Registering for (Non Interactive) Push Notification
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.
Once user clicks on a push notification, the following callback function will be called. You can
parse the JSON to get any specific info sent from backend that will helps you in deep linking:
Swift
http://www.riptutorial.com/ 563
print("Received notification: \(userInfo)")
}
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
http://www.riptutorial.com/ 564
NSLog(@"%@", notification.request.content.userInfo);
}
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)())completionHandler
{
http://www.riptutorial.com/ 565
Chapter 132: QR Code Scanner
Introduction
QR (Quick Response) codes are two-dimensional barcodes which are widely used on machine-
readable optical labels. iOS do provide a way to read the QR codes by using AVFoundation
framework from iOS 7 onwards. This framework provides set of API's to setup/open the camera
and read QR codes from the camera feed.
Examples
UIViewController scanning for QR and displaying video input
import AVFoundation
class QRScannerViewController: UIViewController,
AVCaptureMetadataOutputObjectsDelegate {
func viewDidLoad() {
self.initCaptureSession()
}
self.videoPreviewLayer =
AVCaptureVideoPreviewLayer(session: self.captureSession)
self.videoPreviewLayer?
.videoGravity = AVLayerVideoGravityResizeAspectFill
self.videoPreviewLayer?.frame =
self.view.layer.bounds
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
http://www.riptutorial.com/ 566
}
if let metadataObj =
metadataObjects[0] as? AVMetadataMachineReadableCodeObject {
guard metadataObj.type == AVMetadataObjectTypeQRCode else {
return
}
Prior to iOS 7 when you want to scan a QR code, we might need to rely on third party frameworks
or libraries like zBar or zXing. But Apple introduced AVCaptureMetaDataOutput from iOS 7 for reading
barcodes.
Step 1
Import AVFoundation framework and confirm to AVCaptureMetadataOutputObjectsDelegate protocol
import AVFoundation
class ViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate
http://www.riptutorial.com/ 567
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
Implement AVCaptureMetadataOutputObjectsDelegate delegate method to read the QR code
// 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.
http://www.riptutorial.com/ 568
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.
http://www.riptutorial.com/ 569
Chapter 133: Realm
Remarks
Adding a new RLMObject to an existing Realm - Schema and Migrations
Adding new model classes to a Realm does not require a migration or a schema version bump;
only making changes to an existing Realm.
Examples
RLMObject Base Model Class with Primary Key - Objective-C
An example of a RLMObject base model class that uses a primary key and some generic default
properties. Subclasses can then set metadata specific to their needs.
@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
http://www.riptutorial.com/ 570
Chapter 134: Resizing UIImage
Parameters
Examples
Resize any image by size & quality
http://www.riptutorial.com/ 571
Chapter 135: Rich Notifications
Introduction
The Rich Notifications lets you customize the appearance of local and remote notifications when
they appear on the user’s device.Rich notification mostly includes UNNotificationServiceExtension
and UNNotificationContentExtension ie displaying the normal notification in an extended manner
Examples
Creating a simple UNNotificationContentExtension
Step 1
Making the environment suitable for Notification. Make sure you enabled Background Modes and
Push Notification
http://www.riptutorial.com/ 572
http://www.riptutorial.com/ 573
http://www.riptutorial.com/ 574
Step 2: Creating an UNNotificationContentExtension
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
http://www.riptutorial.com/ 575
http://www.riptutorial.com/ 576
• UNNotificationDefaultContentHidden: This boolean determines whether the default body of
the notification is to be hidden or not
• UNNotificationCategory: Category is created in UNUserNotificationCenter in your application.
Here it can be either a string or an array of strings, so each category can gave different types
of data from which we can create different UI's. The payload we send must contain the
category name in order to display this particular extension
in your application. Here it can be either a string or an array of strings, so each category can
gave different types of data from which we can create different UI's. The payload we send
must contain the category name in order to display this particular extension
• UNNotificationExtensionInitialContentSizeRatio: The size of the initial content ie when
displaying the ContentExtension for the first time the initial size with respect to width of the
device. here 1 denotes the height will be equal to the width
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"
http://www.riptutorial.com/ 577
Step 6: Configuring the ContentExtension
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
http://www.riptutorial.com/ 578
http://www.riptutorial.com/ 579
UNNotificationExtensionOverrideDefaultTitle as YES. In step 3 we gave
UNNotificationExtensionDefaultContentHidden as NO if its YES then the notification will look like
images 3 and 4.
http://www.riptutorial.com/ 580
Chapter 136: Runtime in Objective-C
Examples
Using Associated Objects
Associated objects are useful when you want to add functionality to existing classes which
requires holding state.
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
http://www.riptutorial.com/ 581
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()
}
}
http://www.riptutorial.com/ 582
Chapter 137: Safari Services
Examples
Implement SFSafariViewControllerDelegate
You should implement SFSafariViewControllerDelegate so that your class is notified when the user
hits the Done button on the SafariViewController and you can dismiss it as well.
You can add items to a user's Reading List in Safari by calling the addItem method on the
SSReadingList singleton.
The default Reading List can be nil if access to the Reading List is not permitted.
http://www.riptutorial.com/ 583
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.
import SafariServices
//Objective-C
@import SafariServices;
Optionally you can also tell SafariViewController to enter reading mode if possible once it's done
loading.
http://www.riptutorial.com/ 584
Chapter 138: Security
Introduction
Security in iOS is related to data security, transport security, code security, etc
Examples
Transport Security using SSL
iOS apps needs to be written in a way to provide security to data which is being transported over
network.
SSL is the common way to do it.
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!))
}
http://www.riptutorial.com/ 585
}
@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.
If we want our app data to be protected against iTunes backups, we have to skip our app data
from being backed up in iTunes.
Whenever iOS device backed up using iTunes on macOS, all the data stored by all the apps is
copied in that backup and stored on backing computer.
But we can exclude our app data from this backup using URLResourceKey.isExcludedFromBackupKey
key.
Here is the directory structure of our app:
http://www.riptutorial.com/ 586
Note: Generally sensitive data is stored in 'Application Support' directory.
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.
iExplorer is good one to explore iTunes backups.
http://www.riptutorial.com/ 587
Chapter 139: Segues
Examples
An Overview
Attributes
Swift
References:
PrepareForSegue:
func prepareForSegue(_ segue:UIStoryboardSegue, sender sender:AnyObject?)
Parameters
segue: The segue object.
http://www.riptutorial.com/ 588
Example in Swift
Perform a task if the identifier of the segue is "SomeSpecificIdentifier"
ShouldPerformSegueWithIdentifier:
func shouldPerformSegueWithIdentifier(_ identifier:String, sender sender:AnyObject?) -> Bool
Determines whether the segue with the specified identifier should be performed.
Parameters
Identifier: String that identifies the triggered segue
Example in Swift
Only perform segue if the identifier is "SomeSpecificIdentifier"
Unwind Segues
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]
http://www.riptutorial.com/ 589
Required signature of an unwind segue
Objective C:
-(IBAction)prepareForUnwind:(UIStoryboardSegue *)segue {
}
Swift:
PerformSegueWithIdentifier:
Initiates the segue with the specified identifier from the current view controller's
storyboard file
Parameters
Identifier: String that identifies the triggered segue
Example in Swift
Performing a segue with identifier "SomeSpecificIdentifier" from a table view row selection:
http://www.riptutorial.com/ 590
Chapter 140: Set View Background
Examples
Set View background
Objective C:
Swift:
view.backgroundColor! = UIColor.redColor()
Swift 3
view.backgroundColor = UIColor.redColor
Objective-C
UIGraphicsBeginImageContext(self.view.frame.size);
[[UIImage imageNamed:@"image.png"] drawInRect:self.view.bounds];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.view.backgroundColor = [UIColor colorWithPatternImage:image];
To create a background with a gradient you can use the CAGradientLayer class:
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)
}
http://www.riptutorial.com/ 591
}
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.
http://www.riptutorial.com/ 592
Chapter 141: Simulating Location Using GPX
files iOS
Examples
Your .gpx file: MPS_HQ.gpx
<gpx xmlns="http://www.topografix.com/GPX/1/1"
xmlns:gpxx = "http://www.garmin.com/xmlschemas/GpxExtensions/v3"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.topografix.com/GPX/1/1
http://www.topografix.com/GPX/1/1/gpx.xsd
http://www.garmin.com/xmlschemas/GpxExtensions/v3
http://www8.garmin.com/xmlschemas/GpxExtensions/v3/GpxExtensionsv3.xsd"
version="1.1"
creator="gpx-poi.com">
<wpt lat="38.9072" lon="77.0369">38.9072/-77.0369
<time>2015-04-16T22:20:29Z</time>
<name>Washington, DC</name>
<extensions>
<gpxx:WaypointExtension>
<gpxx:Proximity>10</gpxx:Proximity>
<gpxx:Address>
<gpxx:StreetAddress>Washington DC</gpxx:StreetAddress>
<gpxx:City>Washington</gpxx:City>
<gpxx:State>DC</gpxx:State>
<gpxx:Country>United States</gpxx:Country>
<gpxx:PostalCode> 20005 </gpxx:PostalCode>
</gpxx:Address>
</gpxx:WaypointExtension>
</extensions>
1. Go to Edit Scheme.
2. Select Run -> Options.
3. Check "Allow Location Simulation".
4. Select the *.GPX File Name from the "Default Location" drop down list.
http://www.riptutorial.com/ 593
Read Simulating Location Using GPX files iOS online:
http://www.riptutorial.com/ios/topic/9883/simulating-location-using-gpx-files-ios
http://www.riptutorial.com/ 594
Chapter 142: Simulator
Introduction
iOS, watchOS and tvOS Simulators are great ways to test your apps without using an actual
device. Here we will talk about working with Simulators.
Remarks
There is no simulator for macOS, because Xcode is run on macOS and whenever
needed, it will run the apps native.
Getting Help
You could always visit Simulator help at Help -> Simulator help:
http://www.riptutorial.com/ 595
http://www.riptutorial.com/ 596
Chapter 143: Simulator Builds
Introduction
Where to find simulator build ?
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:
Examples
Installing the build manually on simulator
http://www.riptutorial.com/ 597
Chapter 144: SiriKit
Remarks
• Photo Search (e.g. Look for beach photos taken last summer in MyApp)
• Payments (e.g. Send $20 to John for dinner last night using MyApp)
• Climate and Radio (specifically designed for CarPlay, e.g. Set the heater to 72 degrees)
Examples
Adding Siri Extension to App
To integrate Siri capabilities in your app, you should add an extensions as you would do while
creating an iOS 10 Widget (old Today View Extension) or a custom keyboard.
Adding capability
1- In the project settings, select your iOS app target and go to Capabilities tab
According to Apple:
http://www.riptutorial.com/ 598
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.
http://www.riptutorial.com/ 599
Read SiriKit online: http://www.riptutorial.com/ios/topic/5869/sirikit
http://www.riptutorial.com/ 600
Chapter 145: Size Classes and Adaptivity
Remarks
As you build adaptive apps, keep in mind the limitations of size classes: they are generalizations,
not specific guides for exact pixel sizes or devices. Never attempt to determine what device your
app is running on, or whether it's in a split-screen mode, based on the size classes.
Instead, make high-level layout decisions on size class, and use Auto Layout to change precise
view frames. (See also the UIViewController method viewWillTransition(to:with:) for a more
precise notification of how big a controller's view will be after a transition.)
Examples
Trait Collections
In an iOS app, your user interface can take on one of a few different general shapes and sizes.
These are defined using size classes, which are available through a view or view controller's trait
collection.
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.
Making an app adaptive – that is, responding to size class changes by changing your layout –
http://www.riptutorial.com/ 601
often involves lots of help from the Auto Layout system. One of the primary ways apps become
adaptive is by updating the active Auto Layout constraints when a view's size class changes.
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)
}
view.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
A key piece of adaptivity in a modern iOS app is supporting multitasking on iPad. By default, apps
created in Xcode 7 and newer will be configured to support multitasking: they'll have a
LaunchScreen.storyboard file that uses Auto Layout.
The easiest way for existing apps to opt in to multitasking is to create such a storyboard, then set it
http://www.riptutorial.com/ 602
as the project's Launch Screen:
Once your app supports iPad multitasking, audit existing views and view controllers to make sure
that they use Auto Layout and can support a variety of size class combinations.
http://www.riptutorial.com/ 603
Chapter 146: Size Classes and Adaptivity
Remarks
For more details ( Size Classes and Adaptivity through Storyboard) of using auto layout for
adaptivity in iOS, we can follow the apple developer site link.
We can also add constraints Programatically using Visual Format Language as described here
at apple developer site.
Examples
Size Classes and Adaptivity through Storyboard
We can add adaptivity to any subclass of UIView which we add on view controller in nib file.
Lets take an example of adding adaptivity using size classes to a view.
http://www.riptutorial.com/ 604
http://www.riptutorial.com/ 605
constraints as:
http://www.riptutorial.com/ 606
http://www.riptutorial.com/ 607
http://www.riptutorial.com/ios/topic/6424/size-classes-and-adaptivity
http://www.riptutorial.com/ 608
Chapter 147: SLComposeViewController
Examples
SLComposeViewController for Twitter, facebook, SinaWelbo and
TencentWelbo
Objective-C
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
http://www.riptutorial.com/ 609
[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];
[self presentViewController:alertCont animated:YES completion:nil];
UIAlertAction *okay=[UIAlertAction actionWithTitle:@"Okay"
style:UIAlertActionStyleDefault handler:nil];
[alertCont addAction:okay];
}
SinaWeibo
//- - SinaWeibo - -
if([SLComposeViewController isAvailableForServiceType:SLServiceTypeSinaWeibo]){
SLComposeViewController *SinaWeiboVC=[SLComposeViewController
composeViewControllerForServiceType:SLServiceTypeSinaWeibo];
[SinaWeiboVC setInitialText:text];
TencentWeibo
http://www.riptutorial.com/ 610
Chapter 148: Snapshot of UIView
Examples
Getting the Snapshot
- (UIImage *)getSnapshot
{
UIScreen *screen = [UIScreen mainScreen];
CGRect bounds = [self.view bounds];
UIGraphicsBeginImageContextWithOptions(bounds.size, false, screen.scale);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
[self.view drawViewHierarchyInRect:bounds afterScreenUpdates:YES];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
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{
http://www.riptutorial.com/ 611
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)];
CGFloat oldScale = img.contentScaleFactor;
img.contentScaleFactor = getImageForEdit.scale;
[img drawViewHierarchyInRect:CGRectMake(0, 0, newSize.width, newSize.height)
afterScreenUpdates:YES];
img.contentScaleFactor = oldScale;
UIImage *combImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
imageData = UIImageJPEGRepresentation(combImage, 1);
}
http://www.riptutorial.com/ 612
Chapter 149: SqlCipher integration
Introduction
SQLite is already a popular API for persistent data storage in iOS apps so the upside for
development is obvious. As a programmer you work with a stable, well-documented API that
happens to have many good wrappers available in Objective-C, such as FMDB and Encrypted
Core Data. All security concerns are cleanly decoupled from application code and managed by the
underlying framework.
Remarks
1. Open the Terminal, switch into your project's root directory and checkout the SQLCipher
project code using Git:
2. Right click on the project and choose "Add Files to "My App"" (the label will vary depending
on your app's name). Since we cloned SQLCipher directly into the same folder as your iOS
app you should see a sqlcipher folder in your root project folder. Open this folder and select
sqlcipher.xcodeproj
http://www.riptutorial.com/ 613
3. Select the Build Settings pane. In the search field, type in "Header Search Paths". Double-
click on the field under the target column and add the following path:
$(PROJECT_DIR)/sqlcipher/src
4. Start typing "Other Linker Flags" into the search field until the setting appears, double click to
edit it, and add the following value: $(BUILT_PRODUCTS_DIR)/libsqlcipher.a
5. Start typing "Other C Flags" into the search field until the setting appears, double click to edit
it, and in the pop-up add the following value: -DSQLITE_HAS_CODEC
6. Expand Target Dependencies and click on the + button at the end of the list. In the browser
that opens, select the sqlcipher static library target:
7. Expand Link Binary With Libraries, click on the +button at the end of the list, and select the
libsqlcipher.a library.
http://www.riptutorial.com/ 614
8. Finally, also under Link With Libraries, add Security.framework.
Examples
Integration of code:
-(void)checkAndOpenDB{
sqlite3 *db;
NSString *strPassword = @"password";
- (NSURL *)databaseURL
{
http://www.riptutorial.com/ 615
NSArray *URLs = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask];
NSURL *directoryURL = [URLs firstObject];
NSURL *databaseURL = [directoryURL URLByAppendingPathComponent:@"database.sqlite"];
return databaseURL;
}
http://www.riptutorial.com/ 616
Chapter 150: StoreKit
Examples
Get localized product information from the App Store
Get localized product information from a set of product identifier strings using SKProductsRequest:
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
http://www.riptutorial.com/ 617
Chapter 151: Storyboard
Introduction
Normally, view controllers in a storyboard are instantiated and created automatically in response
to actions defined within the storyboard itself. However, you can use a storyboard object to
instantiate the initial view controller in a storyboard file or instantiate other view controllers that you
want to present programmatically. Below you will find examples of both use cases.
Examples
Initialize
//Swift
let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
//Objective-c
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle
mainBundle]];
//Swift
let initialScreen = storyboard.instantiateInitialViewController()
//Objective-c
UIViewController *initailScreen = [storyboard instantiateInitialViewController];
Fetch ViewController
//Swift
let viewController = storyboard.instantiateViewControllerWithIdentifier("identifier")
//Objective-c
UIViewController *viewController = [storyboard
instantiateViewControllerWithIdentifier:@"identifier"];
http://www.riptutorial.com/ 618
Chapter 152: Swift and Objective-C
interoperability
Examples
Using Objective-C Classes in Swift
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:
http://www.riptutorial.com/ 619
Note
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
http://www.riptutorial.com/ 620
Step 3: Add Objective-C Header -- .h
In CustomObject.h
#import <Foundation/Foundation.h>
- (void) someMethod;
@end
In CustomObject.m
#import "CustomObject.h"
@implementation CustomObject
- (void) someMethod {
NSLog(@"SomeMethod Ran");
}
@end
In YourProject-Bridging-Header.h:
#import "CustomObject.h"
In SomeSwiftFile.swift:
http://www.riptutorial.com/ 621
Add a .swift file to your project, and name it MySwiftObject.swift
In MySwiftObject.swift:
import Foundation
init() {}
In SomeRandomClass.m:
#import "<#YourProjectName#>-Swift.h"
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.
http://www.riptutorial.com/ 622
Chapter 153: Swift: Changing the
rootViewController in AppDelegate to present
main or login/onboarding flow
Introduction
It is often useful to present a first-run experience to new users of your App. This could be for any
number of reasons, such as prompting them to sign in (if required for your situation), explaining
how to use the App, or simply informing them of new features in an update (as Notes, Photos and
Music do in iOS11).
Remarks
Firstly, as you are dealing with multiple flows, this is where Storyboards can be used effectively.
By default your Application uses Main.storyboard for your primary flow. Your onboarding/alternative
flow can be contained in a secondary storyboard, eg. Onboarding.storyboard
When your App launches, you can determine which flow should be presented. The logic for this
can be contained in your AppDelegate:
In order to show the Onboarding flow, it's worth considering how you'd like to handle the
experience of dismissing it once the person using it has completed the journey, and which is
semantically correct for what you are trying to create.
Approaches:
The two main approaches are:
http://www.riptutorial.com/ 623
2. Present the Onboarding flow as a modal journey, overlapping the Main flow.
Examples
Option 1: Swap the Root View Controller (Good)
There are benefits to switching the root view controller, although the transition options are limited
to those supported by UIViewAnimationOptions, so depending on how you wish to transition between
flows might mean you have to implement a custom transition - which can be cumbersome.
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)
}
}
}
In the most straightforward implementation, the Onboarding flow can simply be presented in a
modal context, since semantically the User is on a single journey.
http://www.riptutorial.com/ 624
Consider creating a modal context only when it’s critical to get someone’s attention,
when a task must be completed or abandoned to continue using the app, or to save
important data.
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)
}
}
}
http://www.riptutorial.com/ 625
Chapter 154: SWRevealViewController
Remarks
Using the SWRevealViewController class as the main navigation might not always result in the
best user experience. If the sidebar contains only 5 or less entries (or the content can be
compressed into 5 or less entries), you should consider using the default tab bar.
The tab bar is intuitive and allows the user to quickly change between views/contexts. On the
other hand, the sidebar navigation can perform more actions than switching the view/context and
uses less space when collapsed.
For more information check out Apple's iOS Human Interface Guidelines.
Examples
Setting up a basic app with SWRevealViewController
Create a basic application with single view application template with swift as language
and add
#import "SWRevealViewController.h"
http://www.riptutorial.com/ 626
Then rename the viewController on files to MainViewController and add new ViewController with
RightViewController name
http://www.riptutorial.com/ 627
then we add two segues from SWRevealViewController to MainViewController and from
SWRevealViewController to RightViewController, then we need to select the first (from
SWRevealViewController to MainViewController) and edit properties
http://www.riptutorial.com/ 628
after this we need to do the same with the segue (from SWRevealViewController to
RightViewController)
http://www.riptutorial.com/ 629
then on MainViewController add this line on viewDidLoad method
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
http://www.riptutorial.com/ 630
Chapter 155: UI Testing
Syntax
• XCUIApplication() // Proxy for an application. The information identifying the application is
specified in the Xcode target settings as the "Target Application".
• XCUIElement() // A user interface element in an application.
Examples
Adding Test Files to Xcode Project
Setps:
Accessibility Identifier
http://www.riptutorial.com/ 631
When Accessibility enabled in Utilities
• Select storyboard.
• Expand the Utilities
• Select Identity Inspector
• Select your element on storyboard
• Add new Accessibility Identifier (in example addButton)
http://www.riptutorial.com/ 632
Setting up in UITest file
import XCTest
//Views
//Buttons
app.launch()
//Views
view = app.otherElements["view"]
//Buttons
addButton = app.buttons["addButton"]
}
func testMyApp() {
addButton.tap()
view.tap()
}
}
http://www.riptutorial.com/ 633
let view = app.otherElements["view"]
UILabel
UIStackView
UITableView
UITableViewCell
UITableViewCell elements
UICollectionView
UIButton, UIBarButtonItem
let button = app.buttons["button"]
let barButtonItem = app.buttons["barButtonItem"]
UITextField
• normal UITextField
• password UITextField
http://www.riptutorial.com/ 634
UITextView
UISwitch
Alerts
app.launch()
}
Terminating application
func testStacOverFlowApp() {
app.terminate()
}
Rotate devices
XCUIDevice.shared().orientation = .landscapeLeft
http://www.riptutorial.com/ 635
XCUIDevice.shared().orientation = .portrait
http://www.riptutorial.com/ 636
Chapter 156: UIActivityViewController
Parameters
Contains array of object to perform the activity. This array must not be
activityItems
nil and must contain at least one object.
Examples
Initializing the Activity View Controller
Objective-C
Swift
http://www.riptutorial.com/ 637
Chapter 157: UIAlertController
Remarks
A UIAlertController object displays an alert message to the user. This class replaces
the UIActionSheet and UIAlertView classes for displaying alerts. After configuring the
alert controller with the actions and style you want, present it using the
presentViewController:animated:completion: method.
UIAlertController in Swift
Examples
AlertViews with UIAlertController
UIAlertView and UIActionSheet are Deprecated in iOS 8 and Later. So Apple introduced a new
controller for AlertView and ActionSheet called UIAlertController , changing the preferredStyle, you
can switch between AlertView and ActionSheet. There is no delegate method for it because all
button events are handled in their blocks.
Simple AlertView
Swift:
let alert = UIAlertController(title: "Simple", message: "Simple alertView demo with Cancel and
OK.", preferredStyle: .alert)
Objective-C:
http://www.riptutorial.com/ 638
}];
[alertController addAction:cancelAction];
[alertController addAction:okAction];
[self presentViewController:alertController animated: YES completion: nil];
Destructive AlertView
Swift:
let alert = UIAlertController(title: "Simple", message: "Simple alertView demo with Cancel and
OK.", preferredStyle: .alert)
Objective-C:
[alertController addAction:destructiveAction];
[alertController addAction:okAction];
[self presentViewController:alertController animated: YES completion: nil];
http://www.riptutorial.com/ 639
Adding Text Field in UIAlertController like a prompt Box
Swift
}
defaultAction.isEnabled = false
alert.addAction(defaultAction)
alert.addTextFieldWithConfigurationHandler { (textField) in
textField.delegate = self
}
Objective-C
preferredStyle:UIAlertControllerStyleAlert];
defaultAction.enabled = NO;
[alert addAction:defaultAction];
http://www.riptutorial.com/ 640
Action Sheets with UIAlertController
With UIAlertController, action sheets like the deprecated UIActionSheet are created with the same
API as you use for AlertViews.
let alertController = UIAlertController(title: "Demo", message: "A demo with two buttons",
preferredStyle: UIAlertControllerStyle.actionSheet)
Objective-C
Swift
Objective-C
http://www.riptutorial.com/ 641
UIAlertAction * okAction = [UIAlertAction actionWithTitle:@"Okay"
style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
//action when pressed button
}];
Swift
alertController.addAction(cancelAction)
alertController.addAction(okAction)
Objective-C
[alertController addAction:cancelAction];
[alertController addAction:okAction];
Swift
Objective-C
http://www.riptutorial.com/ 642
Action Sheet with destructive button
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
Objective-C
Swift
http://www.riptutorial.com/ 643
presentViewController(alert, animated: true) {
let delay_s:Double = 2
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delay_s * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue()) {
alert.dismissViewControllerAnimated(true, completion: nil)
}
}
Alert controller has a property which is used to put emphases on an action added in the alert
controller. This property can be used to highlight a particular action for user attention.For objective
C;
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];
http://www.riptutorial.com/ 644
Alert Controller with preferred action not set.The NO button is not highlighted.
One Button
http://www.riptutorial.com/ 645
Swift
Two Buttons
http://www.riptutorial.com/ 646
Swift
http://www.riptutorial.com/ 647
Three Buttons
Swift
http://www.riptutorial.com/ 648
}
}
Swift
// do something like...
self.launchMissile()
}))
Notes
• 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.
http://www.riptutorial.com/ 649
Chapter 158: UIAppearance
Examples
Set appearance of all instances of the class
To customize appearance of all instances of a class, access appearance proxy of the desired
class. For example:
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:
http://www.riptutorial.com/ 650
[UILabel appearance].backgroundColor = [UIColor greenColor];
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:
http://www.riptutorial.com/ 651
[UILabel appearanceWhenContainedInInstancesOfClasses:@[[ViewController
class]]].backgroundColor = [UIColor blueColor];
http://www.riptutorial.com/ 652
Chapter 159: UIBarButtonItem
Parameters
Parameter Description
Remarks
Referencing self.navigationItem assumes that the UIViewController is embedded inside a
UINavigationController.
Examples
Creating a UIBarButtonItem in the Interface Builder
The example below shows how to add a navigation bar button (called a UIBarButtonItem) in the
Interface Builder.
http://www.riptutorial.com/ 653
Alternatively, you could add a UINavigationBar from the Object Library.
http://www.riptutorial.com/ 654
Set the Attributes
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.
http://www.riptutorial.com/ 655
Add an IB Action
Control drag from the UIBarButtonItem to the View Controller to add an @IBAction.
print("How refreshing!")
}
That's it.
Notes
• This example originally comes from this Stack Overflow answer.
Provided that barButtonItem has a non-null image property (e.g. set in the Interface Builder).
Objective-C
barButtonItem.image = [barButtonItem.image
imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
Creating a UIBarButtonItem
//Swift
let barButtonItem = UIBarButtonItem(title: "Greetings!", style: .Plain, target: self, action:
#selector(barButtonTapped))
self.navigationItem.rightBarButtonItem = barButtonItem
//Objective-C
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Greetings!"
http://www.riptutorial.com/ 656
style:UIBarButtonItemStylePlain target:self action:@selector(barButtonTaped)];
self.navigationItem.rightBarButtonItem = barButtonItem;
http://www.riptutorial.com/ 657
Chapter 160: UIBezierPath
Examples
How to apply corner radius to rectangles drawn by UIBezierPath
http://www.riptutorial.com/ 658
CGSizeMake(11, 11)];
[rectanglePath closePath];
[UIColor.grayColor setFill];
[rectanglePath fill];
http://www.riptutorial.com/ 659
[rectanglePath fill];
Swift:
http://www.riptutorial.com/ 660
UIBezierPath* rectanglePath = [UIBezierPath bezierPathWithRect: CGRectMake(0,0,50,50)];
[UIColor.grayColor setFill];
[rectanglePath fill];
Swift:
Swift:
[UIColor.grayColor setFill];
[ovalPath fill];
http://www.riptutorial.com/ 661
Swift:
UIColor.grayColor().setFill()
ovalPath.fill()
Swift:
UIBezierPath + AutoLayout
For bezier path to get resized based on the view frame, override the drawRect of view that you are
drawing the bezier path :
- (void)drawRect:(CGRect)frame
{
UIBezierPath* rectanglePath = [UIBezierPath bezierPathWithRect:
CGRectMake(CGRectGetMinX(frame), CGRectGetMinY(frame), CGRectGetWidth(frame),
CGRectGetHeight(frame))];
[UIColor.grayColor setFill];
http://www.riptutorial.com/ 662
[rectanglePath fill];
}
http://www.riptutorial.com/ 663
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
UIRectClip(rectanglePath.bounds);
CGContextSetShadowWithColor(context, CGSizeZero, 0, NULL);
[opaqueShadow setFill];
[rectanglePath fill];
CGContextEndTransparencyLayer(context);
}
CGContextEndTransparencyLayer(context);
CGContextRestoreGState(context);
This example shows the process from designing the shape you want to drawing it on a view. A
specific shap is used but the concepts you learn can be applied to any shape.
http://www.riptutorial.com/ 664
Design shape outline
You could do anything, but as an example I have chosen the shape below. It could be a popup key
on a keyboard.
http://www.riptutorial.com/ 665
• Black are line segments
• Light blue are arc segments
• Red are curves
• Orange dots are the control points for the curves
• Green dots are the points between path segments
• Dotted lines show the bounding rectangle
• Dark blue numbers are the segments in the order that they will be added programmatically
• line: addLineToPoint
• arc: addArcWithCenter
• curve: addCurveToPoint
http://www.riptutorial.com/ 666
4. Close the path with closePath
// *********************
// ***** 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))
http://www.riptutorial.com/ 667
// segment 9: line
path.addLineToPoint(CGPoint(x: 8, y: 26))
// *********************
// **** Bottom side ****
// *********************
return path
}
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()
http://www.riptutorial.com/ 668
func createBezierPath() -> UIBezierPath {
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:
http://www.riptutorial.com/ 669
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()
strokeColor.setStroke()
Further study
Excellent articles for understanding Bezier paths.
• 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.)
http://www.riptutorial.com/ 670
• 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
• This example originally comes from this Stack Overflow answer.
• In your actual projects you probably shouldn't use hard coded numbers, but rather get the
sizes from your view's bounds.
• pie view
- (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);
http://www.riptutorial.com/ 671
// reset angle
startAngle = endAngle;
}];
}
• column view
- (void)drawRect:(CGRect)rect {
http://www.riptutorial.com/ 672
NSArray *data = @[@300, @150.65, @55.3, @507.7, @95.8, @700, @650.65];
// 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)];
CGContextAddPath(cxtRef, rectPath.CGPath);
// 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);
}
}
http://www.riptutorial.com/ 673
Chapter 161: UIButton
Introduction
UIButton : UIControl intercepts touch events and sends an action message to a target object when
it's tapped. You can set the title, image, and other appearance properties of a button. In addition,
you can specify a different appearance for each button state.
Remarks
Button Types
A button’s type defines its basic appearance and behavior. After creating a button, you cannot
change its type. The most commonly used button types are the Custom and System types, but
use the other types when appropriate
• UIButtonTypeCustom
No button style.
• UIButtonTypeSystem
A system style button, such as those shown in navigation bars and toolbars.
• UIButtonTypeDetailDisclosure
• UIButtonTypeInfoLight
• UIButtonTypeInfoDark
• UIButtonTypeContactAdd
When creating a custom button—that is a button with the type custom—the frame of the button is
set to (0, 0, 0, 0) initially. Before adding the button to your interface, you should update the frame
to a more appropriate value.
http://www.riptutorial.com/ 674
Examples
Attaching a Method to a Button
Objective-C
-(void) someButtonAction{
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
Creating a UIButton
Swift
Objective C
Swift
http://www.riptutorial.com/ 675
let button = UIButton(type: .Custom)
Objective C
Set title
Swift
Objective C
Swift
Objective C
//Swift
button.setTitleColor(color, forControlState: controlState)
//Objective-C
[button setTitleColor:(nullable UIColor *) forState:(UIControlState)];
//Swift
http://www.riptutorial.com/ 676
button.setTitleColor(.blue, for: .normal)
//Objective-C
[button setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]
Swift
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)
http://www.riptutorial.com/ 677
Objective C
Disabling a UIButton
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
-(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
http://www.riptutorial.com/ 678
forControlEvents:UIControlEventTouchUpInside];
Swift
Setting Font
Swift
Objective C
To get the the exact size of a UIButton's text based on its font, use the function
intrinsicContentSize.
Swift
button.intrinsicContentSize.width
Objective-C
button.intrinsicContentSize.width;
Set Image
Swift
Objective C
Swift
Objective C
http://www.riptutorial.com/ 680
Chapter 162: UICollectionView
Examples
UICollectionViewDelegate setup and item selection
Sometimes, if an action should be bind to a collection view's cell selection, you have to implement
the UICollectionViewDelegate protocol.
Objective-C
Swift
Objective-C
Swift
As just an example we can set the background color of selected cell to green.
http://www.riptutorial.com/ 681
Objective-C
Swift
You can animate complex changes to your collection view using the performBatchUpdates method.
Inside the update block, you can specify several modifications to have them animate all at once.
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
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.
http://www.riptutorial.com/ 682
let from = [1, 2, 3, 4, 5]
let to = [1, 3, 6, 4, 5]
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)
Create a UICollectionView
Swift:
Objective C:
UICollectionView - Datasource
Every collection view must have a Datasource object. The Datasource object is the content that your
app will display within the UICollectionView. At a minimum, all Datasource objects must implement
the collectionView:numberOfItemsInSection: and collectionView:cellForItemAtIndexPath: methods.
Required Methods
Swift
http://www.riptutorial.com/ 683
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) ->
Int {
// Return how many items in section
let sectionArray = _data[section]
return sectionArray.count
}
//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 cell
}
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;
}
http://www.riptutorial.com/ 684
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
http://www.riptutorial.com/ 685
• UICollectionViewDataSourceand 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.
Make sure that your defaults in the Attribute Inspector are also
• 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
http://www.riptutorial.com/ 686
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.
http://www.riptutorial.com/ 687
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.
http://www.riptutorial.com/ 688
Making Improvements
If you want to make improvements on the appearance, see the original post that this example
comes from.
Further study
• A Simple UICollectionView Tutorial
• UICollectionView Tutorial Part 1: Getting Started
• UICollectionView Tutorial Part 2: Reusable Views and Cell Selection
Swift
http://www.riptutorial.com/ 689
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
- (void)createCollectionView {
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0,
0, self.view.frame.size.width, self.view.frame.size.height) collectionViewLayout:layout];
[collectionView setDataSource:self];
[collectionView setDelegate:self];
[self.view addSubview:collectionView];
}
Swift - UICollectionViewDelegateFlowLayout
// MARK: - UICollectionViewDelegateFlowLayout
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(collectionView: UICollectionView, layout collectionViewLayout:
UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSize(width: 50, height: 50)
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout:
UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout:
UICollectionViewLayout, minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat {
return 5.0
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout:
UICollectionViewLayout, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat {
return 5.0
}
}
Here we are managing multiple collection there delegate methods with didselect events.
// MARK: - UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection
section: Int) -> Int {
guard collectionView == collectionCategory else {
return arrOfProducts.count
}
return arrOfCategory.count
}
http://www.riptutorial.com/ 690
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath:
IndexPath) -> UICollectionViewCell {
return cell
}
// MARK: - UICollectionViewDelegateFlowLayout
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout:
UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if(UI_USER_INTERFACE_IDIOM() == .pad) {
itemWidth = collectionWidth / 4 - 1;
}
return CGSize(width: itemWidth, height: 50)
}
http://www.riptutorial.com/ 691
}
http://www.riptutorial.com/ 692
Chapter 163: UIColor
Examples
Undocumented Methods
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()
http://www.riptutorial.com/ 693
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:
You can set the opacity to a certain UIColor without creating a new one using the
init(red:_,green:_,blue:_,alpha:_) initializer.
Swift
Swift 3
Objective-C
By default, Interface Builder doesn't accept the CGColor datatype, so to allow adding a CGColor
http://www.riptutorial.com/ 694
using user defined attributes in interface builder; one may want to use an extension like this:
Swift Extension :
extension CALayer {
func borderUIColor() -> UIColor? {
return borderColor != nil ? UIColor(CGColor: borderColor!) : nil
}
Creating a UIColor
Swift
If the compiler already knows that the variable is an instance of UIColor you can skip the type
all together:
http://www.riptutorial.com/ 695
let hsbColor = UIColor(
hue: 0.4,
saturation: 0.3,
brightness: 0.7,
alpha: 1.0
)
Objective-C
http://www.riptutorial.com/ 696
imageNamed:@"myImage.png"]];
You can create a UIColor from a hexadecimal number or string, e.g. 0xff00cc, "#FFFFFF"
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
extension UIColor {
convenience init(hexCode: String) {
let hex =
hexCode.stringByTrimmingCharactersInSet(NSCharacterSet.alphanumericCharacterSet().invertedSet)
var int = UInt32()
NSScanner(string: hex).scanHexInt(&int)
let a, r, g, b: UInt32
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)
}
http://www.riptutorial.com/ 697
Example Usage:
Objective-C
Int Value
Example:
String Value
- (UIColor*) hex:(NSString*)hexCode {
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;
http://www.riptutorial.com/ 698
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:
The below code example will give you an adjusted version of that color where a higher percentage
will be brighter and a lower percentage will be darker.
Objective-C
CGFloat r, g, b, a;
if ([c getRed:&r green:&g blue:&b alpha:&a])
return [UIColor colorWithRed:MAX(r * percent, 0.0)
green:MAX(g * percent, 0.0)
blue:MAX(b * percent, 0.0)
alpha:a];
return nil;
}
http://www.riptutorial.com/ 699
Swift
return UIColor()
}
You can create a UIColor object using an image pattern by using the UIColor(patternImage:_)
method.
http://www.riptutorial.com/ 700
Lighter and Darker Shade of a given UIColor
The code example below demonstrate how you can get a lighter and darker shade of a given
color, useful in applications having dynamic themes
http://www.riptutorial.com/ 701
{
CGFloat r, g, b, a;
if ([c getRed:&r green:&g blue:&b alpha:&a])
return [UIColor colorWithRed:MIN(r + 0.2, 1.0)
green:MIN(g + 0.2, 1.0)
blue:MIN(b + 0.2, 1.0)
alpha:a];
return nil;
}
http://www.riptutorial.com/ 702
Chapter 164: UIControl - Event Handling with
Blocks
Examples
Introduction
Typically, when using UIControl or UIButton, we add a selector as a callback action for when an
event occurs on a button or control, such as the user pressing the button or touching the control.
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)
}
http://www.riptutorial.com/ 703
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 44))
button.addTarget(self, action: #selector(ButtonEvent.onButtonPress(_:)), for:
.touchUpInside)
self.view.addSubview(button)
}
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)
}
http://www.riptutorial.com/ 704
objc_setAssociatedObject(self, unsafeAddress(of: self), nil,
.OBJC_ASSOCIATION_ASSIGN)
}
}
The above is a simple extension on UIControl. It adds an inner private class that has a callback
func run(_ control: UIControl) that is used as the events' action.
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.
}
}
}
http://www.riptutorial.com/ 705
Read UIControl - Event Handling with Blocks online:
http://www.riptutorial.com/ios/topic/3180/uicontrol---event-handling-with-blocks
http://www.riptutorial.com/ 706
Chapter 165: UIDatePicker
Remarks
UIDatePicker does not inherit from UIPickerView, but it manages a custom picker-view object as a
subview.
Examples
Create a Date Picker
Swift
Objective-C
You can set the minimum and the maximum date that UIDatePicker can show.
Minimum date
Maximum date
Modes
http://www.riptutorial.com/ 707
• - The date picker displays hours, minutes, and (optionally) an AM/PM designation.
Time
• 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.
You can change property minuteInterval to set the interval displayed by the minutes wheel. The
default value is 1, the maximum value is 30.
The NSTimeInterval value of this property indicates the seconds from which the date picker in
countdown-timer mode counts down. If the mode of the date picker is not CountDownTimer, this
value is ignored. Maximum value is 86,399 seconds (23:59)
http://www.riptutorial.com/ 708
Chapter 166: UIDevice
Parameters
Property Description
systemVersion:
The current version of the operating system..
String
Remarks
The UIDevice class provides a Singleton instance representing the current device.
From this instance you can obtain information about the device such as assigned
name, device model, and operating-system name and version.
Examples
Get iOS device model name
Swift 2
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"
http://www.riptutorial.com/ 709
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"
http://www.riptutorial.com/ 710
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
}
}
}
// Stuff...
}
http://www.riptutorial.com/ 711
//Device Name iPhone OS
NSLog(@"System Version %@", deviceInfo.systemVersion);
//System Version 9.3
NSLog(@"Model %@", deviceInfo.model);
//Model iPhone
NSLog(@"Localized Model %@", deviceInfo.localizedModel);
//Localized Model iPhone
int device=deviceInfo.userInterfaceIdiom;
//UIUserInterfaceIdiomPhone=0
//UIUserInterfaceIdiomPad=1
//UIUserInterfaceIdiomTV=2
//UIUserInterfaceIdiomCarPlay=3
//UIUserInterfaceIdiomUnspecified=-1
NSLog(@"identifierForVendor %@", deviceInfo.identifierForVendor);
//identifierForVendor <__NSConcreteUUID 0x7a10ae20> 556395DC-0EB4-4FD5-BC7E-B16F612ECC6D
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
http://www.riptutorial.com/ 712
}
-(void)changedToLandscape
{
// Function Body
}
- (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
http://www.riptutorial.com/ 713
else if (d==3)
{
NSLog(@"Battery Full");
}
}
[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.");
}
}
http://www.riptutorial.com/ 714
Chapter 167: UIFeedbackGenerator
Introduction
UIFeedbackGenerator and its subclasses offers a public interface to the Taptic Engine® found on
iOS devices starting with iPhone 7. Haptics, branded Taptics, provide tactile feedback for on-
screen events. While many system controls provide haptics out-of-the-box, developers can use
UIFeedbackGenerator subclasses to add haptics to custom controls and other events.
UIFeedbackGenerator is an abstract class that should not be used directly, rather developers use
one of its subclasses.
Examples
Trigger Impact Haptic
Example shows how to trigger an impact haptic using UIImpactFeedbackGenerator after a button
press.
Swift
http://www.riptutorial.com/ 715
}
}
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:)
forControlEvents:UIControlEventTouchUpInside];
- (void)didPressButton:(UIButton *)sender
{
// Triggers haptic
[self.impactFeedbackGenerator impactOccurred];
}
@end
http://www.riptutorial.com/ 716
Chapter 168: UIFont
Introduction
UIFont is a class that is used for getting and setting font-related information. It inherits from
NSObject and conforms to Hashable, Equatable, CVarArg and NSCopying.
Examples
Declaring and initializing UIFont
To change a label's text font, you need to access its font property:
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:
http://www.riptutorial.com/ 717
Chapter 169: UIGestureRecognizer
Examples
UITapGestureRecognizer (Double Tap)
The double tap, like a single tap, also uses the UITapGestureRecognizer. You simply set the
numberOfTapsRequired to 2.
Swift
// Double Tap
let doubleTapGesture = UITapGestureRecognizer(target: self, action:
#selector(handleDoubleTap))
doubleTapGesture.numberOfTapsRequired = 2
doubleTapView.addGestureRecognizer(doubleTapGesture)
}
Notes
• A sample project can be found here.
• You could recognize a triple tap by setting the numberOfTapsRequired to 3.
UILongPressGestureRecognizer
The UILongPressGestureRecognizer lets you listen for a long press on a view. You can set the length
of delay before the action method is called.
Swift
// Long Press
let longPressGesture = UILongPressGestureRecognizer(target: self, action:
#selector(handleLongPress(_:)))
longPressView.addGestureRecognizer(longPressGesture)
}
http://www.riptutorial.com/ 718
label.text = "Long press recognized"
}
}
Notes
• A fuller sample project can be found here.
UISwipeGestureRecognizer
Swipe gestures allow you to listen for the user moving their finger across the screen quickly in a
certain direction.
Swift
// Swipe action
func handleSwipe(gesture: UISwipeGestureRecognizer) {
label.text = "Swipe recognized"
Objective-C
- (void)viewDidLoad
{
[super viewDidLoad];
UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self
action:@selector(handleSwipe:)];
UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self
action:@selector(handleSwipe:)];
http://www.riptutorial.com/ 719
// Setting the swipe direction.
[swipeLeft setDirection:UISwipeGestureRecognizerDirectionLeft];
[swipeRight setDirection:UISwipeGestureRecognizerDirectionRight];
}
//Handling Swipe Gesture Events
- (void)handleSwipe:(UISwipeGestureRecognizer *)swipe {
if (swipe.direction == UISwipeGestureRecognizerDirectionLeft) {
NSLog(@"Left Swipe");
}
if (swipe.direction == UISwipeGestureRecognizerDirectionRight) {
NSLog(@"Right Swipe");
}
Notes
• A fuller project example can be found here.
UIPinchGestureRecognizer
Pinches are a two fingered gesture where the fingers move closer or farther from each other. This
gesture is generally used for resizing a view.
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
}
}
http://www.riptutorial.com/ 720
Notes
• A fuller project example can be found here.
UIRotationGestureRecognizer
Two fingers rotating around a center can be listened for with the UIRotationGestureRecognizer. This
is generally used for rotating a view.
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
• A sample project can be found here.
Drag a gesture recognizer from the object library onto your view.
http://www.riptutorial.com/ 721
Control drag from the gesture in the Document Outline to your View Controller code in order to
make an Outlet and an Action.
http://www.riptutorial.com/ 722
Notes
• This example comes from this fuller sample project demonstrating gesture recognizers.
UIPanGestureRecognizer
Pan gesture recognizers detect dragging gestures. The following example adds an image to a
view controller and lets the user drag it around on screen.
Objective-C
- (void)viewDidLoad {
[super viewDidLoad];
- (void)handlePan:(UIPanGestureRecognizer *)recognizer {
CGPoint translation = [recognizer translationInView:self.view];
recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x,
recognizer.view.center.y + translation.y);
[recognizer setTranslation:CGPointZero inView:self.view];
}
Swift
http://www.riptutorial.com/ 723
override func viewDidLoad() {
super.viewDidLoad()
UITapGestureRecognizer
Initialize the UITapGestureRecognizer with a target, self in this case, and an action which is a
method that has a single parameter: a UITapGestureRecognizer.
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];
http://www.riptutorial.com/ 724
}
- (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
http://www.riptutorial.com/ 725
Chapter 170: UIImage
Remarks
Apple developer topic for UIImage
Examples
Apply UIColor to UIImage
Use same UIImage with multiple theme base app by just applying UIColor to UIImage instance as
following.
// *** Now Apply `tintColor` to `UIImageView` of UIImageView or UIButton and convert image in
given color ***
[btn setImage:imgMenu forState:UIControlStateNormal]; // Set UIImage in UIButton.
Now lets say you want to do same with UIImageView then use following code
extension UIImage {
func maskWithColor(color: UIColor) -> UIImage? {
http://www.riptutorial.com/ 726
//is it nil?
if let cImage = CGBitmapContextCreateImage(bitmapContext) {
let coloredImage = UIImage(CGImage: cImage)
return coloredImage
} else {
return nil
}
}
}
my_image.maskWithColor(UIColor.blueColor())
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:
http://www.riptutorial.com/ 727
let image = UIImage.gradientImageWithBounds(CGRect(x: 0, y: 0, width: 200, height: 200),
colors: [UIColor.yellowColor().CGColor, UIColor.blueColor().CGColor])
Objective-C:
UIGraphicsBeginImageContext(gradientLayer.bounds.size);
[gradientLayer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
Encoding
Decoding
Creating UIImage
http://www.riptutorial.com/ 728
let image = UIImage(named: "imageFromBundleOrAsset")
Objective-C
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
With UIColor
Swift
Objective-C
http://www.riptutorial.com/ 729
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Objective-C
Example:
Using Array:
Example:
self.myImageView.animationImages = imageArray;
Creating and returning an image object by loading the image data from the file at the specified
path.
Example:
Using Array:
Example
http://www.riptutorial.com/ 730
NSMutableArray *imageArray = [[NSMutableArray alloc] init];
In the example of a message bubble illustrated below: the corners of the image should remain
unchanged which is specified by UIEdgeInsets, but the borders and center of the image should
expand to cover the new size.
Comparing Images
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
http://www.riptutorial.com/ 731
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
// 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
let color = UIColor.redColor()
let size = CGSize(width: 200, height: 200)
Swift 3
let color = UIColor.red()
let size = CGSize(width: 200, height: 200)
http://www.riptutorial.com/ 732
UIGraphicsEndImageContext()
Objective-C:
Add this method as an extension of UIImage:
http://www.riptutorial.com/ 733
Chapter 171: UIImagePickerController
Introduction
UIImagePickerController provides an almost out of the box solution to allow the user to select an
image from their device or take a picture with the camera and then present that image. By
conforming to the UIImagePickerControllerDelegate, you can create logic that specifies in your
app how to present the image and what to do with it (using didFinishPickingMediaWithInfo) and
also what to do if the user declines to select an image or take a picture (using
imagePickerControllerDidCancel).
Examples
Generic usage of UIImagePickerController
Step 1: Create the controller, set the delegate, and conform to the protocol
//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
http://www.riptutorial.com/ 734
UIImagePickerController inherits from UINavigationController and changes the behavior of
UINavigationController. Therefore, we still need to say our view controller conforms to
UINavigationControllerDelegate.
//Swift
self.imagePickerController.sourceType = .Camera // options: .Camera , .PhotoLibrary ,
.SavedPhotosAlbum
self.presentViewController(self.imagePickerController, animated: true, completion: nil)
//Objective-C
imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera; // options:
UIImagePickerControllerSourceTypeCamera, UIImagePickerControllerSourceTypePhotoLibrary,
UIImagePickerControllerSourceTypeSavedPhotosAlbum
[self presentViewController:imagePickerController animated:YES 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 {
http://www.riptutorial.com/ 735
Chapter 172: UIImageView
Examples
Create a UIImageView
//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);
You can assign an image to a UIImageView during initialization, or later using the image property:
//Swift
UIImageView(image: UIImage(named: "image1"))
http://www.riptutorial.com/ 736
//Objective-C
[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"image1"];
Animating a UIImageView
You can animate a UIImageView by quickly displaying images on it in a sequence using the
UIImageView's animation properties:
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
This example shows, how to make a UIView or UIImageView, rounded with some radius like this:
http://www.riptutorial.com/ 737
Objective-C
someImageView.layer.cornerRadius = CGRectGetHeight(someImageView.frame) / 2;
someImageView.clipsToBounds = YES;
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.
http://www.riptutorial.com/ 738
}
The content mode property of a view tells how its content should be laid out. In the Interface
Builder, the various modes can be selected in the Attributes Inspector.
Let's use two image views to see how the various modes work.
Scale to Fill
http://www.riptutorial.com/ 739
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
http://www.riptutorial.com/ 740
The shortest side (either height or width) of the image is stretched to match the view. Like "Aspect
Fit", the proportions of the image are not distorted from their original aspect ratio.
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
The image is centered in the view, but the length and width of the image are not stretched.
http://www.riptutorial.com/ 741
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
http://www.riptutorial.com/ 742
The left edge of the image is centered vertically at the left of the view, and the length and width of
the image are not stretched.
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
http://www.riptutorial.com/ 743
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
The top right corner of the image is placed at the top right corner of the view. The length and width
of the image are not stretched.
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
http://www.riptutorial.com/ 744
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
• This example comes originally from here.
• If the content (in our case the image) is the same size as the view (in our case the
UIImageView), then changing the content mode will make no noticeable difference.
• 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
//Swift
imageView.tintColor = UIColor.redColor()
imageView.image = imageView.image?.imageWithRenderingMode(.AlwaysTemplate)
//Swift 3
imageView.tintColor = UIColor.red
imageView.image = imageView.image?.withRenderingMode(.alwaysTemplate)
http://www.riptutorial.com/ 745
//Objective-C
imageView.tintColor = [UIColor redColor];
imageView.image = [imageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]
This makes image masked to the shape of the letters of the label:
Objective-C
self.maskImage.layer.mask = self.maskLabel.layer;
self.maskImage.layer.masksToBounds = YES;
Swift 3
maskImageView.mask = maskLabel
maskImageView.masksToBounds = true
http://www.riptutorial.com/ 746
Chapter 173: UIKit Dynamics
Introduction
UIKit Dynamics is a full real-world physics engine integrated into UIKit. It allows you to create
interfaces that feel real by adding behaviors such as gravity, attachments, collision and forces.
You define the physical traits that you would like your interface elements to adopt, and the
dynamics engine takes care of the rest.
Remarks
An import thing to keep in mind when using UIKit Dynamics is views that are positioned by the
animator cannot readily be positioned by other common iOS layout methods.
Newcomers to UIKit Dynamics often struggle with this important caveat. Placing constraints on a
view that is also an item of a UIDynamicBehavior will likely cause confusion as a both the auto layout
engine and the dynamic animator engine fight over the appropriate position. Similarly, attempting
to set the frame directly of a view being controlled by the animator will typically result in jittery
animation and unexpected placement. Adding a view as an item to a UIDynamicBehavior means that
the animator will take on the responsibility of positioning a view and as such changes of view
positions should be implemented through the animator.
A view's frame that is being updated by a dynamic animator can be set, but that should be
immediately followed by messaging the animator to update the animator's internal model of the
view hierarchy. For example, if I have UILabel, label that is an item of a UIGravityBehavior I can
move it to the top of the screen to watch it fall again by saying:
Swift
Objective-C
After which the animator will apply the gravity behavior from the label's new location.
http://www.riptutorial.com/ 747
Examples
The Falling Square
Lets draw a square in the middle of our view and make it fall to the bottom and stop at the bottom
edge collising with the screen bottom boundary.
http://www.riptutorial.com/ 748
override func viewDidLoad() {
super.viewDidLoad()
let squareSize = CGSize(width: 30.0, height: 30.0)
let centerPoint = CGPoint(x: self.animationView.bounds.midX - (squareSize.width/2), y:
self.animationView.bounds.midY - (squareSize.height/2))
let frame = CGRect(origin: centerPoint, size: squareSize)
squareView = UIView(frame: frame)
squareView.backgroundColor = UIColor.orangeColor()
animationView.addSubview(squareView)
animator = UIDynamicAnimator(referenceView: view)
gravity = UIGravityBehavior(items: [squareView])
animator.addBehavior(gravity)
collision = UICollisionBehavior(items: [square])
collision.translatesReferenceBoundsIntoBoundary = true
animator.addBehavior(collision)
}
This example shows how to have a view track a pan gesture and depart in a physics-based
manner.
Swift
http://www.riptutorial.com/ 749
}()
http://www.riptutorial.com/ 750
push.pushDirection = CGVector(dx: velocity.x, dy: velocity.y)
push.magnitude = magnitude * magnitudeMultiplier
dynamicAnimator.removeBehavior(attachment)
dynamicAnimator.addBehavior(push)
}
}
}
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)
http://www.riptutorial.com/ 751
{
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];
}
}
- (UIGravityBehavior *)gravity
{
if (!_gravity)
{
_gravity = [[UIGravityBehavior alloc]initWithItems:@[self.orangeView]];
}
return _gravity;
}
- (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;
}
http://www.riptutorial.com/ 752
- (UIAttachmentBehavior *)attachment
{
if (!_attachment)
{
_attachment = [[UIAttachmentBehavior alloc]initWithItem:self.orangeView
attachedToAnchor:CGPointZero];
}
return _attachment;
}
@end
This example shows how to achieve an effect similar to FaceTime were a view is attracted to point
once it enters a particular region, in this case two regions a top and bottom.
Swift
http://www.riptutorial.com/ 753
{
let field = UIFieldBehavior.springField()
field.addItem(self.orangeView)
fieldBehaviors.append(field)
}
return fieldBehaviors
}()
orangeView.addGestureRecognizer(panGesture)
}
orangeView.center = view.center
dynamicAnimator.updateItem(usingCurrentState: orangeView)
http://www.riptutorial.com/ 754
for (index, field) in fieldBehaviors.enumerated()
{
field.position = CGPoint(x: view.bounds
.midX, y: view.bounds.height * (0.25 + 0.5 * CGFloat(index)))
field.region = UIRegion(size: CGSize(width: view.bounds.width, height:
view.bounds.height * 0.5))
}
}
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
{
http://www.riptutorial.com/ 755
[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 ||
sender.state == UIGestureRecognizerStateEnded ||
sender.state == UIGestureRecognizerStateFailed ||
sender.state == UIGestureRecognizerStatePossible)
{
[self.itemBehavior addLinearVelocity:velocity forItem:self.orangeView];
[self.dynamicAnimator removeBehavior:self.attachment];
}
}
- (UICollisionBehavior *)collision
{
if (!_collision)
{
_collision = [[UICollisionBehavior alloc]initWithItems:@[self.orangeView]];
_collision.translatesReferenceBoundsIntoBoundary = YES;
}
return _collision;
}
http://www.riptutorial.com/ 756
{
NSMutableArray *fields = [[NSMutableArray alloc]init];
for (NSInteger i = 0; i < 2; i++)
{
UIFieldBehavior *field = [UIFieldBehavior springField];
[field addItem:self.orangeView];
[fields addObject:field];
}
_fieldBehaviors = fields;
}
return _fieldBehaviors;
}
- (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)
{
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
http://www.riptutorial.com/ 757
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
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)
http://www.riptutorial.com/ 758
}
}
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;
[_button setTitle:@"Present" forState:UIControlStateNormal];
[_button setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
}
return _button;
}
@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
http://www.riptutorial.com/ 759
{
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;
}
http://www.riptutorial.com/ 760
- (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:(UIViewController
*)presented presentingController:(UIViewController *)presenting
sourceController:(UIViewController *)source
{
return [[DropOutAnimator alloc]initWithDuration: 1.5 appearing:YES];
}
-
(id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController
*)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: UIViewControllerContextTransitioning).
Swift
http://www.riptutorial.com/ 761
var finishTime: TimeInterval = 0.0
var collisionBehavior: UICollisionBehavior?
var attachmentBehavior: UIAttachmentBehavior?
var animator: UIDynamicAnimator?
// 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])
http://www.riptutorial.com/ 762
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
http://www.riptutorial.com/ 763
self.addChildBehavior(attachmentBehavior)
self.transitionContext?.completeTransition(!(self.transitionContext?.transitionWasCancelled ??
false))
self.childBehaviors.forEach { self.removeChildBehavior($0) }
animator.removeAllBehaviors()
self.transitionContext = nil
}
else
{
if let attachmentBehavior = self.attachmentBehavior
{
// If we have an attachment, we are at the end of part one and start part two.
http://www.riptutorial.com/ 764
self.removeChildBehavior(attachmentBehavior)
self.attachmentBehavior = nil
animator.addBehavior(self)
let duration = self.transitionDuration(using: self.transitionContext)
self.finishTime = 1.0 / 3.0 * duration + animator.elapsedTime
}
else
{
// Clean up and call completion
let fromView = self.transitionContext?.viewController(forKey: .from)?.view
let toView = self.transitionContext?.viewController(forKey: .to)?.view
fromView?.removeFromSuperview()
toView?.isUserInteractionEnabled = true
self.transitionContext?.completeTransition(!(self.transitionContext?.transitionWasCancelled ??
false))
self.childBehaviors.forEach { self.removeChildBehavior($0) }
animator.removeAllBehaviors()
self.transitionContext = nil
}
}
}
}
Objective-C
@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
viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC = [transitionContext
viewControllerForKey:UITransitionContextToViewControllerKey];
http://www.riptutorial.com/ 765
UIView *fromView = fromVC.view;
UIView *toView = toVC.view;
// 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;
http://www.riptutorial.com/ 766
{
if (strongSelf.animator.elapsedTime >= strongSelf.finishTime)
{
strongSelf.elapsedTimeExceededDuration = YES;
[strongSelf.animator removeBehavior:strongSelf];
}
}
};
// 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;
http://www.riptutorial.com/ 767
// Animation has two parts part one is hanging from rope.
// Part two is bouncying off-screen
// Divide duration in two
self.finishTime = (2./3.) * duration + [self.animator elapsedTime];
-
(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;
}
http://www.riptutorial.com/ 768
[animator addBehavior:self];
NSTimeInterval duration = [self transitionDuration:self.transitionContext];
self.finishTime = 1./3. * duration + [animator elapsedTime];
}
else
{
// Clean up and call completion
UIView *fromView = [self.transitionContext
viewControllerForKey:UITransitionContextFromViewControllerKey].view;
UIView *toView = [self.transitionContext
viewControllerForKey:UITransitionContextToViewControllerKey].view;
[fromView removeFromSuperview];
toView.userInteractionEnabled = YES;
[self.transitionContext completeTransition:![self.transitionContext
transitionWasCancelled]];
for (UIDynamicBehavior *behavior in self.childBehaviors)
{
[self removeChildBehavior:behavior];
}
[animator removeAllBehaviors];
self.transitionContext = nil;
}
}
}
For more information 2013 WWDC Session "Advanced Techniques with UIKit Dynamics" as well
as SOLPresentingFun
This example shows how to make an interactive presentation transition with "real-world" physics
similar to iOS's notifications screen.
http://www.riptutorial.com/ 769
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 transition. So we'll create instances of our interactive
animators (one for presenting, one for dismissing). We'll also create an instance of the shade view
controller, which, in this example, is just a view controller with a label. Because we want the same
pan gesture to drive the entire interaction we pass references to the presenting view controller and
the shade into our interactive animators.
Swift
http://www.riptutorial.com/ 770
presentedVC: shadeVC, transitionDelegate: self)
}
}
extension ViewController: UIViewControllerTransitioningDelegate
{
func animationController(forPresented presented: UIViewController, presenting:
UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning?
{
return EmptyAnimator()
}
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;
http://www.riptutorial.com/ 771
[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:(UIViewController
*)presented presentingController:(UIViewController *)presenting
sourceController:(UIViewController *)source
{
return [[EmptyAnimator alloc] init];
}
-
(id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController
*)dismissed
{
return [[EmptyAnimator alloc] init];
}
-
(id<UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id<UIViewController
{
return self.presentingAnimator;
}
-
(id<UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id<UIViewControllerAni
{
return self.dismissingAnimator;
}
@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
http://www.riptutorial.com/ 772
}
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
// The Pan Gesture that drives the transition. Not using EdgePan because triggers
Notifications screen
http://www.riptutorial.com/ 773
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
http://www.riptutorial.com/ 774
{
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)
animator.addBehavior(self)
animator.delegate = self
self.action =
{ [weak self] in
guard let strongSelf = self else { return }
if strongSelf.animator.elapsedTime > strongSelf.finishTime
{
strongSelf.animator.removeAllBehaviors()
http://www.riptutorial.com/ 775
}
else
{
strongSelf.transitionContext?.updateInteractiveTransition(view.frame.maxY
/ view.frame.height
)
}
}
default:
break
}
}
}
extension ShadeAnimator: UIDynamicAnimatorDelegate
{
// Determines transition has ended
func dynamicAnimatorDidPause(_ animator: UIDynamicAnimator)
{
guard let transitionContext = self.transitionContext else { return }
let fromVC = transitionContext.viewController(forKey: .from)
let toVC = transitionContext.viewController(forKey: .to)
guard let view = isAppearing ? toVC?.view : fromVC?.view else { return }
http://www.riptutorial.com/ 776
switch (view.center.y < 0.0, isAppearing)
{
case (true, true), (true, false):
view.removeFromSuperview()
transitionContext.finishInteractiveTransition()
transitionContext.completeTransition(!isAppearing)
case (false, true):
toVC?.view.frame = transitionContext.finalFrame(for: toVC!)
transitionContext.finishInteractiveTransition()
transitionContext.completeTransition(true)
case (false, false):
fromVC?.view.frame = transitionContext.initialFrame(for: fromVC!)
transitionContext.cancelInteractiveTransition()
transitionContext.completeTransition(false)
}
childBehaviors.forEach { removeChildBehavior($0) }
animator.removeAllBehaviors()
self.animator = nil
self.transitionContext = nil
}
}
extension ShadeAnimator: UICollisionBehaviorDelegate
{
// Triggers haptics
func collisionBehavior(_ behavior: UICollisionBehavior, beganContactFor item:
UIDynamicItem, withBoundaryIdentifier identifier: NSCopying?, at p: CGPoint)
{
guard p.y > 0.0 else { return }
impactFeedbackGenerator.impactOccurred()
}
}
extension ShadeAnimator: UIViewControllerInteractiveTransitioning
{
// Starts transition
func startInteractiveTransition(_ transitionContext: UIViewControllerContextTransitioning)
{
setupViewsForTransition(with: transitionContext)
}
}
Objective-C
@implementation ShadeAnimator
- (instancetype)initWithIsAppearing:(BOOL)isAppearing presentingVC:(UIViewController
*)presentingVC presentedVC:(UIViewController *)presentedVC
http://www.riptutorial.com/ 777
transitionDelegate:(id<UIViewControllerTransitioningDelegate>)transitionDelegate
{
self = [super init];
if (self)
{
_isAppearing = isAppearing;
_presentingVC = presentingVC;
_presentedVC = presentedVC;
_transitionDelegate = transitionDelegate;
_impactFeedbackGenerator = [[UIImpactFeedbackGenerator
alloc]initWithStyle:UIImpactFeedbackStyleLight];
[_impactFeedbackGenerator prepare];
if (_isAppearing)
{
[_presentingVC.view addGestureRecognizer:self.pan];
}
else
{
[_presentedVC.view addGestureRecognizer:self.pan];
}
}
return self;
}
- (UIDynamicAnimator *)animator
{
if (!_animator)
{
_animator = [[UIDynamicAnimator
alloc]initWithReferenceView:self.transitionContext.containerView];
}
return _animator;
}
{
UIViewController *fromVC = [transitionContext
viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC = [transitionContext
viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *toView = toVC.view;
UIView *containerView = transitionContext.containerView;
self.transitionContext = transitionContext;
if (self.isAppearing)
{
CGRect fromViewInitialFrame = [transitionContext
initialFrameForViewController:fromVC];
http://www.riptutorial.com/ 778
CGRect toViewInitialFrame = toView.frame;
toViewInitialFrame.origin.y -= CGRectGetHeight(toViewInitialFrame);
toViewInitialFrame.origin.x = CGRectGetWidth(fromViewInitialFrame) * 0.5 -
CGRectGetWidth(toViewInitialFrame) * 0.5;
[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)
http://www.riptutorial.com/ 779
{
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 addAttachmentBehaviorWithView:view isCancelled:isCancelled];
[self addCollisionBehaviorWithView:view];
[self addItemBehaviorWithView:view];
[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];
}
http://www.riptutorial.com/ 780
{
anchor = CGPointMake(view.center.x, -CGRectGetHeight(view.frame));
}
UIAttachmentBehavior *attachmentBehavior = [[UIAttachmentBehavior alloc]initWithItem:view
attachedToAnchor:anchor];
attachmentBehavior.damping = 0.1;
attachmentBehavior.frequency = 3.0;
attachmentBehavior.length = 0.5 * CGRectGetHeight(view.frame);
[self addChildBehavior:attachmentBehavior];
}
@end
The animator triggers the start of the transition when the pan gesture begins. And simply moves
http://www.riptutorial.com/ 781
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.
This example shows how to customize the UIDynamicItem protocol to map position changes of a
view being dynamically animated to bounds changes to create a UIButton that expands and
contracts in a elastic fashion.
To start we need to create a new protocol that implements UIDynamicItem but that also has a
http://www.riptutorial.com/ 782
settable and gettable bounds property.
Swift
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
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)
}
}
http://www.riptutorial.com/ 783
var transform: CGAffineTransform
{
get
{
return self.target.transform
}
set
{
self.target.transform = newValue
}
}
}
Objective-C
@interface PositionToBoundsMapping ()
@property (nonatomic, strong) id<ResizableDynamicItem> target;
@end
@implementation PositionToBoundsMapping
- (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
http://www.riptutorial.com/ 784
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
// Create mapping
let buttonBoundsDynamicItem = PositionToBoundsMapping(target: button)
http://www.riptutorial.com/ 785
let pushBehavior = UIPushBehavior(items: [buttonBoundsDynamicItem], mode:
.instantaneous)
// 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];
self.view.backgroundColor = [UIColor whiteColor];
[self.button addTarget:self action:@selector(didTapButton:)
forControlEvents:UIControlEventTouchUpInside];
self.buttonBounds = self.button.bounds;
}
- (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];
http://www.riptutorial.com/ 786
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
http://www.riptutorial.com/ 787
Chapter 174: UIKit Dynamics with
UICollectionView
Introduction
UIKit Dynamics is a physics engine integrated into UIKit. UIKit Dynamics offers a set of API that
offers interoperability with a UICollectionView and UICollectionViewLayout
Examples
Creating a Custom Dragging Behavior with UIDynamicAnimator
This example shows how to create a custom dragging behavior by Subclassing UIDynamicBehavior
and subclassing UICollectionViewFlowLayout. In the example, we have UICollectionView that allows
for the selection of multiple items. Then with a long press gesture those items can be dragged in
an elastic, "springy" animation driven by a UIDynamicAnimator.
http://www.riptutorial.com/ 788
The dragging behavior is produced by combining a low-level behavior that adds a
UIAttachmentBehavior to the for corners of a UIDynamicItem and a high-level behavior that manages
the low-level behavior for a number of UIDynamicItems.
Swift
http://www.riptutorial.com/ 789
// Higher frequency more "ridged" formation
let frequency: CGFloat = 8.0
super.init()
attachmentBehaviors.forEach
{
addChildBehavior($0)
}
}
Objective-C
@implementation RectangleAttachmentBehavior
- (instancetype)initWithItem:(id<UIDynamicItem>)item point:(CGPoint)point
{
CGFloat frequency = 8.0f;
CGFloat damping = 0.6f;
self = [super init];
if (self)
http://www.riptutorial.com/ 790
{
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
http://www.riptutorial.com/ 791
}
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
http://www.riptutorial.com/ 792
// Custom high-level behavior that dictates drag animation
var dragBehavior: DragBehavior?
// 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
}
http://www.riptutorial.com/ 793
var allAttributes = [UICollectionViewLayoutAttributes]()
Objective-C
@implementation DraggableLayout
http://www.riptutorial.com/ 794
self.startDragPoint = point;
self.dragBehavior = [[DragBehavior alloc]initWithItems:draggableAttributes point:point];
[self.animator addBehavior:self.dragBehavior];
}
- (void)updateDragLoactionWithPoint:(CGPoint)point
{
[self.dragBehavior updateDragLocationWithPoint:point];
}
- (void)endDragging
{
self.finishedDragging = YES;
[self.dragBehavior updateDragLocationWithPoint:self.startDragPoint];
}
- (void)clearDraggedIndexPath
{
self.animator = nil;
self.indexPathsForDraggingElements = nil;
self.finishedDragging = NO;
}
- (void)dynamicAnimatorDidPause:(UIDynamicAnimator *)animator
{
if (self.finishedDragging)
{
[self clearDraggedIndexPath];
}
}
- (NSArray<UICollectionViewLayoutAttributes *>
*)layoutAttributesForElementsInRect:(CGRect)rect
{
NSArray *existingAttributes = [super layoutAttributesForElementsInRect:rect];
NSMutableArray *allAttributes = [[NSMutableArray
alloc]initWithCapacity:existingAttributes.count];
for (UICollectionViewLayoutAttributes *attributes in existingAttributes)
{
if (![self.indexPathsForDraggingElements containsObject:attributes.indexPath])
{
[allAttributes addObject:attributes];
}
}
[allAttributes addObjectsFromArray:[self.animator itemsInRect:rect]];
return allAttributes;
}
@end
Finally, we'll create a view controller that will create our UICollectionView and handle our long
press gesture.
Swift
http://www.riptutorial.com/ 795
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
}()
http://www.riptutorial.com/ 796
{
return 1000
}
Objective-C
@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)
http://www.riptutorial.com/ 797
{
_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;
}
- (void)handleLongPress:(UILongPressGestureRecognizer *)sender
{
DraggableLayout *draggableLayout = (DraggableLayout
*)self.collectionView.collectionViewLayout;
CGPoint location = [sender locationInView:self.collectionView];
if (sender.state == UIGestureRecognizerStateBegan)
{
[draggableLayout startDraggingWithIndexPaths:self.selectedIndexPaths
fromPoint:location];
}
else if(sender.state == UIGestureRecognizerStateChanged)
{
[draggableLayout updateDragLoactionWithPoint:location];
}
else if(sender.state == UIGestureRecognizerStateEnded || sender.state ==
UIGestureRecognizerStateCancelled || sender.state == UIGestureRecognizerStateFailed)
{
[draggableLayout endDragging];
}
}
- (NSInteger)collectionView:(UICollectionView *)collectionView
numberOfItemsInSection:(NSInteger)section
{
return 1000;
}
http://www.riptutorial.com/ 798
if ([self.selectedIndexPaths containsObject:indexPath])
{
cell.backgroundColor = [UIColor redColor];
}
return cell;
}
- (void)collectionView:(UICollectionView *)collectionView
didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
BOOL isSelected = ![self.selectedIndexPaths containsObject:indexPath];
UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
if (isSelected)
{
cell.backgroundColor = [UIColor redColor];
[self.selectedIndexPaths addObject:indexPath];
}
else
{
cell.backgroundColor = [UIColor grayColor];
[self.selectedIndexPaths removeObject:indexPath];
}
}
@end
For more information 2013 WWDC Session "Advanced Techniques with UIKit Dynamics"
http://www.riptutorial.com/ 799
Chapter 175: UILabel
Introduction
The UILabel class implements a read-only text view. You can use this class to draw one or
multiple lines of static text, such as those you might use to identify other parts of your user
interface. The base UILabel class provides support for both simple and complex styling of the label
text. You can also control over aspects of appearance, such as whether the label uses a shadow
or draws with a highlight. If needed, you can customize the appearance of your text further by
subclassing.
Syntax
• UILabel.numberOfLines: Int // get or set the maximum number of lines the label can have. 0
is unlimited
• UILabel.text: String? // get or set the text the label displays
• UILabel.textColor: UIColor! // get or set the color of the text on the label
• UILabel.tintColor: UIColor! // get or set the tint color of the label
• UILabel.attributedText: NSAttributedString? // get or set the attributed text of the label
• UILabel.font: UIFont! // get or set the font of the text on the label
• UILabel.textAlignment: NSTextAlignment // get or set the alignment of the text
Remarks
UILabels are views which can be used to display one or many lines of text. It contains multiple
ways of stylizing text, such as shadows, text colors, and fonts.
UILabels can also display Attributed Strings, which is text + inline markup to apply styles to
portions of the text.
UILabel does not conform to the UIAppearance protocol, so you cannot use UIAppearance proxy
methods to customise appearance of UILabels. See this discussion for more.
Examples
Highlighted and Highlighted Text Color
Objective-C
http://www.riptutorial.com/ 800
Swift
Swift 3
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.
Sometimes we have to resize a UILabel based on dynamic content where the text length is
unknown. In this example, width of the UILabel is fixed at 280 points and the height is infinite, lets
say 9999. Estimating the frame with respect to the text style and maximumLabelSize.
Objective-C
http://www.riptutorial.com/ 801
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
Clickable Label
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
http://www.riptutorial.com/ 802
Swift
Objective-C
Setting "userInteractionEnabled" in
storyboard's attributes inspector
Instead of using code, you can select the UILabel inside the storyboard and check the option:
This example shows how a label's width can automatically resize when the text content changes.
Notes
• This example comes from this Stack Overflow answer.
• Don't add constraints for the width and height. Labels have an intrinsic size based on their
text content.
• No need to set sizeToFit when using auto layout. The complete code for the example project
is here:
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
http://www.riptutorial.com/ 804
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.)
Step 1
Select the Label and change the label type Plain to Attributed
http://www.riptutorial.com/ 805
Step 2
http://www.riptutorial.com/ 806
Step 3
http://www.riptutorial.com/ 807
Step 4
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.
http://www.riptutorial.com/ 808
Finally click enter and label will be shown underline or strikethrough according to your selection.
http://www.riptutorial.com/ 809
02. Add text shaddow/background blur effects
Get the Font view as the above described and click the effects button.
http://www.riptutorial.com/ 810
If you don't See the preview click the show image in settings
http://www.riptutorial.com/ 811
Justify Text
Swift
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;
http://www.riptutorial.com/ 812
}];
label.attributedText = attributedString;
[self.view addSubview:label];
You can make an UILabel with a dynamic height using auto layout.
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
iOS 6
Swift
label.numberOfLines = 0
label.addConstraint(heightConstraint)
iOS 9
Swift
label.numberOfLines = 0
label.translatesAutoresizingMaskIntoConstraints = false
label.heightAnchor.constraintGreaterThanOrEqualToConstant(20).active = true
Swift
Swift 3
http://www.riptutorial.com/ 813
Objective-C
A common use case for wanting to calculate the frame a label will take up is for sizing table view
cells appropriately. The recommended way of doing this is using the NSString method
boundingRectWithSize:options:attributes:context:.
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.
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
http://www.riptutorial.com/ 814
NSFont *labelFont = [cell.theLabel font];
// 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
paragraphStyle.lineBreakMode = .byWordWrapping
paragraphStyle.alignment = .center
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:
options:NSStringDrawingTruncatesLastVisibleLine
context:nil];
CGFloat lineHeight = CGRectGetHeight(singleLineRect);
http://www.riptutorial.com/ 815
CGFloat maxHeight = lineHeight * cell.theLabel.numberOfLines;
LineBreakMode
Using code
UILabel.lineBreakMode: NSLineBreakMode
Swift
label.lineBreakMode = .ByTruncatingTail
• .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
http://www.riptutorial.com/ 816
• NSLineBreakByTruncatingHead
• NSLineBreakByTruncatingTail
• NSLineBreakByTruncatingMiddle
Using storyboard
This can also be set in the attributes inspector of a UILabel:
Constants
• Word Wrapping - wrapping occurs at word boundaries, unless the word itself doesn’t fit on a
single line
• Char Wrapping - wrapping occurs before the first character that doesn’t fit
• Clipping - lines are simply not drawn past the edge of the text container
• Truncating Head - the line is displayed so that the end fits in the container and the missing
text at the beginning of the line is indicated by an ellipsis glyph
• Truncating Tail - the line is displayed so that the beginning fits in the container and the
missing text at the end of the line is indicated by an ellipsis glyph
• Truncating Middle - the line is displayed so that the beginning and end fit in the container
and the missing text in the middle is indicated by an ellipsis glyph
Size to fit
Suppose you have a UILabel on your storyboard and you have created an IBOutlet for it in
ViewController.swift / ViewController.m and named it labelOne.
To make the changes easily visible, change the backgroundColor and textColor of labelOne in the
viewDidLoad method:
http://www.riptutorial.com/ 817
The function sizeToFit is used when you want to automatically resize a label based on the content
stored within it.
Swift
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.
http://www.riptutorial.com/ 818
Now, labelOne looks like this:
Even calling sizeToFit doesn't change anything. This is because by default, the numberOfLines
shown by the UILabel is set to 1. Let’s change it to zero on the storyboard:
http://www.riptutorial.com/ 819
The numberOfLines property can also be changed in the ViewController file :
// Objective-C
labelOne.numberOfLines = 0;
// Swift
labelOne.numberOfLines = 0
Background Color
Swift
label.backgroundColor = UIColor.redColor()
label.backgroundColor = .redColor()
Swift 3
label.backgroundColor = UIColor.red
Objective-C
Text Color
You can use the label's textColor property to apply a text color to the entire text of the label.
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)
http://www.riptutorial.com/ 820
Swift 3
label.textColor = UIColor.red
label.textColor = UIColor(red: 64.0/255.0, green: 88.0/255.0, blue: 41.0/225.0, alpha: 1)
Objective-C
Objective-C
Swift
Text alignment
Swift
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;
http://www.riptutorial.com/ 821
Any value in the NSTextAlignment enum is valid: NSTextAlignmentLeft, NSTextAlignmentCenter,
NSTextAlignmentRight, NSTextAlignmentJustified, NSTextAlignmentNatural
Vertical alignment in UILabel is not supported out of the box: Vertically align text to top within a
UILabel
Create a UILabel
With a Frame
When you know the exact dimensions you want to set for your label, you can initialize a UILabel
with a CGRect frame.
Swift
Objective-C
Swift
NSLayoutConstraint.activate([
//stick the top of the label to the top of its superview:
label.topAnchor.constraint(equalTo: view.topAnchor)
http://www.riptutorial.com/ 822
//stick the label's bottom to the bottom of its superview:
label.bottomAnchor.constraint(equalTo: view.bottomAnchor)
Objective-C
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.
http://www.riptutorial.com/ 823
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.
In the properties dialog, you can set the name of UILabel, and set it as strong or weak. For more
information about strong and weak, see this,
Swift
http://www.riptutorial.com/ 824
Objective-C
Set Font
Swift
Objective-C
label.font = UIFont.systemFontOfSize(17)
Swift 3
Objective-C
Swift
http://www.riptutorial.com/ 825
Swift3
Objective-C
iOS 8.2
Swift
label.font = UIFont.boldSystemFontOfSize(17)
Swift3
Objective-C
Swift
label.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody)
Swift 3
Objective-C
http://www.riptutorial.com/ 826
Use a different font altogether
Swift
Objective-C
Swift
label.font = label.font.fontWithSize(15)
Swift 3
label.font = label.font.withSize(15)
Objective-C
Number of Lines
When you make a label and set its text to be more than a single line that it can display, it will be
truncated and you will see only one line of text ending with three dots (...). This is because a
property called numberOfLines is set to 1, and therefore only one line will be displayed. It is a
common mistake in handling UILabels, and many people think of it as a bug, or they may use more
than one label to show more than a line of text, but just by editing this property, we can tell a
UILabel to accept up to the specified number of lines. For example, if this property is set to 5, the
label can show 1, 2, 3, 4 or 5 lines of data.
http://www.riptutorial.com/ 827
Setting the value programmatically
To set this property, simply assign a new integer to it:
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;
Note
If the label has a height constraint, the constraint will be respected. In this case,
label.numberOfLines = 0 may not work as expected.
Note
For a more complex multi-line text, UITextView may be a better fit.*
http://www.riptutorial.com/ 828
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:
Changing the text of an existing UILabel can be done by accessing and modifying the text property
of the UILabel. This can be done directly using String literals or indirectly using variables.
Objective-C
// Dot Notation
label.text = @"the new text";
// Message Pattern
[label setText:@"the new text"];
Objective-C
// Dot Notation
http://www.riptutorial.com/ 829
label.text = stringVar;
// Message Pattern
[label setText: stringVar];
http://www.riptutorial.com/ 830
Chapter 176: UILabel text underlining
Examples
Underlining a text in a UILabel using Objective C
http://www.riptutorial.com/ 831
Chapter 177: UILocalNotification
Introduction
Local notifications allow your app to notify the user about content which does not require the use
of a server.
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.
Remarks
Do not confuse UILocalNotification with push notifications. UILocalNotification is triggered by your
device, and when scheduled, is copied to the system.
Links:
Examples
Scheduling a local notification
Make sure you see Registering for local notifications in order for this to work:
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
http://www.riptutorial.com/ 832
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).
iOS 8
In order to present local notifications to the user, you have to register your app with the device:
Swift
Objective-C
http://www.riptutorial.com/ 833
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.
Swift
Objective-C
- (void)application:(UIApplication *)application
didReceiveLocalNotification:(UILocalNotification *)notification {
Notification Sound
Custom sounds may be provided for notifications generated by your app. When the system
displays an alert for a local notification or badges an app icon, it plays this sound (so long as the
user has not disabled notification sounds).
http://www.riptutorial.com/ 834
The default value is nil which means no sound is played for your notification.
To supply a custom sound, add a .caf, .wav, or .aiff file to your app bundle. Sounds that last
longer than 30 seconds are not supported. Supplying a sound that does not meet those
requirements will cause the default sound to play (UILocalNotificationDefaultSoundName).
Objective-C
Swift
Swift 3
UIApplication.shared.presentLocalNotificationNow(notification)
Swift 2
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.
Often times you will need to be able to manage your notifications, by being able to keep track of
them and cancel them.
Track a notification
You can assign a UUID (universally unique identifier) to a notification, so you can track it:
Swift
http://www.riptutorial.com/ 835
let notification = UILocalNotification()
let uuid = NSUUID().uuidString
notification.userInfo = ["UUID": uuid]
UIApplication.shared.scheduleLocalNotification(notification)
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.
Registration
in AppDelegate
import UserNotifications
http://www.riptutorial.com/ 836
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.
You can use UILocalNotification, old APIs also works fine with iOS10, but we had better use the
APIs in the User Notifications framework instead. There are also some new features, you can only
use with iOS10 User Notifications framework.
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.
http://www.riptutorial.com/ 837
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
http://www.riptutorial.com/ 838
#import <UserNotifications/UserNotifications.h>
3. schedule localNotification
#updated
http://www.riptutorial.com/ 839
Read UILocalNotification online: http://www.riptutorial.com/ios/topic/635/uilocalnotification
http://www.riptutorial.com/ 840
Chapter 178: UINavigationController
Remarks
From the documentation:
Examples
Embed a view controller in a navigation controller programmatically
Swift
//Swift
let viewController = UIViewController()
let navigationController = UINavigationController(rootViewController: viewController)
//Objective-C
UIViewController *viewController = [[UIViewController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc]
initWithRootViewController:viewController];
//Swift
let fooViewController = UIViewController()
navigationController?.pushViewController(fooViewController, animated: true)
//Objective-C
UIViewController *fooViewController = [[UIViewController alloc] init];
[navigationController pushViewController:fooViewController animated:YES];
Swift
navigationController?.popViewControllerAnimated(true)
http://www.riptutorial.com/ 841
Objective-C
[self.navigationController popViewControllerAnimated:YES];
Swift
navigationController?.popToRootViewControllerAnimated(true)
Objective C
[self.navigationController popToRootViewControllerAnimated:YES];
Creating a NavigationController
In your storyboard select the ViewController that you want to embed into a Navigation Controller.
http://www.riptutorial.com/ 842
Purpose
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.
helps to remember where user is at the moment (navigation bar title) and
UINavigationController
how he can go back (embedded back button) to one of the previous screens.
http://www.riptutorial.com/ 843
Chapter 179: UIPageViewController
Introduction
UIPageViewController provides users the ability to easily transition between several views by
using a swipe gesture. In order to create a UIPageViewController, you must implement the
UIPageViewControllerDataSource methods. These include methods to return both the
UIPageViewController before and after the current UIPageViewController along with the
presentationCount and presentationIndex methods.
Syntax
1. UIPageViewControllerTransitionStyle
2. UIPageViewControllerNavigationOrientation
3. UIPageViewControllerSpineLocation
4. UIPageViewControllerNavigationDirection
Remarks
Apple Developer reference here
Examples
Create a horizontal paging UIPageViewController programatically
1. Init array of view controllers which will be managed by UIPageViewController. Add a base
view controller class which has property identifier which will be used to identify view
controllers when working with UIPageViewController data source methods. Let the view
controllers to inherit from that base class.
navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal
options:nil];
http://www.riptutorial.com/ 844
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];
http://www.riptutorial.com/ 845
} else {
return nil;
}
}
1. Let's create a new project, I'm choosing Single View Application for better demonstration
2. Drag a page view controller to the storyboard, there are 2 things you should change after
that:
1. Set the page view controller as initial view controller
2. Change the transition style to scroll
http://www.riptutorial.com/ 846
3. And you need to create a UIPageViewController class, then set it as custom class of the
page view controller on the storyboard
4. Paste this code into your UIPageViewController class, you should get a colorful infinite
paged app :)
http://www.riptutorial.com/ 847
return controller
}
This is what the final project looks like, you get a view controller with different color with every
scroll:
http://www.riptutorial.com/ 848
http://www.riptutorial.com/ 849
Chapter 180: UIPheonix - easy, flexible,
dynamic & highly scalable UI framework
Introduction
Inspired by game development UIPheonix is a super easy, flexible, dynamic and highly scalable UI
framework + concept for building reusable component/control-driven apps for macOS, iOS and
tvOS. The same API apply for cross platform development! Think of it as using Lego blocks, you
can use similar ones and move them around easy as pie.
https://github.com/MKGitHub/UIPheonix
Remarks
• Forget static layouts, constraint issues and warning explosions in the console.
• Forget all the glue code, all the boilerplate code and all the very common overly engineered
unnecessary pile of garbage code in your apps.
• Build and make changes to your UI quickly in a snap.
• Make your UI reusable.
• Focus on creating your app, not fighting layout issues.
• Minimal setup, minimal impact on your app, lightweight, no dependencies, no pain but so
much gain!
• Builds on top of collection views & table views, so you can easily mix and match.
• Does not replace Apple technologies with custom implementations, so you will always be
safe and up-to-date, and you can easily revert at any time.
• Demo apps provided for macOS, iOS and tvOS (Kung Fu!)
Examples
Example UI Components
http://www.riptutorial.com/ 850
http://www.riptutorial.com/ 851
http://www.riptutorial.com/ios/topic/9120/uipheonix---easy--flexible--dynamic---highly-scalable-ui-
framework
http://www.riptutorial.com/ 852
Chapter 181: UIPickerView
Examples
Basic example
Swift
class PickerViewExampleViewController : UIViewController, UIPickerViewDelegate,
UIPickerViewDataSource {
@IBOutlet weak var btnFolder: UIButton!
let pickerView = UIPickerView()
let pickerViewRows = ["First row,", "Secound row,","Third row,","Fourth row"]
//MARK: UIPickerViewDelegate
//MARK: UIPickerViewDataSource
Objective-C
@property (nonatomic,strong) UIPickerView *countryPicker;
@property (nonatomic,strong) NSArray *countryNames;
- (void)viewDidLoad {
http://www.riptutorial.com/ 853
[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;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView
numberOfRowsInComponent:(NSInteger)component {
return _countryNames.count;
}
Objective-C
//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
http://www.riptutorial.com/ 854
Chapter 182: UIRefreshControl TableView
Introduction
A UIRefreshControl object provides a standard control that can be used to initiate the refreshing of
a table view’s contents. You link a refresh control to a table through an associated table view
controller object. The table view controller handles the work of adding the control to the table’s
visual appearance and managing the display of that control in response to appropriate user
gestures.
Examples
Objective-C Example
- (void)refreshTable {
//TODO: refresh your data
[self.refreshControl endRefreshing];
[self.refreshControl beginRefreshing];
[self.tableView reloadData];
[self.refreshControl endRefreshing];
}
http://www.riptutorial.com/ 855
Set up refreshControl on tableView:
- (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];
});
});
http://www.riptutorial.com/ 856
Chapter 183: UIScrollView
Examples
Create a UIScrollView
Swift
Objective-C
The contentSize property must be set to the size of the scrollable content. This specifies the size of
the scrollable area. Scrolling is visible when scrollable area i.e. contentSize is larger than the
UIScrollView frame size.
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
This project is a self-contained example done completely in the Interface Builder. You should be
able to work through it in 10 minutes or less. Then you can apply the concepts you learned to your
own project.
http://www.riptutorial.com/ 857
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
http://www.riptutorial.com/ 858
Freeform in the Size Inspector. Make the width 1,000 and the height 300. This just gives us the
room on the storyboard to add content that will scroll.
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.
http://www.riptutorial.com/ 859
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.
Note:
• 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.
http://www.riptutorial.com/ 860
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
• iOS: How To Make AutoLayout Work On A ScrollView
• How to configure a UIScrollView with Auto Layout in Interface Builder
• YouTube video tutorial: UIScrollView - How to keep your views on screen
http://www.riptutorial.com/ 861
inspector.
• Add a scrollview to your viewcontroller's view as follows and set background color to blue
http://www.riptutorial.com/ 862
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,
http://www.riptutorial.com/ 863
Next comes the important part,we need it to scroll horizontally and vertically.
http://www.riptutorial.com/ 864
Let me explain what we did in above step.
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.
http://www.riptutorial.com/ 865
• And Done!!! Simply run and check if it scrolls vertically
Scenario 3:
• Undo all the changes to achieve constraints as below(i.e restore original constraints
which achieved vertical and horizontal scroll)
http://www.riptutorial.com/ 866
• Delete height constraint of orange view.
• Change the height of orange view to match the scrollview height.
• Ctrl-drag from orange view to scroll view and add equal heights constraint.
Enable/Disable Scrolling
Property scrollEnabled stores a Boolean value that determines whether scrolling is enabled or not.
If the value of this property is true/YES, scrolling is enabled, otherwise not.The default value is
true
Swift
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
http://www.riptutorial.com/ 867
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
scrollViewDidEndDecelerating: this tells the delegate that the scroll view has ended
decelerating the scrolling movement.
Objective C:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
[self stoppedScrolling];
}
http://www.riptutorial.com/ 868
[self stoppedScrolling];
}
}
- (void)stoppedScrolling {
// done, do whatever
}
Swift:
func stoppedScrolling() {
// done, do whatever
}
You can restrict the directions the user is able to scroll to using the following code:
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
http://www.riptutorial.com/ 869
Chapter 184: UIScrollView AutoLayout
Examples
UIScrollView dynamic content size through Storyboard
While using scrollviews in storyboard it's better to calculate content size according to number of
views present in scrollview rather than giving content size programatically with static value.
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.
http://www.riptutorial.com/ 870
http://www.riptutorial.com/ 871
ScrollableController
When using Autolayout with a UIScrollView, it does NOT resize properly depending on the size of
its contents or subviews.
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.
http://www.riptutorial.com/ 872
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
}
func layoutContentView() {
self.scrollView.addSubview(self.contentView)
http://www.riptutorial.com/ 873
self.scrollView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat:
constraint, 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
}
}
Now we can see that the greenView (400 height) + the whiteView (500 height) is larger than our
screen. This will cause the ScrollView's contentSize to grow to fit BOTH views, allowing it to scroll
vertically.
We disabled horizontal scrolling using the EqualWidth constraint on the contentView and self.view
http://www.riptutorial.com/ 874
http://www.riptutorial.com/ 875
http://www.riptutorial.com/ios/topic/4671/uiscrollview-autolayout
http://www.riptutorial.com/ 876
Chapter 185: UIScrollView with StackView
child
Examples
A complex StackView inside Scrollview Example
Here follows a example of what can be done with nested StackViews, giving the user the
impression of a continuous scrolling experience using complex user interface elements or
alignments.
http://www.riptutorial.com/ 877
Preventing ambiguous layout
http://www.riptutorial.com/ 878
A frequent question about StackViews inside Scrollviews comes from ambiguous with/heigh alerts
on interface builder. As this answer explained, it is necessary to:
The big gotcha about scrolling is to determine the offset necessary to present (for instance) a
Textfield inside a StackView with is inside the ScrollView.
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:
http://www.riptutorial.com/ 879
Chapter 186: UISearchController
Syntax
• UISearchController(searchResultsController: UIViewController?) // Pass nil as the parameter
if the search updating controller also displays the searchable content.
• func updateSearchResults(for searchController: UISearchController) // Required method to
implement when adopting the UISearchResultsUpdating protocol
Parameters
Parameter Details
http://www.riptutorial.com/ 880
Parameter Details
Remarks
UIKit Framework Reference:
UISearchController
UISearchResultsUpdating
Examples
Search Bar in Navigation Bar Title
This example uses a search controller to filter the data inside a table view controller. The search
bar is placed inside the navigation bar that the table view is embedded into.
http://www.riptutorial.com/ 881
http://www.riptutorial.com/ 882
(which contains the navigation bar). Then set our custom ViewController class to inherit from
UITableViewController and adopt the UISearchResultsUpdating protocol.
searchController.searchResultsUpdater = self
self.definesPresentationContext = true
// Don't hide the navigation bar because the search bar is in it.
searchController.hidesNavigationBarDuringPresentation = false
}
http://www.riptutorial.com/ 883
UITableViewCell {
// If the search bar is active, use the searchResults data.
let entry = searchController.isActive ?
searchResults[indexPath.row] : entries[indexPath.row]
This example uses a search controller to filter the cells in a table view controller. The search bar is
placed inside the header view of the table view. The table view content is offset with the same
height as the search bar so that the search bar is hidden at first. Upon scrolling up past the top
edge of the table view, the search bar is revealed. Then when the search bar becomes active, it
hides the navigation bar.
http://www.riptutorial.com/ 884
http://www.riptutorial.com/ 885
Embed a UITableViewController into a UINavigationController to get the UINavigationItem (which
UISearchResultsUpdating protocol:
UISerachController in Objective-C
- (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.
}
http://www.riptutorial.com/ 886
Chapter 187: UISegmentedControl
Introduction
A UISegmentedControl object is a horizontal control made of multiple segments, each segment
functioning as a discrete button. A segmented control affords a compact means to group together
a number of controls.
Examples
Creating UISegmentedControl via code
2. Setup frame;
mySegmentedControl.selectedSegmentIndex = 0
4. Configure target:
yourView.addSubview(mySegmentedControl)
http://www.riptutorial.com/ 887
Chapter 188: UISlider
Examples
UISlider
Objective-C
- (IBAction)sliderAction:(id)sender {
NSLog(@"Slider Value %f", sender.value);
}
To add a custom image for the thumb of the slider, simply call the setThumbImage method with
your custom image:
Swift 3.1:
SWIFT Example
http://www.riptutorial.com/ 888
slider.maximumValue = 50.0
//sending a NO/False would update the value of slider only when the user is no longer
touching the screen. Hence sending only the final value
slider.isContinuous = true
slider.value = 25.0
view.addSubview(slider)
func sliderAction(sender:UISlider!)
{
print("value--\(sender.value)")
}
http://www.riptutorial.com/ 889
Chapter 189: UISplitViewController
Remarks
UISplitViewController is a container class like UITabViewController, UINavigationController. It
separates the main view into two View Controllers masterViewController(PrimaryViewController)
and detailViewController(SecondaryViewController). we can send an array with two view
controllers and Apple recommends to to UISplitViewController as a rootviewcontroller for your
application. To interact between the viewcontrolers I use NSNotificationCenter.
Examples
Master and Detail View interaction using Delegates in Objective C
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
http://www.riptutorial.com/ 890
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];
self.preferredDisplayMode = UISplitViewControllerDisplayModeAutomatic;
self.viewControllers = vcArray;
self.delegate = (id)self;
self.presentsWithGesture = YES;
}
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
http://www.riptutorial.com/ 891
@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
http://www.riptutorial.com/ 892
{
[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>
DetailViewController.m
#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
sendSelectedNavControlleris declared here with removing all the views in the DetailViewController
and adding the passed UIViewController from the MasterViewController
http://www.riptutorial.com/ 893
http://www.riptutorial.com/ 894
preferredDisplayMode as automatic on swiping the screen we get the MasterViewController as
attached in the below image but in Landscape mode we get both the MasterViewController and
DetailViewController
http://www.riptutorial.com/ 895
http://www.riptutorial.com/ 896
http://www.riptutorial.com/ 897
http://www.riptutorial.com/ 898
Chapter 190: UISplitViewController
Remarks
In iOS 8 and later, you can use the UISplitViewController class on all iOS devices, in previous
versions of iOS, the class is available only on iPad. UISplitViewController is a container class like
UITabViewController, UINavigationController. It separates the main view into two UIViewControllers
masterViewController(PrimaryViewController) and detailViewController(SecondaryViewController).
we can send an NSArray with two UIViewControllers and Apple recommends UISplitViewController
as a rootviewcontroller for your application. To interact between the UIViewControllers I use
NSNotificationCenter.
Examples
Interacting Between Master and Detail View using Delegates in Objective C
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
http://www.riptutorial.com/ 899
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;
self.presentsWithGesture = YES;
}
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"
http://www.riptutorial.com/ 900
@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
http://www.riptutorial.com/ 901
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[detailDelegate sendSelectedNavController:[viewControllerArray
objectAtIndex:indexPath.row]];
}
@end
DetailViewController.h
#import <UIKit/UIKit.h>
DetailViewController.m
#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
The sendSelectedNavController is declared here with removing all the UIView's in the
DetailViewController and adding the passed UIViewController from the MasterViewController.
http://www.riptutorial.com/ 902
Chapter 191: UIStackView
Examples
Create a horizontal stack view programmatically
Swift 3
Swift
Objective-C
http://www.riptutorial.com/ 903
Swift
Objective-C
http://www.riptutorial.com/ 904
Step 3 :- All 2 - 2 button's pair in 2 stackview.
http://www.riptutorial.com/ 905
Step 4 :- Set UIStackview Property for both .
http://www.riptutorial.com/ 906
Step 5 :- Add both Stackview in one Stackview
http://www.riptutorial.com/ 907
Step 6 :- Set Distribution = Fill equally Spacing =5 in main stackview (set According to your
requirement)
http://www.riptutorial.com/ 908
Step 7 :- Now set Constrain to main stackview
http://www.riptutorial.com/ 909
Step 8 :- It's time for Output for All device .
http://www.riptutorial.com/ 910
Read UIStackView online: http://www.riptutorial.com/ios/topic/1390/uistackview
http://www.riptutorial.com/ 911
Chapter 192: UIStoryboard
Introduction
A UIStoryboard object encapsulates the view controller graph stored in an Interface Builder
storyboard resource file. This view controller graph represents the view controllers for all or part of
your application’s user interface.
Examples
Getting an instance of UIStoryboard programmatically
SWIFT:
Getting an instance of UIStoryboard programmatically can be done as follows:
where:
For example, you can use the instance created above to access a certain UIViewController
instantiated within that storyboard:
OBJECTIVE-C:
Getting an instance of UIStoryboard in Objective-C can be done as follows:
http://www.riptutorial.com/ 912
let storyboard = UIStoryboard(name: "StoryboardName", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "ViewControllerID") as
YourViewController
self.present(vc, animated: true, completion: nil)
http://www.riptutorial.com/ 913
Chapter 193: UISwitch
Syntax
• (instancetype)initWithFrame:(CGRect)frame;
• (void)setOn:(BOOL)on animated:(BOOL)animated;
• (nullable instancetype)initWithCoder:(NSCoder *)aDecoder;
Remarks
Examples
Set On / Off
Objective-C
[mySwitch setOn:YES];
//or
[mySwitch setOn:YES animated:YES];
http://www.riptutorial.com/ 914
Swift
mySwitch.setOn(false)
//or
mySwitch.setOn(false, animated: false)
Objective-C
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)
Objective-C
//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()
Objective-C
//set off-image
mySwitch.offImage = [UIImage imageNamed:@"off_image"];
http://www.riptutorial.com/ 915
[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")
http://www.riptutorial.com/ 916
Chapter 194: UITabBarController
Examples
Create an instance
A 'tab bar' is commonly found in most iOS apps and is used to present distinct views in each tab.
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.
http://www.riptutorial.com/ 917
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.
Programmatically:
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")
Navigation controller can be embed in each tabs using storyboard it self. It can be like in the
screenshot added.
To add a Navigation Controller to a View Controller connecting from Tab Bar Controller, here are
the flow
http://www.riptutorial.com/ 918
• 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
http://www.riptutorial.com/ 919
[[UINavigationBar appearance] setTintColor:[UIColor whiteColor]];
[[UINavigationBar appearance] setBarStyle:UIBarStyleBlack];
UITabBarController building in Swift 3 Change image color and title according to selection with
changing selected tab color.
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)
http://www.riptutorial.com/ 920
color.setFill()
UIRectFill(rect)
let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return image
}
http://www.riptutorial.com/ 921
Create Tab Bar controller programmatically without Storyboard
window?.backgroundColor = UIColor.black
firstTabNavigationController = UINavigationController.init(rootViewController:
FirstViewController())
secondTabNavigationControoller = UINavigationController.init(rootViewController:
SecondViewController())
thirdTabNavigationController = UINavigationController.init(rootViewController:
ThirdViewController())
fourthTabNavigationControoller = UINavigationController.init(rootViewController:
FourthViewController())
fifthTabNavigationController = UINavigationController.init(rootViewController:
FifthViewController())
tabBarController.viewControllers = [firstTabNavigationController,
http://www.riptutorial.com/ 922
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
}
http://www.riptutorial.com/ 923
Chapter 195: UITableView
Introduction
A simple, widely-used, yet very powerful view that can present data in a list form using rows and a
single column. Users may scroll vertically through the items in a table view, and optionally
manipulate and select content.
Syntax
• - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath
*)indexPath;
• - (CGFloat)tableView:(UITableView *)tableView
heightForHeaderInSection:(NSInteger)section;
• - (CGFloat)tableView:(UITableView *)tableView
heightForFooterInSection:(NSInteger)section;
• - (UITableViewCellAccessoryType)tableView:(UITableView *)tableView
accessoryTypeForRowWithIndexPath:(NSIndexPath *)indexPath
• - (void)tableView:(UITableView *)tableView
accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath;
• - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView
editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath;
http://www.riptutorial.com/ 924
• - (BOOL)tableView:(UITableView *)tableView
shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath;
• - (void)tableView:(UITableView*)tableView willBeginEditingRowAtIndexPath:(NSIndexPath
*)indexPath;
• - (void)tableView:(UITableView*)tableView didEndEditingRowAtIndexPath:(NSIndexPath
*)indexPath;
• - (NSInteger)tableView:(UITableView *)tableView
indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath;
• - (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section;
• - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
• - (void)tableView:(UITableView *)tableView
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath;
http://www.riptutorial.com/ 925
Remarks
UITableView is a subclass of UIScrollView. Classes that follow the UITableViewDelegate protocol also
follow the UIScrollViewDelegate protocol. UITableView can be useful for showing long or
indeterminate lists through its cells, whilst UIScrollView is better for when the size of the views to
be shown is known beforehand.
Examples
Delegate and Datasource
The UITableViewDelegate is used to control how the table is displayed, and UITableViewDataSource is
used to define the UITableView's data. There are two required methods and many optional ones
which can be used to customize size, sections, headings, and cells in the UITableView.
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.
Objective-C
http://www.riptutorial.com/ 926
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath {
MyCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyCustomCell"
forIndexPath:indexPath];
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
http://www.riptutorial.com/ 927
default:
return nil
}
}
titleForFooterInSection: Defines a string as the title for each section header in the
table view.
Objective-C
Swift 3
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];
http://www.riptutorial.com/ 928
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
http://www.riptutorial.com/ 929
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;
}
http://www.riptutorial.com/ 930
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
http://www.riptutorial.com/ 931
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 33
}
Custom Cells
Customizing a UITableViewCell can allow for very powerful, dynamic, and responsive interfaces.
With extensive customization and in combination with other techniques you can do things like:
update specific properties or interface elements as they change, animate or draw things in the cell,
efficiently load video as the user scrolls, or even display pictures as they download from a
network. The possibilities here are nearly endless. Below is a simple example of what a custom
cell may look like.
http://www.riptutorial.com/ 932
This section covers the basics, and hopefully will be expanded to detail more complex processes
like those described above.
Swift
http://www.riptutorial.com/ 933
class CustomTableViewCell: UITableViewCell {
static var identifier: String {
return NSStringFromClass(self)
}
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
http://www.riptutorial.com/ 934
override func viewDidLoad() {
super.viewDidLoad()
Swift
// Register Nib
tableView.register(UINib(nibName: CustomTableViewCell.identifier, bundle: nil),
forCellReuseIdentifier: CustomTableViewCell.identifier)
Now that your tableView knows about your custom cell, you can dequeue it in
cellForRowAtIndexPath:
Swift
// This is where the magic happens - setting a custom property on your very own cell
cell.customLabel.text = "My Custom Cell"
return cell
}
Creating a UITableView
A Table View is a list of rows that can be selected. Each row is populated from a data source. This
example creates a simple table view in which each row is a single line of text.
http://www.riptutorial.com/ 935
Add a UITableView to your Storyboard
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).
http://www.riptutorial.com/ 936
Creating a simple 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:
Swift
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
http://www.riptutorial.com/ 937
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) ->
UITableViewCell {
// Create a new cell here. The cellReuseIdentifier needs to match the reuse
identifier from the cell in your Storyboard
let cell: UITableViewCell =
tableView.dequeueReusableCellWithIdentifier(cellReuseIdentifier) as UITableViewCell!
// 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:
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
http://www.riptutorial.com/ 938
selections you'll need to use the following method:
// Swift
// Objective-C
Swift
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
// Data model: These strings will be the data for the table view cells
let myDataArray: [String] = ["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
}
http://www.riptutorial.com/ 939
// create a cell for each table view row
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) ->
UITableViewCell {
return cell
}
Objective-C
ViewController.h
#import <UIKit/UIKit.h>
@end
ViewController.m
#import "ViewController.h"
@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;
}
http://www.riptutorial.com/ 940
// number of rows in table view
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return myDataArray.count;
}
return cell;
}
@end
Self-Sizing Cells
In iOS 8 Apple introduced the self sizing cell. Layout your UITableViewCells with Autolayout
explicitly and UITableView takes care of the rest for you. Row height is calculated automatically,
by default rowHeight value is UITableViewAutomaticDimension.
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
http://www.riptutorial.com/ 941
}
Objective-C
I always think it is nice to have a very simple, self-contained example so that nothing is assumed
when I am learning a new task. This answer is that for deleting UITableView rows. The project
performs like this:
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"]
http://www.riptutorial.com/ 942
override func viewDidLoad() {
super.viewDidLoad()
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 {
http://www.riptutorial.com/ 943
// remove the item from the data model
animals.removeAtIndex(indexPath.row)
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
In your Storyboard, add a UITableView object on your UIViewController and let it cover the entire
view. Setup the UITableviewDataSource and UITableviewDelegate connections.
Objective-C
In your .h file
NSMutableArray *arrayForBool;
NSMutableArray *sectionTitleArray;
http://www.riptutorial.com/ 944
In your .m file
- (void)viewDidLoad {
[super viewDidLoad];
_tableView.dataSource = self;
_tableView.delegate = self;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [sectionTitleArray count];
http://www.riptutorial.com/ 945
}
return sectionView;
- (void)sectionHeaderTapped:(UITapGestureRecognizer *)gestureRecognizer{
http://www.riptutorial.com/ 946
if (indexPath.section==i) {
[arrayForBool replaceObjectAtIndex:i withObject:[NSNumber
numberWithBool:!collapsed]];
}
}
[_expandableTableView reloadSections:[NSIndexSet
indexSetWithIndex:gestureRecognizer.view.tag]
withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
Separator Lines
Objective-C
[cell setLayoutMargins:UIEdgeInsetsZero];
Swift
http://www.riptutorial.com/ 947
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 property at any time before loading or reloading the table view (does not necessarily
need to be in the viewDidLoad: method).
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.
Swift
tableView.tableFooterView = UIView()
Objective-C
http://www.riptutorial.com/ 948
http://www.riptutorial.com/ 949
Chapter 196: UITableViewCell
Introduction
Load custom cell xib file uses the cell category class, no need to register the nib file
Examples
Xib file of UITableViewCell
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
http://www.riptutorial.com/ 950
*)indexPath
{
//Creted custom cell xib file to load by cell category class
CustomCell *cell = [[CustomCell alloc]initWithOwner:self];
return cell;
}
http://www.riptutorial.com/ 951
Chapter 197: UITableViewController
Introduction
UITableViewController controller object that manages a table view. For some certain scenario it
will be recommended to use UITableViewController, for example if you have lot of cells and some
have UITextfield.
Examples
TableView with dynamic properties with tableviewCellStyle basic.
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// return the number of rows inside the tableview.
return 3
}
return cell
}
http://www.riptutorial.com/ 952
TableView with Custom Cell
For custom tableview cell you need a class that is subclass from UITableViewCell, an example
class you can see below.
http://www.riptutorial.com/ 953
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// return the number of rows inside the tableview.
return 3
}
return cell
}
http://www.riptutorial.com/ 954
Chapter 198: UITextField
Introduction
UITextField is part of UIKit framework and is used to display an area to collect text input from the
user using the onscreen keyboard
Syntax
• UITextField.text: String // get or set the text the field displays.
• UITextField.attributedText: NSAttributedString // get or set the attributed text the field
displays.
• UITextField.textColor: UIColor // get or set the color of the text on the field
• UITextField.font: UIFont // get or set the font of the text on the field
• UITextField.textAlignment: NSTextAlignment // default is NSLeftTextAlignment
• UITextField.borderStyle: UITextBorderStyle // default is UITextBorderStyleNone. If set to
UITextBorderStyleRoundedRect, custom background images are ignored.
• UITextField.placeholder: String // default is nil. string is drawn 70% gray
• UITextField.attributedPlaceholder: NSAttributedString // get or set the attributed placeholder
of the field
• UITextField.clearsOnBeginEditing: Bool // default is NO which moves cursor to location
clicked. if YES, all text cleared
• UITextField.adjustsFontSizeToFitWidth: Bool // default is NO. if YES, text will shrink to
minFontSize along baseline
• UITextField.minimumFontSize: CGFloat // default is 0.0. actual min may be pinned to
something readable. used if adjustsFontSizeToFitWidth is YES
• UITextField.delegate: UITextFieldDelegate? // default is nil. weak reference
• UITextField.clearButtonMode: UITextFieldViewMode // sets when the clear button shows up.
default is UITextFieldViewModeNever
• UITextField.leftView: UIView? // e.g. magnifying glass
• UITextField.leftViewMode: UITextFieldViewMode // sets when the left view shows up. default
is UITextFieldViewModeNever
• UITextField.rightView: UIView? // e.g. bookmarks button
• UITextField.rightViewMode: UITextFieldViewMode // sets when the right view shows up.
default is UITextFieldViewModeNever
• UITextField.inputView: UIView? // Presented when object becomes first responder. If set to
nil, reverts to following responder chain. If set while first responder, will not take effect until
reloadInputViews is called.
• UITextField.inputAccessoryView: UIView?
• UITextField.isSecureTextEntry : Bool // e.g If field contain confidential input like password or
card number
Examples
http://www.riptutorial.com/ 955
Getting and Setting the Cursor Position
Useful information
The very beginning of the text field text:
print("\(cursorPosition)")
}
To the beginning
To the end
http://www.riptutorial.com/ 956
// only if there is a currently selected range
if let selectedRange = textField.selectedTextRange {
To an arbitrary position
Related
Select all text
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
http://www.riptutorial.com/ 957
• This example originally comes from this Stack Overflow answer.
• 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)
To hide the blinking caret, you need to override caretRectForPosition of a UITextField and return
CGRectZero.
Swift 3
Objective-C
http://www.riptutorial.com/ 958
if let placeholder = textField.placeholder {
let newAttributedPlaceholder = NSAttributedString(string: placeholder, attributes:
placeholderAttributes)
textField.attributedPlaceholder = newAttributedPlaceholder
}
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.
Create a UITextField
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)];
Dismiss Keyboard
Swift
Ctrl + Drag from the UItextfield in MainStoryboard to the ViewController Class and create a
UITextField Outlet
http://www.riptutorial.com/ 959
http://www.riptutorial.com/ 960
After that select the UItextField again and Ctrl+drag in ViewController class but this time select
Action connection and on storage select Did End On Exit then click connect.
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.
http://www.riptutorial.com/ 961
@IBOutlet var textField: UITextField!
Objective-C
[textField resignFirstResponder];
Set Alignment
Swift
textField.textAlignment = .Center
Objective-C
In the example, we have set the NSTextAlignment to center. You can also set to .Left, .Right,
.Justified and .Natural.
.Naturalis 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.
Swift
http://www.riptutorial.com/ 962
Objective-C
Interface Builder
You can also add a UITextField to a storyboard by dragging it from Object Library.
Add an accessory view above the keyboard. This is commonly used for adding next/previous
buttons, or additional buttons like Done/Submit (especially for the number/phone/decimal pad
keyboard types which don't have a built-in return key).
Swift
textField.inputAccessoryView = toolbar
Objective-C
http://www.riptutorial.com/ 963
UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(done)];
NSArray *items = @[
flexibleSpace,
doneButton
];
[toolbar setItems:items];
[toolbar sizeToFit];
textField.inputAccessoryView = toolbar;
Autocapitalization
Swift
textField.autocapitalizationType = .None
Objective-C
textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
All options:
KeyboardType
To change the appearance of the keyboard, the following types can be set individually on every
UITextFields property: keyboardType
http://www.riptutorial.com/ 964
(shows space @ . prominently).
UIKeyboardTypeDecimalPad NS_ENUM_AVAILABLE_IOS(4_1), // A number pad with a decimal
point.
UIKeyboardTypeTwitter NS_ENUM_AVAILABLE_IOS(5_0), // A type optimized for twitter
text entry (easy access to @ #)
UIKeyboardTypeWebSearch NS_ENUM_AVAILABLE_IOS(7_0), // A default keyboard type with
URL-oriented addition (shows space . prominently).
Setup your view controller to manage editing of text for the text field.
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;
}
- (void)viewDidLoad
{
[super viewDidLoad];
http://www.riptutorial.com/ 965
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:self.view.window];
// register for keyboard notifications
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:self.view.window];
}
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
* that should be visible, e.g. a purchase button below an amount text field
* it makes sense to set _focusedControl in delegates like -textFieldShouldBeginEditing:
if you have multiple input fields
*/
if (_focusedControl) {
CGRect controlFrameInScrollView = [_scrollView convertRect:_focusedControl.bounds
fromView:_focusedControl]; // if the control is a deep in the hierarchy below the scroll view,
this will calculate the frame as if it were a direct subview
controlFrameInScrollView = CGRectInset(controlFrameInScrollView, 0, -10); // replace
10 with any nice visual offset between control and keyboard or control and top of the scroll
view.
http://www.riptutorial.com/ 966
controlFrameInScrollView.size.height;
// 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];
}
http://www.riptutorial.com/ 967
Get Focus
Swift
textField.becomeFirstResponder()
Objective-C
[textField becomeFirstResponder];
Resign
Swift
textField.resignFirstResponder()
Objective-C
[textField resignFirstResponder];
In some cases, you want to show your users a UIPickerView with predefined contents for a
UITextField instead of a keyboard.
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:
http://www.riptutorial.com/ 968
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 {
get {
if data != nil {
return data![selectedRow(inComponent: 0)]
} else {
return ""
}
}
}
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?
http://www.riptutorial.com/ 969
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.
http://www.riptutorial.com/ 970
pickerAccessory?.items = [cancelButton, flexSpace, doneButton]
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:
http://www.riptutorial.com/ 971
picker?.selectRow(3, inComponent: 0, animated: false) //Will select the row at index 3
http://www.riptutorial.com/ 972
Chapter 199: UITextField Delegate
Examples
UITextField - Restrict textfield to certain characters
If you want to perform a user input validation of your textfield use the following code snippet:
// 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:
http://www.riptutorial.com/ 973
Actions when a user has started/ended interacting with a textfield
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:
http://www.riptutorial.com/ 974
If you want to have control over whether a TextField should begin/end editing, the
textFieldShouldBeginEditing(_:) and textFieldShouldEndEditing(_:) methods can be used by return
true/false based on your needed logic.
The text field calls different delegate methods (only if delegates are set)One of delegate method
called by textfield is *- (BOOL)textFieldShouldReturn:(UITextField )textField
This method is called whenever users taps the return button.By using this method, we can
implement any custom behaviour.
For Example,
In the below example ,next responder will be find out on the basis of tag and manage
the keyboard. Here 20 is the constant,As tag assigned to textfield are like this 50,70,90
etc.
Here on finding a new textfield object as responder,it will make current text field as new
responder and open keyboard accordingly.
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
http://www.riptutorial.com/ 975
Chapter 200: UITextView
Examples
Change text
Swift
Objective-C:
// Add tint.
attributedText.addAttribute(NSForegroundColorAttributeName, value: UIColor.blue, range:
tintedRange)
// Add highlight.
attributedText.addAttribute(NSBackgroundColorAttributeName, value: UIColor.yellow, range:
highlightedRange)
textView.attributedText = attributedText
Swift
textView.textAlignment = .left
Objective-C
textView.textAlignment = NSTextAlignmentLeft;
UITextViewDelegate methods
http://www.riptutorial.com/ 976
Responding to Editing Notifications
• textViewShouldBeginEditing(_:)
• textViewDidBeginEditing(_:)
• textViewShouldEndEditing(_:)
• textViewDidEndEditing(_:)
• textView(_:shouldChangeTextIn:replacementText:)
• textViewDidChange(_:)
Responding to URL
Change font
Swift
//System Font
textView.font = UIFont.systemFont(ofSize: 12)
Objective-C
//System Font
textView.font = [UIFont systemFontOfSize:12];
Swift
textView.textColor = UIColor.red
Objective-C
Swift
http://www.riptutorial.com/ 977
// Do stuff for nil text or empty string
}
Objective-C
UITextViewhas built in support to auto detect a variety of data. The data that is able to be auto-
detected currently includes:
enum {
UIDataDetectorTypePhoneNumber = 1 << 0,
UIDataDetectorTypeLink = 1 << 1,
UIDataDetectorTypeAddress = 1 << 2,
UIDataDetectorTypeCalendarEvent = 1 << 3,
UIDataDetectorTypeNone = 0,
UIDataDetectorTypeAll = NSUIntegerMax
};
Enabling auto-detection
// you may add as many as you like by using the `|` operator between options
textView.dataDetectorTypes = (UIDataDetectorTypeLink | UIDataDetectorTypePhoneNumber);
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
http://www.riptutorial.com/ 978
NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType }
documentAttributes: nil
error: nil
];
_yourTextView.attributedText = attributedString;
// If you want to modify the font
field.font = [UIFont fontWithName:@"Raleway-Regular" size:15];
has extra paddings by default. Sometimes it's annoying especially if you want to
UITextView
measure some text without view instance and place them at some area precisely.
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.
Useful information
The very beginning of the text field text:
http://www.riptutorial.com/ 979
let cursorPosition = textView.offsetFromPosition(textView.beginningOfDocument, toPosition:
selectedRange.start)
print("\(cursorPosition)")
}
To the beginning
To the end
To an arbitrary position
http://www.riptutorial.com/ 980
Related
Select all text
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)
http://www.riptutorial.com/ 981
Chapter 201: UIView
Syntax
1. // Objective-C
3. [[UIView alloc] initWithFrame:(Pass CGRect)] // Get the view allocated and initialized with a
frame
5. // Swift
Remarks
The UIView class defines a rectangular area on the screen and the interfaces for managing the
content in that area. At runtime, a view object handles the rendering of any content in its area and
also handles any interactions with that content.
Examples
Animating a UIView
http://www.riptutorial.com/ 982
Create a UIView
Objective-C
Swift
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
http://www.riptutorial.com/ 983
//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:
Note
#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.
http://www.riptutorial.com/ 984
Swift Extension
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()
Taking a snapshot
Swift
Objective-C
http://www.riptutorial.com/ 985
One (or two) of the coolest new features in recent Xcode releases are the IBInspectable properties
and IBDesignable UIViews. These have nothing to do with the functionality of your application but
instead impact the developer experience in Xcode. The goal is to be able to visually inspect
custom views in your iOS application without running it. So assume that you have a custom view
creatively named CustomView that inherits from UIView. In this custom view, it will display a string of
text with a designated color. You can also choose not to display any text. We'll need three
properties:
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
http://www.riptutorial.com/ 986
@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.
Finally, setting Show Text to Off in the property inspector makes the text display in Interface
Builder disappear.
http://www.riptutorial.com/ 987
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 {
When creating a UIView subclass, intrinsic content size helps to avoid setting hardcoded height
and width constraints
http://www.riptutorial.com/ 988
a basic glimpse into how a class can utilize this
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.
http://www.riptutorial.com/ 989
Interface builder will complain to you at this point giving the following warning:
http://www.riptutorial.com/ 990
This is where Placeholder Intrinsic Size comes in.
Going into the Size inspector panel, and down to the Intrinsic Size dropdown, you can switch this
value from Default to Placeholder.
and now interface builder will remove the previous warnings and you can use this size to have
dynamically sized views laid out in interface builder.
[self.view addSubview:view];
http://www.riptutorial.com/ 991
//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
http://www.riptutorial.com/ 992
addedOnParentView:(UIView*)parentView{
subView.translatesAutoresizingMaskIntoConstraints = NO;
Suppose you have a parentView into which you want to insert a new subView programmatically (eg.
when you want to insert an UIImageView into a UIViewController's view), than you can do it as below.
Objective-C
[parentView addSubview:subView];
Swift
http://www.riptutorial.com/ 993
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
Objective-C
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()
If we want to get the x-cordinate of origin of the view, then we need to write like:
http://www.riptutorial.com/ 994
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
view.x = 10
view.y = 10
view.width = 100
view.height = 200
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)
}
}
http://www.riptutorial.com/ 995
return self.frame.height
}
set {
self.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width:
self.frame.size.width, height: newValue)
}
}
}
We need to add this class file in a project and it'll be available to use throughout the project!
Shake a View
extension UIView {
func shake() {
let animation = CAKeyframeAnimation(keyPath: "transform.translation.x")
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
animation.duration = 0.6
animation.values = [-10.0, 10.0, -7.0, 7.0, -5.0, 5.0, 0.0 ]
layer.add(animation, forKey: "shake")
}
}
This function can be used to draw attention to a specific view by shaking it a bit.
http://www.riptutorial.com/ 996
Chapter 202: UIViewController
Examples
Set the view programmatically
Swift
Create an instance
Swift
Objective-C
Subclassing
• beginTrackingWithTouch is called when the finger first touches down within the control's
bounds.
• continueTrackingWithTouchis 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()
}
http://www.riptutorial.com/ 997
// 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
This is how the view controller is set up to be the delegate and respond to touch events from our
custom control.
import UIKit
class ViewController: UIViewController, ViewControllerCommunicationDelegate {
func myTrackingBegan() {
trackingBeganLabel.text = "Tracking began"
}
http://www.riptutorial.com/ 998
yLabel.text = "y: \(location.y)"
}
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 {
With an Identifier:
Give the scene a Storyboard ID within the identity inspector of the storyboard.
http://www.riptutorial.com/ 999
Instantiate in code:
Within the storyboard select the view controller, then select the attribute inspector, check the "Is
Initial View Controller" box.
When the view controller is presented within a tab bar controller, you can access the tab bar
controller like this:
http://www.riptutorial.com/ 1000
Swift
Objective-C
When the view controller is part on an navigation stack, you can access the navigation controller
like this:
Swift
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];
}
http://www.riptutorial.com/ 1001
Chapter 203: UIWebView
Remarks
UIWebView Delegate functions:-
Objective-C Declerations
- (BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType;
- (void)webView:(UIWebView *)webView
didFailLoadWithError:(NSError *)error;
- (void)webViewDidFinishLoad:(UIWebView *)webView;
- (void)webViewDidStartLoad:(UIWebView *)webView;
Examples
Load JavaScript
Swift
webview.stringByEvaluatingJavaScriptFromString("alert('This is JavaScript!');")
Objective-C
http://www.riptutorial.com/ 1002
[webview stringByEvaluatingJavaScriptFromString:@"alert('This is JavaScript!');"];
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
Swift
http://www.riptutorial.com/ 1003
A local base URL may be specified. This is useful to reference images, stylesheets or scripts from
the app bundle:
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.
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];
}
http://www.riptutorial.com/ 1004
return NO;
return YES;
First, add the HTML File to your Project (If you are asked to choose options for adding the file,
select Copy items if needed)
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 many cases, for instance when using web views in table view cells, it's important to determine
the content size of the rendered HTML page. After loading the page, this can be calculated in the
UIWebViewDelegate delegate method:
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
webview.stopLoading()
http://www.riptutorial.com/ 1005
Objective-C
[webview stopLoading];
Swift
webview.reload()
Objective-C
[webview reload];
Swift
Objective-C
Swift
Objective-C
http://www.riptutorial.com/ 1006
Chapter 204: Universal Links
Remarks
1. When you support universal links, iOS 9 users can tap a link to your website and get
seamlessly redirected to your installed app without going through Safari. If your app isn’t
installed, tapping a link to your website opens your website in Safari.
2. Generally, any supported link clicked in Safari, or in instances of UIWebView/WKWebView should
open the app.
3. For iOS 9.2 and less, this will only work on a device. iOS 9.3 also supports the simulator.
4. iOS remembers the user’s choice when opening Universal Links. If they tap the top-right
breadcrumb to open the link in Safari, all further clicks will take them to Safari, and not the
app. They can switch back to opening the app by default by choosing Open in the app
banner on the website.
Examples
Setup Server
You need to having a server running online. To securely associate your iOS app with a server,
Apple requires that you make available a configuration file, called apple-app-site-association. This
is a JSON file which describes the domain and supported routes.
The apple-app-site-association file needs to be accessible via HTTPS, without any redirects, at
https://{domain}/apple-app-site-association.
{
"applinks": {
"apps": [ ],
"details": [
{
"appID": "{app_prefix}.{app_identifier}",
"paths": [ "/path/to/content", "/path/to/other/*", "NOT /path/to/exclude" ]
},
{
"appID": "TeamID.BundleID2",
"paths": [ "*" ]
}
]
}
}
http://www.riptutorial.com/ 1007
: Is an array of dictionaries, one for each iOS app supported by the website. Each dictionary
contains information about the app, the team and bundle IDs.
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
Each domain supported in the app needs to make available its own apple-app-site-association file.
If the content served by each domain is different, then the contents of the file will also change to
support the respective paths. Otherwise, the same file can be used, but it needs to be accessible
at every supported domain.
Note: You can skip this part if your server uses HTTPS to serve content and jump to Application
Setup guide.
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.
http://www.riptutorial.com/ 1008
Note: If the file is unsigned, it should have a Content-Type of application/json. Otherwise, it should
be application/pkcs7-mime.
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.
http://www.riptutorial.com/ 1009
Next, get the App ID prefix and suffix by clicking on the respective App ID.
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:
http://www.riptutorial.com/ 1010
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.
http://www.riptutorial.com/ 1011
2. Handling Incoming Links in your AppDelegate
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
http://www.riptutorial.com/ 1012
}
}
return YES;
}
Swift :
http://www.riptutorial.com/ 1013
Chapter 205: Using Image Aseets
Introduction
Image assets are used to manage and organize different types of image assets in our iOS app
using Xcode.
These assets can be App Icons, Launch Images, images used throughout the app, full size
images, random sized images etc.
Examples
App Icon using Image Assets
Whenever we create a new project in Xcode for our new app, it gives us various in-built classes,
targets, tests, plist file, etc. Similarly it also gives us as Assets.xcassets file, which manages all the
image assets in our project.
http://www.riptutorial.com/ 1014
http://www.riptutorial.com/ 1015
We just have to drag and drop respective image on each empty square block. Each black will tell
us what size that image should be, it's written just below it.
After dragging and dropping all the images in all the squares, it'll look like this:
http://www.riptutorial.com/ 1016
http://www.riptutorial.com/ 1017
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
http://www.riptutorial.com/ 1018
Chapter 206: UUID (Universally Unique
Identifier)
Remarks
To save the UUID we can use SSKeychainUtility. Example can be found on Github page
Examples
Generating UUID
Random UUID
Swift
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);
CFRelease(uuidRef);
NSString *uuid = [((__bridge NSString *) cfuuid) copy];
CFRelease(cfuuid);
return uuid;
}
iOS 6
Swift
http://www.riptutorial.com/ 1019
Objective-C
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.
Apple's IFA vs. IFV (Apple Identifier for Advertisers vs. Identifier for Vendors)
• You can use the IFA for measuring ad clicks and the IFV for measuring app installs.
• IFA has built-in privacy mechanisms that make it perfect for advertising. In contrast, the IFV
is for developers to use internally to measure users who install their apps.
IFA
IFV
Represents UUID strings, which can be used to uniquely identify types, interfaces, and other
items.
Swift 3.0
print(UUID().uuidString)
http://www.riptutorial.com/ 1020
universally-unique-identifier-
http://www.riptutorial.com/ 1021
Chapter 207: WCSessionDelegate
Introduction
WCSessionDelegateworks with watch OS2 + using WatchConnectivity. var watchSession :
WCSession? func startWatchSession(){ if(WCSession.isSupported()){ watchSession =
WCSession.default() watchSession!.delegate = self watchSession!.activate() } } Implement the
required method:- didReceiveApplicationContext
Examples
Watch kit controller (WKInterfaceController)
import WatchConnectivity
func startWatchSession(){
if(WCSession.isSupported()){
watchSession = WCSession.default()
watchSession!.delegate = self
watchSession!.activate()
}
}
http://www.riptutorial.com/ 1022
Chapter 208: WKWebView
Introduction
WKWebView is the centerpiece of the modern WebKit API introduced in iOS 8 & OS X Yosemite.
It replaces UIWebView in UIKit and WebView in AppKit, offering a consistent API across the two
platforms.
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.
Examples
Creating a Simple WebBrowser
import UIKit
import WebKit
self.initControls()
self.setTheme()
self.doLayout()
}
func initControls() {
self.searchbar = UISearchBar()
http://www.riptutorial.com/ 1023
self.webView = WKWebView(frame: .zero, configuration: configuration)
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
http://www.riptutorial.com/ 1024
//Setup which views will be constrained.
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
http://www.riptutorial.com/ 1025
}
}
//WebView Delegates
//Handle the error. Display an alert to the user telling them what happened.
http://www.riptutorial.com/ 1026
func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
//When the content for the webpage starts arriving, this is called.
}
//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 navigationAction: WKNavigationAction, windowFeatures:
WKWindowFeatures) -> WKWebView? {
//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-|")
http://www.riptutorial.com/ 1027
//TODO: Add the containerView to self.view or present it with a new controller. Keep
track of tabs..
return webView
}
http://www.riptutorial.com/ 1028
http://www.riptutorial.com/ 1029
more than once, results in NSInvalidArgumentExceptionexception.
http://www.riptutorial.com/ 1030
Chapter 209: Xcode Build & Archive From
Command Line
Syntax
• xcodebuild [-project name.xcodeproj] -scheme schemename [[-destination
destinationspecifier] ...] [-destination-timeout value] [-configuration configurationname]
[-sdk [sdkfullpath | sdkname]] [action ...] [buildsetting=value ...] [-userdefault=value
...]
Parameters
Option Description
Remarks
Run xcodebuild from the directory containing your project to build an Xcode project. To build an
Xcode workspace, you must pass both the -workspace and -scheme options to define the build.
The parameters of the scheme will control which targets are built and how they are built, although
you may pass other options to xcodebuild to override some parameters of the scheme.
Examples
Build & Archive
Build:
Archive:
http://www.riptutorial.com/ 1031
xcodebuild -project <ProjectName.xcodeproj>
-scheme <ProjectName>
-sdk iphonesimulator
-configuration Debug
-destination "platform=iOS Simulator,name=<Device>,OS=9.3"
clean build
http://www.riptutorial.com/ 1032
Chapter 210: XCTest framework - Unit Testing
Examples
Writing a test class
import XCTest
@testable import PersonApp
Now let's discuss what's going on here. The import XCTest line will allow us to extend XCTestCase
and use XCTAssertEqual (among other assertions). Extending XCTestCase and prefixing our test
name with test will ensure that Xcode automatically runs this test when running the tests in the
project (U or Product > Test). The @testable import PersonApp line will import our PersonApp target
so we can test and use classes from it, such as the Person in our example above. And finally, our
XCTAssertEqual will ensure that person.completeName() is equal to the string "Josh Brown".
2- Go to "Targets"
http://www.riptutorial.com/ 1033
3- Click "Add Target"
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 testExample() {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
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
http://www.riptutorial.com/ 1034
@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
To get started with unit testing, which will be done in the tests file and will be testing the View
Controller and Storyboard, we should introduce these two files to the test file.
Swift
http://www.riptutorial.com/ 1035
Objective-C
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.
According to Apple:
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 assert that
improper use of a method in one of your classes throws an exception.
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(){
http://www.riptutorial.com/ 1036
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)
Start Testing
If there is a red cross next to the definition, the test has failed.
http://www.riptutorial.com/ 1037
Running all tests
Product -> Test OR Cmd + U
It will run all the tests from all the test targets!
Classes, structs, enums and all their methods are internal by default. This means they can be
only accessed from the same module. The test cases are in a different target an this means they
are in a different module. To be able to access the method you want to test, you need to import
the module to be tested using the @testable keyword.
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.
View loading
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 test), then the code would look like this:
XCTAssertNotNil(sut.view)
View appearance
You can also trigger the methods viewWillAppear(_:) and viewDidAppear(_:) by adding the following
code:
http://www.riptutorial.com/ 1038
sut.endAppearanceTransition()
http://www.riptutorial.com/ 1039
Credits
S.
Chapters Contributors
No
ADDING A SWIFT
4 yogesh wadhwa
BRIDGING HEADER
Application rating/review
13 Abhijit
request
http://www.riptutorial.com/ 1040
ARC (Automatic
14 4444, Irfan, John Militer, Ketan P, Tricertops
Reference Counting)
http://www.riptutorial.com/ 1041
31 CGContext Reference 4444, Narendra Pandey
Content Hugging/Content
43 Mehul Chuahan
Compression in Autolayout
Convert HTML to
44 NSAttributed string and Md. Ibrahim Hassan
vice verse
Convert
45 NSAttributedString to Md. Ibrahim Hassan
UIImage
http://www.riptutorial.com/ 1042
50 Core SpotLight in iOS Md. Ibrahim Hassan
Create a Custom
53 Saeed-rz
framework in iOS
Custom methods of
59 selection of Kamil Harasimowicz
UITableViewCells
Dynamically updating a
68 Harshal Bhavsar, Rahul, Stephen Leppik
UIStackView
http://www.riptutorial.com/ 1043
Notification - iOS 10.
GameCenter
76 4444, Cyril Ivar Garcia, Harshal Bhavsar, Stephen Leppik
Leaderboards
Handle Multiple
81 Tien
Environment using Macro
iOS - Implementation of
88 XMPP with Robbie Saheb Roy
Hanson framework
iOS 10 Speech
89 rohit90, Stephen Leppik
Recognition API
http://www.riptutorial.com/ 1044
91 iOS TTS Ali Abbas, Stephen Leppik
106 MyLayout
http://www.riptutorial.com/ 1045
Bonnie, Charles, dasdom, Dunja Lalic, ERbittuu,
FelixSFD, Harshal Bhavsar, Jon Snow, Josh Caswell,
lostAtSeaJoshua, maxkonovalov, Mehul Thakkar,
112 NSDate
NSNoob, Nykholas, OhadM, Sally, Samuel Teferra,
Sandy, Seyyed Parsa Neshaei, Stephen Leppik, tharkay,
tobeiosdeveloper
Objective-C Associated
123 Noam
Objects
http://www.riptutorial.com/ 1046
MessageBox-Concept)
http://www.riptutorial.com/ 1047
148 StoreKit askielboe
http://www.riptutorial.com/ 1048
Harshal Bhavsar, Honey, ing0, iphonic, Irfan, JAL, Jaleel
Nazir, Jojodmo, Luca D'Alberti, maxkonovalov, mtso,
nielsbot, NSNoob, pableiros, Reinier Melian, Rex, Sally,
Samer Murad, Sandy, shim, The_Curry_Man, Tommie C.,
Viktor Simkó, WMios, Yagnesh Dobariya
http://www.riptutorial.com/ 1049
Community, Daniel Bocksteger, Daniel Stradowski,
danshevluk, dasdom, ddb, DeyaEldeen, Dunja Lalic, Eric,
Erwin, esthepiking, Fabio Berger, Fahim Parkar, Felix,
FelixSFD, Franck Dernoncourt, gadu, ggrana,
GingerHead, gvuksic, HaemEternal, hankide, Hans
Sjunnesson, Harshal Bhavsar, Hossam Ghareeb, idobn,
Imanou Petit, iOS BadBoy, iphonic, Irfan, J F, Jacky,
Jacobanks, johnpenning, Jojodmo, Josh Brown, Joshua,
Joshua J. McKinnon, jtbandes, juanjo, kabiroberai, Kai
Engelhardt, KANGKANG, Khanh Nguyen, Kireyin, leni,
Luca D'Alberti, lufritz, Lukas, Luke Patterson, Lumialxk,
Mad Burea, Mahmoud Adam, Md. Ibrahim Hassan,
Moshe, Nadzeya, Narendra Pandey, Nathan Levitt, Nirav
D, njuri, noelicus, NSNoob, Ollie, Quantm, Radagast the
Brown, Rahul Vyas, RamenChef, ramsserio, rfarry,
sage444, Scotow, Seyyed Parsa Neshaei, Shahabuddin
Vansiwala, solidcell, Sravan, stackptr, Sunil Sharma,
Suragch, sushant jagtap, TDM, tharkay, The_Curry_Man,
Tibor Molnár, Tyler, Undo, user3480295, vasili111,
Vignan, Viktor Simkó, william205, WMios, Yagnesh
Dobariya
UIRefreshControl
180 Md. Ibrahim Hassan, Mohammad Rana
TableView
http://www.riptutorial.com/ 1050
182 UIScrollView AutoLayout Aaron, Brandon, Shrikant K
UIScrollView with
183 mourodrigo
StackView child
196 UITextField Delegate Andreas, animuson, Md. Ibrahim Hassan, midori, Ruby
http://www.riptutorial.com/ 1051
Adam Preble, alaphao, Anh Pham, Caleb Kleveter,
Community, Cory Wilhite, D4ttatraya, ddb, DeyaEldeen,
Douglas Starnes, hgwhittle, iphonic, Irfan, James,
Jojodmo, Jota, Kotha Sai Ram, Luca D'Alberti,
198 UIView maxkonovalov, Md. Ibrahim Hassan, muazhud, Narendra
Pandey, Nikhil Manapure, NSNoob, pableiros, pckill,
Peter DeWeese, Rahul Vyas, sasquatch, shallowThought
, Sunil Sharma, That lazy iOS Guy , The_Curry_Man,
Viktor Simkó, william205
XCTest framework - Unit D4ttatraya, dasdom, Jan ATAC, Josh Brown, msohng,
207
Testing Raphael Silva, Seyyed Parsa Neshaei, Tarun Seera
http://www.riptutorial.com/ 1052