Here is the code snippet to clear CocoaPods cache then re-download and reinstall all pods.
rm -rf “${HOME}/Library/Caches/CocoaPods“
rm -rf “`pwd`/Pods/“
pod update
Tweaking Apps
Here is the code snippet to clear CocoaPods cache then re-download and reinstall all pods.
rm -rf “${HOME}/Library/Caches/CocoaPods“
rm -rf “`pwd`/Pods/“
pod update
In this demo, we will be using PDFKit to View and Annotate PDF file. Let us start by selecting a Single View App template and name the project as PDFDemo.
For this demo, we will be using a PDF file “TheWakingLights.pdf” and this can downloaded from the github project folder. Now drag and drop this file to Xcode project and in “Choose options for adding these files” select “Copy items if needed”
In Xcode’s project navigator, select ViewController.swift and add the following lines after viewDidLoad function.
func openPDFDocument() { guard let path = Bundle.main.url(forResource: "TheWakingLights", withExtension: "pdf") else { return } let document = PDFDocument(url: path) let pdfView = PDFView(frame: view.frame) pdfView.document = document view.addSubview(pdfView)
This function does the following
guard let path = Bundle.main.url(forResource: "TheWakingLights", withExtension: "pdf") else { return }
Creates URL instance with the path of “TheWalkingLights.pdf” file.
Loads the pdf file in a PDFDocument object
let document = PDFDocument(url: path)
Creates an instance of PDFView and sets the frame to ViewController’s view then assigns the PDFDocument to PDFView instance.
let pdfView = PDFView(frame: view.frame) pdfView.document = document view.addSubview(pdfView)
You will be seeing couple of unresolved identified errors because of missing import PDFKit statement. Add import statement after import UIKit and now you should be able to run the app on the simulator and select text on the PDF
PDFKit provides option to add annotation to PDF file using PDFAnnoation class. Various annotation can be added like Circle, line, Strikeout, Square, Underline, Highlight etc.. Let us see a code example of adding highlight to PDF page.
Add the following code snippet after openPDFDocument function.
func highlightAnnotation() -> PDFAnnotation { let annotation = PDFAnnotation(bounds: CGRect(x: 30, y: 80, width: 230, height: 50), forType: .highlight, withProperties: nil) annotation.color = .yellow return annotation }
The above code does the following
In the openDocument function add the following line after view.addSubView(pdfview)
pdfView.currentPage?.addAnnotation(highlightAnnotation())
This gets the current page from PDFView and sets the highlight annotation. When you run the app on the simulation you will see the highlight as shown below.
Download the source code from here
Let us see an example TaskManager app using CoreData written in Swift Programming language. This app provides the following functionality
You can download source code for this project from Github. If you are familiar with user interface then move on to the Core Data implementation in Swift section
Create a new File -> New -> Project and select template Single View Application
Enter Product Name, Language as Swift and select “Use Core Data” for the new Project.
Delete ViewController.swift and Add new view controller which will be used for displaying the list of tasks.
Right click on the Project and select New File
Choose the template as Cocoa Touch under iOS -> Source
Enter name of the file as TaskManagerViewController with Subclass as UITableViewController and Language as Swift.
Navigate to Main.storyboard, delete the ViewController and add new TableViewController to the Storyboard
Embed this TableViewController inside a navigation controller. You can do this by clicking Editor menu -> Embed In -> Navigation Controller.
Navigate to Storyboard file and select Table View Controller. Click Identity Inspector and set the Class to the TaskManagerViewController.
Users can navigate to new task screen by tapping the button on the TaskManager. Drag and drop the button bar item to the navigation bar.
In the attributes inspector, set the identifier for button bar item as Add. Also enter title as “Task Manager” in the navigation bar.
Now to enter task detail, let us add new View Controller. From the Objects library, drag and drop View Controller on to storyboard. Then drag and drop a navigation item to this View Controller. Add a Done bar button item for saving the changes, Cancel bar button item for dismissing the screen. Also provide a title for the screen as Task Detail.
Then add a textfield to the View Controller to enter details about the task.
Now to connect the Task Manager screen to Task Detail screen, select the Add button in Task Manager screen, hold the control button and make a connection to the Task Detail screen. Select type of Action Segue as Show.
Select each View Controller and Click on the Resolve Auto Layout Issues option and pick Reset to Suggested Constraints. This would ensure that the controls alignment and display remains same in different screen sizes.
Right click on the Project, select New File from menu list.
Select Cocoa Touch Class as template.
Enter the Class name as TaskDetailViewController, Subclass of UIViewController and Language as Swift.
Navigate to Storyboard file and select Task Detail View Controller. Click Identity Inspector and set the Class to the TaskDetailViiewController.
Now let us add the function required for dismissing the View Controller. This gets called when user taps done and cancel buttons. Navigate to TaskDetailViewController.swift file and add the following functions.
@IBAction func done(sender: AnyObject) { if task != nil { editTask() } else { createTask() } dismissViewController() } @IBAction func cancel(sender: AnyObject) { dismissViewController() } // MARK:- Dismiss ViewControllers func dismissViewController() { navigationController?.popViewController(animated: true) }
Connect the IBActions with the corresponding done and cancel buttons
Try to compile and run the app on the Simulator. You should see the following Task Manager screen and tapping + sign should display the Task Detail screen with TextField, Cancel and Done button.
When you tap the Cancel or Done button should take you to the Task Manager screen.
Add the following piece of code after the Class TaskDetailViewController: UIViewController
@IBOutlet var txtDesc: UITextField!
Now use the connection inspector to connect the IBOutlet variable to the textfield on the User Interface.
Click Show Project Navigator and select CoreData model file (ending with extension .xcdatamodelid)
Click Add Entity option available at the bottom of Xcode Editor window.
Then enter the name of the entity as Tasks.
Click Add Attribute then enter name as desc and choose the type as String. This attribute will be used for storing the task detail information.
Now to generate the CoreData mapping class, click Editor and select Create NSManagedObject Subclass.
Select the data models and click Next
Then select entities and in this example it is Tasks
Make sure to select Language for NSManagedObject class as Swift. Click Create to the create new class.
Click Yes to to configure an Objective-C birding header for the Swift class.
This should create a new class called Tasks.swfit with variable for corresponding attribute defined in Entities
Add the following line at the top of TaskDetailViewController class
let managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext
The above line defines a variable to store the ManagedObjectContext. In order to save the task information entered in the UITextField, add the following code to TaskDetailViewController.swift. Then call this function in the @IBAction done.
func createTask() { let entityDescripition = NSEntityDescription.entity(forEntityName: "Tasks", in: managedObjectContext) let task = Tasks(entity: entityDescripition!, insertInto: managedObjectContext) task.desc = txtDesc.text! do { try managedObjectContext.save() } catch _ { } }
@IBAction func done(sender: AnyObject) { createTask() dismissViewController() }
The createTask function uses the Tasks Entity class and ManagedObjectContext class to save the information entered in the text field in to SQLite using CoreData.
Now if you try to run this app in Xcode simulator, you should be able to enter the details in textfield and save the task. But there is no way to see the saved tasks.
We will be using NSFetchedResultsController to retrieve and manage information returned from Core Data. Write the following code after the class declaration of TaskManagerViewController class
let managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext var fetchedResultController: NSFetchedResultsController = NSFetchedResultsController<NSFetchRequestResult>()
You might see the above error message “Use of undeclared type ’NSFetchedResultsContoller”. This can be fixed by importing CoreData module and making your class a delegate of NSFetchedResultsControllerDelegate.
import CoreData class TaskManagerViewController: UITableViewController, NSFetchedResultsControllerDelegate {
Then add the following function to populate fetchedResultController.
func getFetchedResultController() -> NSFetchedResultsController<NSFetchRequestResult> { fetchedResultController = NSFetchedResultsController(fetchRequest: taskFetchRequest(), managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: nil) return fetchedResultController }
Update the ViewDidLoad method of TableViewController to populate fetchedResultController variable and set the delegate to self and call the function to retrieve the results.
override func viewDidLoad() { super.viewDidLoad() fetchedResultController = getFetchedResultController() fetchedResultController.delegate = self do { try fetchedResultController.performFetch() } catch _ { } }
Navigate to Main.storyoard then to TaskManagerViewController and set Identifier for Prototype Cells as “Cell”
Add the following functions required for population of rows in tableView and to refresh the tableView when content is changed.
And for refreshing the tableview content add the following piece of code snippet.
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) { tableView.reloadData() }
Swift uses namespaces for classes, so the downcast of NSManagedObject class to Tasks class will work only when you append the module name with the class for Entity
let task = fetchedResultController.object(at: indexPath as IndexPath) as! Tasks
Navigate to TaskManager.xcdatamodeld, select Tasks under Entities and using the Data Model Inspector append Module name i.e TaskManager with the class.
Now you should be able to see the data added via TaskDetailScreen in the TaskManager Screen.
Copy and paste the following code to provide the users with the option to delete the rows.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { let managedObject:NSManagedObject = fetchedResultController.object(at: indexPath as IndexPath) as! NSManagedObject managedObjectContext.delete(managedObject) do { try managedObjectContext.save() } catch _ { } }
Now let us see how to edit a task in the TaskManager screen. We will re-use the same TaskDetail screen for editing the task information. First let create segue from UITableViewCell to TaskDetailViewController. You can do this by holding the Control key and drag and drop the connection to TaskDetailViewController.
Make sure to set the Segue identifier as edit using Attributes Inspector
Add the following piece of code in TaskManagerViewController to populate the task detail for the edited row.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "edit" { let cell = sender as! UITableViewCell let indexPath = tableView.indexPath(for: cell) let taskController:TaskDetailViewController = segue.destination as! TaskDetailViewController let task:Tasks = fetchedResultController.object(at: indexPath!) as! Tasks taskController.task = task } }
Navigate to TaskDetailViewController and variable which used to pass the task details across the ViewControllers
var task: Task? = nil
In viewDidLoad fund, populate the textField with the task details for edit operation i.e task is not nil
override func viewDidLoad() { super.viewDidLoad() if task != nil { txtDesc.text = task?.desc } }
Then add a new function to save the edited task. Also modify the done function to handle create and edit task functionality
func editTask() { task?.desc = txtDesc.text! do { try managedObjectContext.save() } catch _ { } }
@IBAction func done(sender: AnyObject) { if task != nil { editTask() } else { createTask() } dismissViewController() }
Now when you run the app in Xcode simulator, you should be able to edit the task.
The final piece of code left is to add background colour to the navigation bar for both the controllers. Click AppDelegate.swift file and add the following function. Then call this function from the didFinishLaunchingWithOptions.
func setupAppearance() { let navigationBarAppearance = UINavigationBar.appearance() navigationBarAppearance.barTintColor = UIColor(red: 51.0/255.0, green: 104.0/255.0, blue: 121.0/255.0, alpha: 1.0) navigationBarAppearance.tintColor = UIColor.white navigationBarAppearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white] }
Running the app on the iOS simulator should change the appearance for the navigation bar.
Hope you found this beginner tutorial useful. Please use the comments section to share your thoughts and suggestion
Download the source code for this tutorial from GitHub
In this Swift tutorial, we will see the steps required for using CoreLocation framework and retrieve the latitude and longitude of the location. Then use the CLGeocoder to reverse geocode the latitude and longitude details. This is a very basic tutorial that retrieves the location details on tap of a button and displays the information on the screen.
Updated :- The source has now been to updated to show the address details in TextFields.
Click File -> New and select Project sub menu list.
In the Choose a template screen, select Single View Application and click Next button.
Enter the product name as WhereAmI and select the language as Swift then click Next. Select a folder and create the new project and that folder.
Navigate to ViewController.swift file and add a new function with name as findMyLocation after viewDidLoad function.
@IBAction func findMyLocation(sender: AnyObject) { }
Navigate to Main.storyboard file, drag and drop Button from the Object Library on to the View Controller. Using the attributes inspector, change the name of the button to “Where Am I?”. If you need then change the background and text colour for the button. Then centre align the button both vertically and horizontally. Use the Resolve Auto Layout Option and pick Reset to Suggested Constraints.
Navigate to Connections Inspector and connect the button to the findMyLocation action under Received Actions (Touch Up Inside event).
Click the Project under Project Navigator and navigate to Build Phases. Click the + sign under Link Binary With Libraries and pick CoreLocation.framework from the list.
CoreLocation in Swift
Now navigate back to ViewController.swift file, add import CoreLocation after UIKit. Then we need to assign the current class as the delegate for CLLocationManagerDelegate
. This is required because we will be using couple of delegate methods from CLLocationManager.
class ViewController: UIViewController, CLLocationManagerDelegate {
Define a constant for CLLocationManager after the class declaration.
let locationManager = CLLocationManager()
Navigate to IBAction function findMyLocation and add the following code
locationManager.delegate = self locationManager.desiredAccuracy = kCLLocationAccuracyBest locationManager.requestWhenInUseAuthorization() locationManager.startUpdatingLocation()
The above lines sets the class as delegate for locationManager, specifies the location accuracy and starts receiving location updates from CoreLocation. In order to get the location updates we need to implement the delegate functions of CLLocationManager, didUpdateLocations and didFailWithError
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) { } func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) { }
didUpdateLocations function is triggered when new location updates are available. Similarly didFailWithError is called when there is a problem receiving the location updates. Let us first start implementing the simpler one i.e didFailWithError function. When there is an error, we are going to log the message to the console.
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) { println("Error while updating location " + error.localizedDescription) }
Then update didUpdateLocations function with the following code, also add a new function for printing the location details.
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) { CLGeocoder().reverseGeocodeLocation(manager.location, completionHandler: {(placemarks, error)->Void in if error { println("Reverse geocoder failed with error" + error.localizedDescription) return } if placemarks.count > 0 { let pm = placemarks[0] as CLPlacemark self.displayLocationInfo(pm) } else { println("Problem with the data received from geocoder") } }) } func displayLocationInfo(placemark: CLPlacemark) { if placemark != nil { //stop updating location to save battery life locationManager.stopUpdatingLocation() println(placemark.locality ? placemark.locality : "") println(placemark.postalCode ? placemark.postalCode : "") println(placemark.administrativeArea ? placemark.administrativeArea : "") println(placemark.country ? placemark.country : "") } }
in the didUpdateLocations
function, we pass the location co-ordinates to
CLGeocoder().reverseGeocodeLocation
. Then check for error and process the location array (placemarks). Then for displaying the location details, we pass the placemark detail to displayLocationInfo function.
In order to use the user’s location you need to request permission from the user by adding the keys “NSLocationWhenInUseUsageDescription” or “NSLocationAlwaysUsageDescription” to your Info.plist file, with the value blank or optionally a message included in the prompt to the user. One of those two key is required in iOS 8 to ask for your location.
It is not possible to test current location with simulator. So we need to define a custom location or use the location already defined for debug purpose. When an app tries to access the location services on a simulator it displays the following popup.
Here is a workaround to test the app using Xcode 11. Run the app on the a Simulator and tap “Find My Location” button. Nothing will happen as the app has not been given permission to use Location Services on Simulator.
Click Debug menu then Location and select Apple from the sub menu list. Still nothing happens with the app and no messages are written to the console.
Now click Hardware menu and select Home from menu list.
Tap the Settings icon on Simulator -> Privacy -> Location -> Tap , select Always to allow the app to access the location.
Now you should see Apple address details in the Console Output.
You can also try out other location using the Simulate Location option.
Hopefully the testing should be lot easier after issue with “Allow to use Current Location” is fixed.
Source from GitHub
Updated for Swift 5
In this short tutorial, we will see an example in Swift programming language using UIWebView. The WebView will load a webpage and provide option to refresh, stop, go back and go forward. This tutorial should give a brief overview on how to declare IBAction, IBOutlets and use Objective-C classes (NSURL and NSURLRequest) in Swift
Interface Design
Step 1: Create a Single View Application Project and make sure to select the programming language as Swift
Step 2: Select Main.Storyboard under Project navigator. then drag and drop WebView and Toolbar from Object Library to the View Controller.
Step 3: Now place four bar button items on Toolbar to provide stop, refresh, go back and go forward functionality. You can also use flexible and fixed separators for aligning the bar button items.
Step 4: Make sure to use the SuggestedConstraints for WebView and Toolbar. You can do this by selecting the controls and using the Reset to Suggested Constraints available as part of Resolve Auto Layout option. This would ensure that the controls gets adjusted automatically depending upon the device’s screen width and height.
Updated – 28/08/2014
Since some users are facing problems with Reset to Suggested Constraints in Xcode 6 Beta 6, you can use Pin option to define the four constraints using the default values. Then click Add 4 Constraints available at the bottom of the screen.
Write Code
Step 5: Navigate to ViewController.swift file on the Project Navigator. Add the following line after class ViewController: UIViewController which defines the IBOutlet element for WebView.
@IBOutlet var webView: UIWebView!
Then connect this IBOutlet element to the WebView on InterfaceBuilder.
Step 6: In the viewDidLoad function, create URL and NSURLRequest for the webpage and associate this with the WebView by calling loadRequest method.
override func viewDidLoad() { super.viewDidLoad() let url = NSURL(string: "https://rshankar.com") let request = NSURLRequest(url: url! as URL) webView.delegate = self activityIndicator.hidesWhenStopped = true activityIndicator.startAnimating() webView.loadRequest(request as URLRequest) }
Step 7: Now add the corresponding IBAction methods for the four buttons stop, refresh, go back and go forward. And connect these IBActions to the buttons on Interface builder.
func webViewDidFinishLoad(_ webView: UIWebView) { activityIndicator.stopAnimating() } @IBAction func doRefresh(_: AnyObject) { webView.reload() } @IBAction func goBack(_: AnyObject) { webView.goBack() } @IBAction func goForward(_: AnyObject) { webView.goForward() } @IBAction func stop(_: AnyObject) { webView.stopLoading() }
Step 8: Compile and run the project by selecting a suitable simulator.
Download the souce code from GitHub.
AutoLayout solves the mystery when designing app for more than one screen size and for both Portrait and Landscape orientation. This is done by adding constraints to the views using various Auto Layout options available as part of Interface Builder. As an iOS developer, you can also add these constraints programmatically using NSLayoutConstraints or Visual Format Languages. In this tutorial we will see how to use NSLayoutConstraints for adding constraints to the views.
For this demo, we will design something similar to flag of England by adding all the views and constraints programmatically. Funza Academy have published a video tutorial on how to design this screen using Interface Buidler, please check that out.
The following will be done to create the UI programmatically.
Create a new Xcode project by selecting Single View Application for the project template. Also choose the language and Swift and iPhone for Devices.
Navigate to ViewController.swift file and add the following code snippet after the class declaration and above the viewDidLoad() function.
[code language=”swift”]private let SCREEN_SIZE = UIScreen.mainScreen().bounds
private let GAP_BETWEEN_VIEWS:CGFloat = 0.08
// Create four Subviews
var topLeftView = UIView()
var topRightView = UIView()
var bottomLeftView = UIView()
var bottomRightView = UIView()[/code]
The above set of code creates two constants which stores the screen size and specifies the gap between the views. Then we have created four variables that holds the instance of four views.
Add the following addViews functions below the viewDidLoad method
[code language=”swift”]
func addViews() {
let heightOfSubView = SCREEN_SIZE.height / 2 – SCREEN_SIZE.height * GAP_BETWEEN_VIEWS/2
let widthOfSubView = SCREEN_SIZE.width / 2 – SCREEN_SIZE.height * GAP_BETWEEN_VIEWS/2
// Calculate the height and size of each views
topLeftView = UIView(frame: CGRect(x: 0, y: 0, width: widthOfSubView, height: heightOfSubView))
topRightView = UIView(frame: CGRect(x: widthOfSubView + (SCREEN_SIZE.height * GAP_BETWEEN_VIEWS), y: 0, width: widthOfSubView, height: heightOfSubView))
bottomLeftView = UIView(frame: CGRect(x: 0, y: heightOfSubView + (SCREEN_SIZE.height * GAP_BETWEEN_VIEWS), width: widthOfSubView, height: heightOfSubView))
bottomRightView = UIView(frame: CGRect(x: widthOfSubView + (SCREEN_SIZE.height * GAP_BETWEEN_VIEWS), y: heightOfSubView + (SCREEN_SIZE.height * GAP_BETWEEN_VIEWS), width: widthOfSubView, height: heightOfSubView))
topLeftView.backgroundColor = UIColor.whiteColor()
topRightView.backgroundColor = UIColor.whiteColor()
bottomLeftView.backgroundColor = UIColor.whiteColor()
bottomRightView.backgroundColor = UIColor.whiteColor()
view.addSubview(topLeftView)
view.addSubview(topRightView)
view.addSubview(bottomLeftView)
view.addSubview(bottomRightView)
}
[/code]
The addViews function, calculates the height and width of each subview (rectangular view with white background). Then the four views are created with positioning them in the corresponding corners i.e topLeft, topRight, bottomLeft and bottomRight. The background colour for these views are set White then they added to parent view using addSubView method.
Now call this addViews function inside viewDidLoad method. Also make sure to set the background colour of parent view to red.
[code language=”swift”]
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.redColor()
addViews()
}
[/code]
Compiling and running this app on iPhone 6 simulator, the portrait mode should look as shown below
And in Landscape mode the views are randomly placed. Let us now fix this by adding the required constraints for all the veiws.
In order to pin the four subviews, we need to add Leading, Traling, Top and Bottom constraints for the views based on their position. For example the top left view needs a leading and top constraint to the superview. The below screenshot should give a better understanding of constraints required for each view. And we will be adding these constraints using NSLayoutConstraint class
Add the following code snippet that which creates Leading and Top constraint for TopLeft view.
[code language=”swift”]func addtopLeftViewConstraints() {
let topLeftViewLeadingConstraint = NSLayoutConstraint(item: topLeftView, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal
, toItem: view, attribute: NSLayoutAttribute.Leading, multiplier: 1, constant: 0)
let topLeftViewTopConstraint = NSLayoutConstraint(item: topLeftView, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal
, toItem: view, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0)
NSLayoutConstraint.activateConstraints([topLeftViewLeadingConstraint, topLeftViewTopConstraint])
}
[/code]
First we create a leading constraint to the topLeft view and super view. Then a top constraint is added for topLeft view to the SuperView. Constant refers to the gap between the views using attribute we specify the Leading or Top attributes. Since we do not need any gap between corners the constant value is set to 0. Finally we add these constraints for the view by using the activateConstraints function in NSLayoutConstraint class.
Now let us repeat the above steps topRight. bottomLeft and bottomLeft Views.
[code language=”swift”]func addTopRightViewConstraints() {
let topRightViewTrailingConstraint = NSLayoutConstraint(item: topRightView, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal
, toItem: view, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: 0)
let topRightViewTopConstraint = NSLayoutConstraint(item: topRightView, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal
, toItem: view, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0)
NSLayoutConstraint.activateConstraints([topRightViewTrailingConstraint, topRightViewTopConstraint])
}
func addBottomLeftViewConstraints() {
let bottomLeftViewLeadingConstraint = NSLayoutConstraint(item: bottomLeftView, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal
, toItem: view, attribute: NSLayoutAttribute.Leading, multiplier: 1, constant: 0)
let bottomLeftViewBottomConstraint = NSLayoutConstraint(item: bottomLeftView, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal
, toItem: view, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0)
NSLayoutConstraint.activateConstraints([bottomLeftViewLeadingConstraint, bottomLeftViewBottomConstraint])
}
func addBottomRightViewConstraints() {
let bottomRightViewTrailingConstraint = NSLayoutConstraint(item: bottomRightView, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal
, toItem: view, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: 0)
let bottomRightViewBottomConstraint = NSLayoutConstraint(item: bottomRightView, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal
, toItem: view, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0)
NSLayoutConstraint.activateConstraints([bottomRightViewTrailingConstraint, bottomRightViewBottomConstraint])
}[/code]
We need leave constant space in the middle between these views. This can be achieved by adding constriants between the top/bottom views and left/right views. So basically we need to add two vertical spacing and two horizontal spacing constraints.
The below code snippet adds the required spacing constraings between views by specifying a constant value. Then activate these constraints by calling NSLayoutConstraint.activateConstraint.
[code language=”swift”] func addTopBottomConstraints() {
let verticalSpacing1 = NSLayoutConstraint(item: bottomLeftView, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: topLeftView, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: (SCREEN_SIZE.height * GAP_BETWEEN_VIEWS))
let verticalSpacing2 = NSLayoutConstraint(item: bottomRightView, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: topRightView, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: (SCREEN_SIZE.height * GAP_BETWEEN_VIEWS))
NSLayoutConstraint.activateConstraints([verticalSpacing1, verticalSpacing2])
}
func addLeftRightConstraints() {
let horizontalSpacing1 = NSLayoutConstraint(item: topRightView, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: topLeftView, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: (SCREEN_SIZE.height * GAP_BETWEEN_VIEWS))
let horizontalSpacing2 = NSLayoutConstraint(item: bottomRightView, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: bottomLeftView, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: (SCREEN_SIZE.height * GAP_BETWEEN_VIEWS))
NSLayoutConstraint.activateConstraints([horizontalSpacing1, horizontalSpacing2])
}
[/code]
Now add Equal Width and Equal Height constraints for topRight, bottomLeft and bottomRight views based on topLeft View. The code snippet for EqualWidth and EqualHeight is given below. The first function adds equal width constaints for all the three views based on TopLeft view. Similarly the second function adds equal height constraints based on the TopLeft view.
[code language=”swift”]
func addEqualWidthConstraints() {
let topRightViewWidth = NSLayoutConstraint(item: topLeftView, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: topRightView, attribute: NSLayoutAttribute.Width, multiplier: 1, constant: 0)
let bottomLeftViewWidth = NSLayoutConstraint(item: topLeftView, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: bottomLeftView, attribute: NSLayoutAttribute.Width, multiplier: 1, constant: 0)
let bottomRightViewWidth = NSLayoutConstraint(item: topLeftView, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: bottomRightView, attribute: NSLayoutAttribute.Width, multiplier: 1, constant: 0)
NSLayoutConstraint.activateConstraints([topRightViewWidth, bottomLeftViewWidth,bottomRightViewWidth ])
}
func addEqualHeightConstraints() {
let topRightViewHeight = NSLayoutConstraint(item: topLeftView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: topRightView, attribute: NSLayoutAttribute.Height, multiplier: 1, constant: 0)
let bottomLeftViewHeight = NSLayoutConstraint(item: topLeftView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: bottomLeftView, attribute: NSLayoutAttribute.Height, multiplier: 1, constant: 0)
let bottomRightViewHeight = NSLayoutConstraint(item: topLeftView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: bottomRightView, attribute: NSLayoutAttribute.Height, multiplier: 1, constant: 0)
NSLayoutConstraint.activateConstraints([topRightViewHeight, bottomLeftViewHeight,bottomRightViewHeight ])
}[/code]
Finally we need to disable the auto resizing masks for all the views to prevent constraints getting automatically based on the autoResizingMask property. The autoResizingMask property is set to true when the views are added programmtically added so we need make sure that this property for all these views are set to false.
[code language=”swift”]func disableAutoResizingMasks() {
topLeftView.translatesAutoresizingMaskIntoConstraints = false
topRightView.translatesAutoresizingMaskIntoConstraints = false
bottomLeftView.translatesAutoresizingMaskIntoConstraints = false
bottomRightView.translatesAutoresizingMaskIntoConstraints = false
}[/code]
Just to make code little organized, we can create a new function that calls these constraints functions.
[code language=”swift”]func addConstraints() {
addtopLeftViewConstraints()
addTopRightViewConstraints()
addBottomLeftViewConstraints()
addBottomRightViewConstraints()
addTopBottomConstraints()
addLeftRightConstraints()
addEqualWidthConstraints()
addEqualHeightConstraints()
disableAutoResizingMasks()
}
[/code]
Then call the addConstraints function in viewDidLoad method
[code language=”swift”]override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.redColor()
addViews()
addConstraints()
}[/code]
If you need any assistance in Auto Layout, check out our new iOS 9 Auto Layout Tutorials.
Download the source code from GitHub
In this short tutorial, we are going to see the steps required use DatePicker in a iOS / Swift project. This demo is done by adding the DatePicker controls to Interface Builder and not programmatically.
Date Picker control allow developers to specify the mode such as Date, Time, Date and Time and Count Down Timer. Listed below are the screenshots of each Date Picker mode.
Using the Date and Time mode does not provide option to pick year. Hence in this demo we are going to use two date picker controls, one for date and another for time.
Add a View Controller (or use existing ViewController) to storyboard then drag and drop 2 date picker controls to the View Controller. Also add a UILabel for displaying the selected date and time values. For the first Date Picker set the mode to Date and for the second as Time.
Now add a new file to the project and choose the template as Cocoa Touch class. Provde the name for your class file as DatePickerController. Add the following lines of code that adds IBOutlets to the ViewController
[code language=”swift”]@IBOutlet var datePicker:UIDatePicker!
@IBOutlet var timePicker:UIDatePicker!
@IBOutlet var dateTimeDisplay:UILabel![/code]
Select the ViewController in the Storyboard and set the class in the Identity Inspector to DatePickerController. Now click Show Assistant Editor then Control + drag and drop date picker to class file. Select connect as Action and provide the name for the function as datePickerChanged.
Now you should see the following function added to your class file.
[code language=”swift”]
@IBAction func datePickerChanged(sender: AnyObject) {
}[/code]
Repeat this exercise for the TimePicker (second date picker control) with function name as timePickerChanged.
[code language=”swift”]@IBAction func timePickerChanged(sender: AnyObject) {
}[/code]
Also make sure to connect all the IBOutlets from the class file to the corresponding controls in View Controller.
Add the following piece of Date Formatter code just below the IBOutlets definition. We are using two instance of NSDateFormatter to specify the date and time style for each date picker controls.
[code language=”swift”]let dateFormatter = NSDateFormatter()
let timeFormatter = NSDateFormatter()[/code]
Add the following function that formats the date and time and assigns the value to UILabel.
[code language=”swift”]//MARK:- Date and time
func setDateAndTime() {
dateFormatter.dateStyle = NSDateFormatterStyle.ShortStyle
timeFormatter.timeStyle = NSDateFormatterStyle.ShortStyle
dateTimeDisplay.text = dateFormatter.stringFromDate(datePicker.date) + ” ” + timeFormatter.stringFromDate(timePicker.date)
}[/code]
Add the function call to the date picker’s Value Changed methods.
[code language=”swift”]@IBAction func datePickerChanged(sender: AnyObject) {
setDateAndTime()
}
@IBAction func timePickerChanged(sender: AnyObject) {
setDateAndTime()
}[/code]
Download the source code from here (SwiftDemo -> DatePicker)
In this tutorial, we will see some of the common UITableView operations such as Adding, Updating, Deleting and Moving records using Swift.
Let us start with a TableView placed over a ViewController instead of using UITableViewController. By this way you will learn lot more about the functionality of UITableView. Add a new file and select Cocoa Touch Class as a template for the new file.
In “Choose options for your new file” screen, enter the class name as TableViewDemoController with subclass as UIViewController. Then save the new file under your preferred location.
Navigate to Main.stotyboard then drag and drop a ViewController from Object Libray to Storyboard. Select the ViewController and click Show Identity Inspection and enter the class name as “TableViewDemoController”
Drag and drop Table View from object library to the View Controlller and make sure Table View is aligned properly. Now place a Table View Cell from object library on top of the TableView.
Set the identifier for Prototype cell to “CellIdentifier” using Show Identity Inspector.
Now select the tableview in the Document Outline pane and click Connection Inspector under Utilies pane. Connect the dataSource and delegate Outlets to the TableViewDemoController (yellow color circle on top View Controller)
In this demo, we will be seeing how to display list of Socia Media icons. Here are the steps to load those icons in TableView.
First create a Struct that would act as a place holder for holding the name and image file name. Right click on the Project, select New File. In template screen, choose Swift file and provide name as SocialMedia and save the file.
Edit SocialMedia.swift and add the following code snippet. Apart name and imageName property, this also has computed property that returms UIImage based upon the image file name.
[code language=”swift”]import UIKit
struct SocialMedia {
var name:String
var imageName:String
var image: UIImage {
get {
return UIImage(named: imageName)!
}
}
}[/code]
Now Drag and drop social icon images from folder to Xcode project (download images from gitHub repoistory). Navigate TableViewDemoController.swift and add the following code snippet.
[code language=”swift”]var data:[SocialMedia] = [SocialMedia]()
//MARK:- Populate data
func loadData() -> [SocialMedia] {
data.append(SocialMedia(name:"Evernote",imageName:"evernote"))
data.append(SocialMedia(name:"Facebook",imageName:"facebook"))
data.append(SocialMedia(name:"GitHub",imageName:"github"))
data.append(SocialMedia(name:"Google",imageName:"google"))
data.append(SocialMedia(name:"LinkedIn",imageName:"linkedin"))
data.append(SocialMedia(name:"Paypal",imageName:"paypal"))
data.append(SocialMedia(name:"Pinterest",imageName:"pinterest"))
data.append(SocialMedia(name:"Twitter",imageName:"twitter"))
data.append(SocialMedia(name:"Vimeo",imageName:"vimeo"))
data.append(SocialMedia(name:"youtube",imageName:"YouTube"))
return data
}
[/code]
We have declared an array called data which will hold all the SocialMedia icon related information. The function loadData is used for adding all the social media images. Now call this function in the viewDidLoad method.
[code language=”swift”]override func viewDidLoad() {
super.viewDidLoad()
// call loaddata
loadData()
}
[/code]
In order display data, ViewController needs to conform UITableViewDataSource protocol. Add UITableViewDataSource
to the class declaration next to UIViewController.
[code language=”swift”]class TableViewDemoController: UIViewController, UITableViewDataSource {
[/code]
Then implement the following methods in TableViewDemoController class, these required methods when a class conforms to UITableViewDataSource protocol.
[code language=”swift”]//MARK:- UITableViewDataSource methods
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("CellIdentifier") as! UITableViewCell
let mediaIcon = data[indexPath.row] as SocialMedia
cell.textLabel?.text = mediaIcon.name
cell.imageView?.image = mediaIcon.image
return cell
}
[/code]
Finally we need to create IBOutlet for tableView and connect with tableView control in Storyboard.
[code language=”swift”]@IBOutlet var tableView: UITableView!
[/code]
Now you should be able to build and run the project. This should show list all Social Media icons as shown below
In order the customize the tableview, the TableViewDemoController class needs to conform to UITableViewDelegate protocol. Let us say you want to increase the height of tableview rows. Then implement the function heightForRowAtIndexPath to return the height for each row.
[code language=”swift”]func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 60.0
}
[/code]
Build and run the project should show the difference in height.
Navigate to Main.storyboard and add a new View Controller to Interface builder. This View Controller will be used for capturing name of the icon when adding a new row.
This View Controller has a text field to accept the name of the Social Media icon, Done button to save the entered informatiom and Cancel button to cancel the operation. Make sure to create Unwind segue for Done and Cancel button by Control drag and drop each button to Exit icon on the View Controller. Also provide the identifer for the Unwind segue as addAction and cancelAction.
Navigate to TableViewDemoController and add Bar Button Item to the left hand side. Set the Identifier of Bar Button Item to Add.
Now Control + Drag from the Add button to DetailViewController and select Segue as Push with identifier as “addAction”. Similarly to allow users to edit the existing row, Control + Drag TableView prototype cell to DetailViewController and set identifier for the Push segue as “editAction”.
Add a new Cocoa Touch Class file to the existing project with Sub class as UIViewController and name of the file as DetailViewController. Set this file as the class name in the Identity Inspector of DetailViewController in Interface builder.
Update the DetailViewController.swift and replace the existing code with the following lines of code.
[code language=”swift”]import UIKit
class DetailViewController: UIViewController {
var socialMedia: SocialMedia?
var index:Int?
@IBOutlet var textFeild:UITextField?
override func viewDidLoad() {
super.viewDidLoad()
if let name = socialMedia?.name {
textFeild?.text = name
}
}
// MARK:- PrepareForSegue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let name = textFeild?.text
if segue.identifier == "addAction" {
if var socialMedia = socialMedia {
self.socialMedia?.name = name!
} else {
socialMedia = SocialMedia(name:name!,imageName:"unknown")
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}[/code]
We have declared two variables socialMedia and index which will be populated when user taps an esitsing row in the TableView. Also you should find a IBOutlet for UITextField, make sure to connect this with TextField in the Interface Builder.
In the viewDidLoad function, if the user is editing an existing row then the textfield is updated with that value. The prepareForSegue method is called when the user taps Done or Cancel button. And based on the action, a new social media icon is added or an existing row is updated.
Navigate back to TableViewDemoController and implement the following function that will be called on cancel or done operation in DetailViewController.
[code language=”swift”]//MARK:- Cancel and Done
@IBAction func cancel(segue:UIStoryboardSegue) {
// do nothing
}
@IBAction func done(segue:UIStoryboardSegue) {
let detailViewController = segue.sourceViewController as! DetailViewController
let socialMedia = detailViewController.socialMedia
if let selectedIndex = detailViewController.index {
data[selectedIndex] = socialMedia!
} else {
data.append(socialMedia!)
}
tableView.reloadData()
}[/code]
Delete operation can be added by implementing the following function in TableViewDemoController.
[code language=”swift”]func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
switch editingStyle {
case .Delete:
// remove the deleted item from the model
data.removeAtIndex(indexPath.row)
// remove the deleted item from the `UITableView`
self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
default:
return
}
}[/code]
This would allow users to swipe and delete a row in TableView. The function checks whether the editing style is Delete, then the row is removed from the array as well from the TableView display.
In order to allow users to move the rows, the tableView editing property needs to be set to true. Add another Bar Button Item, this time to the right of TableViewDemoController and provide the caption as Edit. Then connect this button with the following IBAction function.
[code language=”swift”]//MARK:- Editing toggle
@IBAction func startEditing(sender: UIBarButtonItem) {
tableView.editing = !tableView.editing
}
[/code]
This button acts as a toggle switch to enable or disable tableview edit operation. Now add the following function required for Move operation.
[code language=”swift”]//MARK:- TableViewCell Move row methods
func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
func tableView(tableView: UITableView,
moveRowAtIndexPath sourceIndexPath: NSIndexPath,
toIndexPath destinationIndexPath: NSIndexPath) {
let val = data.removeAtIndex(sourceIndexPath.row)
data.insert(val, atIndex: destinationIndexPath.row)
}
[/code]
Function canMoveRowAtIndexPath needs to return true and in moveRowAtIndexPath function, the tableView row data gets removed from the original index and inserted in to the new position.
Now the user can tap and hold the move option then drag and drop it to the desired position. When the tableview editing is set to true, it also provides delete button apart from the move operation.
Download the source code from here.
Social Media icons credit to Sebastiano Guerriero