iOS apps with REST APIs

241 670 0
iOS apps with REST APIs

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

iOS Apps with REST APIs Building Web-Driven Apps in Swift Christina Moulton ©2015 Teak Mobile Inc All rights reserved Except for the use in any review, the reproduction or utilization of this work in whole or in part in any form by any electronic, mechanical or other means is forbidden without the express permission of the author Tweet This Book! Please help Christina Moulton by spreading the word about this book on Twitter! The suggested hashtag for this book is #SwiftRestAppsBook Find out what other people are saying about the book by clicking on this link to search for this hashtag on Twitter: https://twitter.com/search?q=#SwiftRestAppsBook Contents Thanks i From JSON API to Swift App 1.1 What Will You Be Able to Do? 1.2 Who Is This Book For? 1.3 Who Is This Book Not For? 1.4 Using This Book 1.5 What We Mean By Web Services / APIs / REST / CRUD 1.6 JSON 1.7 Versions 1.8 Source Code 1.9 Disclaimer 1.10 Trademarks 1 2 3 4 Our App’s Requirements 2.1 Match Tasks to Endpoints 2.2 User Interface 2.3 API Requirements 2.4 Make a Plan 10 11 Swift JSON Parsing & Networking Calls 101 3.1 Simple REST API Calls with Swift 3.2 REST API Calls with Alamofire & SwiftyJSON 3.3 Alamofire Router 3.4 Strongly Typed GET and POST Calls with Alamofire 3.5 And That’s All 13 13 22 27 33 42 Why I Use Libraries Like Alamofire 43 Hooking Up a REST API to a Table View 5.1 Our Swift Project 5.2 Analyzing the API JSON Response 5.3 Setting Up the Table View 5.4 Getting & Processing the API Response 5.5 And That’s All 44 44 47 52 60 66 CONTENTS Custom Headers 6.1 Session Headers 6.2 Per Request Headers 6.3 Headers in URLRequestConvertible 6.4 And That’s All For Headers 68 68 69 69 70 Loading UITableViewCell Images from an API 7.1 Loading UIImages from URLs 7.2 UITableViewCell Images from URLs 7.3 Enhancements 7.4 Caching Images 7.5 A Better Cache: PINRemoteImage 7.6 And That’s All 71 72 72 75 76 80 81 Pagination, a.k.a., Load More on Scroll 8.1 Where is the Next Page? 8.2 Fetching and Appending 8.3 Integrating with the View Controller 8.4 When to Load More Gists? 8.5 And That’s All for Pagination 82 82 85 87 89 91 Pull to Refresh 9.1 Adding Pull to Refresh 9.2 Showing the Last Refreshed Time 9.3 And That’s All 92 92 94 96 10 Authentication 10.1 The Docs 10.2 Basic Auth: Username/Password 10.3 HTTP Header Authentication 10.4 Alamofire Validation 10.5 OAuth 2.0 10.6 Displaying the Results 10.7 Unauthorized Responses: 404 vs 401 10.8 And That’s All 97 97 97 102 104 106 137 149 151 11 Switching Lists 11.1 Setting Up the UI 11.2 Sharing a Completion Handler 11.3 And That’s All 152 152 156 160 12 Switching Between View Controllers and More JSON Parsing 12.1 JSON Parsing: Arrays & Dates 12.2 Parsing Dates in JSON 161 161 164 CONTENTS 12.3 12.4 12.5 12.6 12.7 Configuring the Detail View Controller Passing Data in a Segue Adding a Table View Displaying Gist File Content And That’s All 166 171 172 178 179 13 Adding More API Calls - Starring 13.1 Is the Gist Starred? 13.2 Starred Status in the Table View 13.3 PUT and DELETE Calls to Star and Unstar Gists 13.4 Authorization Check 13.5 And That’s All 180 180 181 184 186 190 14 Deleting Gists 14.1 DELETE API Call 14.2 User Interface: Table View Delete Features 14.3 And That’s All 191 191 192 195 15 Creating Gists and Clearing the Cache 15.1 POST API Call with Nested JSON Parameters 15.2 Creating an Input Form with Validation 15.3 And That’s All 196 196 200 208 16 What if They’re Offline? 16.1 How Do We Know? 16.2 Save a Local Copy 16.3 Databases 209 209 221 227 17 What Next? 17.1 User Interface 17.2 Test the User Experience 17.3 Suggested Exercises 17.4 Did I Miss Anything? 229 229 229 229 230 A Brief Introduction to CocoaPods Adding a CocoaPod to a Project What Does the Podfile Mean? Other Options Dependencies CocoaPods Version Numbers Updating CocoaPods 231 231 232 233 233 233 234 Thanks Without a few key people this book wouldn’t have happened Most of all, thanks to Jeff Moulton for putting up with my excessive focus on coding & writing, even while living on a 34’ sailboat Jeff also took the cover photo Thanks also to: • • • • • My Twitter peeps for support & fav’s @BugKrusha¹ & the iOS Developers² community GitHub LeanPub Everyone who gave feedback or asked questions about the book or GrokSwift.com³ Every little bit helps make the book better for you ¹http://twitter.com/BugKrusha ²http://ios-developers.io ³https://grokswift.com i From JSON API to Swift App You need to build an iOS app around your team’s API or integrate a third party API You need a quick, clear guide to demystify Xcode and Swift No esoteric details about Core Anything or mathematical analysis of flatMap Only the nitty gritty that you need to get real work done now: pulling data from your web services into an iOS app, without tossing your MacBook or Mac Mini through a window You just need the bare facts on how to get CRUD done on iOS That’s what this book will for you 1.1 What Will You Be Able to Do? After reading this book you’ll be able to: • Analyze a JSON response from a web service call and write Swift code to parse it into model objects • Display those model objects in a table view so that when the user launches the app they have a nice list to scroll through • Add authentication to use web service calls that require OAuth 2.0, a username/password, or a token • Transition from the main table view to a detail view for each object, possibly making another web service call to get more info about the object • Let users add, modify and delete objects (as long as your web service supports it) • Hook in to more web service calls to extend you app, like adding user profiles or letting users submit comments or attach photos to objects To achieve those goals we’ll build out an app based on the GitHub API, focusing on gists (If you’re not familiar with gists, they’re basically just text snippets, often code written a GitHub user.) Your model objects might be bus routes, customers, chat messages, or whatever kind of object is core to your app We’ll start by figuring out how to make API calls in Swift then we’ll start building out our app one feature at a time: • • • • • Show a list of all public gists in a table view Load more results when the user scrolls down Let them pull to refresh to get the latest public gists Load images from URLs into table view cells Use OAuth 2.0 for authentication to get lists of private and starred gists From JSON API to Swift App • Have a detail view for each gist showing the text • Allow users to add new gists, star and unstar gists, and delete gists • Handle not having an internet connection with warnings to the user and saving the gists on the device 1.2 Who Is This Book For? • • • • Software developers getting started with iOS but experienced in other languages Front-end devs looking to implement native UIs for iOS apps (no CSS, oh noes!) Back-end devs tasked with getting the data into the user’s hands on iOS Android, Windows Phone, Blackberry, Tizen, Symbian & Palm OS devs looking to expand their web service backed apps to iOS • Anyone whose boss is standing over their shoulder asking why the API data isn’t showing up in the table view yet 1.3 Who Is This Book Not For? • Complete newcomers to programming, you should have a decent grasp of at least one objectoriented programming language or have completed several intro to iOS tutorials • Designers, managers, UX pros, … It’s a programming book All the monospace font inserts will probably drive you crazy • Cross-platform developers dedicated to their tools (including HTML5 & Xamarin), this is all Swift & native UI, all the time • Programmers building apps that have little or no web service interaction • Game devs, unless you’re tying in a REST-like API 1.4 Using This Book This book is mostly written as a tutorial in implementing the gists app Depending on how you learn best and how urgently you need to implement your own app, there are two different approaches you might take: Work through the tutorials as written, creating an app for GitHub Gists You’ll understand how that app works and later be able to apply it to your own apps Read through the tutorials but implement them for your own app and API Throughout the text I’ll point out where you’ll need to analyze your own requirements and API to help you figure out how to modify the example code to work with your API Those tips will look like this: From JSON API to Swift App List the tasks or user stories for your app Compare them to the list for the gists app, focusing on the number of different objects (like stars, users, and gists) and the types of action taken (like viewing a list, viewing an object’s details, adding, deleting, etc.) We’ll start with that task in the next chapter We’ll analyze our requirements and figure out just what we’re going to build Then we’ll start building the gists app, right after an introduction to making network calls and parsing JSON in Swift 1.5 What We Mean By Web Services / APIs / REST / CRUD Like anything in tech there are plenty of buzzwords around web services For a while it was really trendy to say your web services were RESTful If you want to read the theory behind it, head over to Wikipedia¹ For our purposes in this book, all we mean by “REST web service” or even when we say “web service” or “API” is that we can send an HTTP request and we get back some data in a format that’s easy to use in our app Usually the response will be in JSON Web services are wonderful since they let you use existing systems in your own apps There’s always a bit of a learning curve with any web service that you’re using for the first time since every one has its own quirks Most of the integration is similar enough that we can generalize how to integrate them into our iOS apps If you want an argument about whether or not a web service is really RESTful you’re not going to find it here We’ve got work that just needs to get done 1.6 JSON In this book we’re going to deal with web services that return JSON JSON is hugely common these days so it’s probably what you’ll be dealing with Of course, there are other return types out there, like XML This book won’t cover responses in anything but JSON but it will encapsulate the JSON parsing so that you can replace it with whatever you need to without having to touch a ton of code If you are dealing with XML response you should look at NSXMLParser² 1.7 Versions This is version 1.1.1 of this book It uses Swift 2.0, iOS 9, and Xcode 7.1 When we use libraries we’ll explicitly list the versions used The most commonly used ones are Alamofire 3.1 and SwiftyJSON 2.3 ¹https://en.wikipedia.org/wiki/Representational_state_transfer ²https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSXMLParser_Class/ What if They’re Offline? 220 GitHubAPIManager.sharedInstance.OAuthTokenCompletionHandler = { (error) -> Void in self.safariViewController?.dismissViewControllerAnimated(true, completion: nil) if let error = error { print(error) self.isLoading = false if error.domain == NSURLErrorDomain && error.code == NSURLErrorNotConnectedToInternet { // show not connected error & tell em to try again when they have a connection // check for existing banner if let existingBanner = self.notConnectedBanner { existingBanner.dismiss() } self.notConnectedBanner = Banner(title: "No Internet Connection", subtitle: "Could not load gists Try again when you're connected to the internet", image: nil, backgroundColor: UIColor.redColor()) self.notConnectedBanner?.dismissesOnSwipe = true self.notConnectedBanner?.show(duration: nil) } else { // Something went wrong, try again self.showOAuthLoginView() } } else { self.loadGists(nil) } } If we test that we’ll find the Login view controller is still getting popped up because it’s set to always show up when we show the Master view controller but aren’t logged in The easy way to fix that is to leave the app thinking it’s still loading an OAuth token when we don’t have an internet connection: func safariViewController(controller: SFSafariViewController, didCompleteInitialLoad didLoadSuccessfully: Bool) { // Detect not being able to load the OAuth URL if (!didLoadSuccessfully) { let defaults = NSUserDefaults.standardUserDefaults() defaults.setBool(false, forKey: "loadingOAuthToken") if let completionHandler = GitHubAPIManager.sharedInstance.OAuthTokenCompletionHandler { let error = NSError(domain: NSURLErrorDomain, code: NSURLErrorNotConnectedToInternet, userInfo: [ NSLocalizedDescriptionKey: "No Internet Connection", NSLocalizedRecoverySuggestionErrorKey: "Please retry your request"]) completionHandler(error) } controller.dismissViewControllerAnimated(true, completion: nil) What if They’re Offline? 221 } } Now the app won’t pop up the Login view controller again until we pull to refresh Analyze and test your app for web service calls that could fail Make sure each one is handled with an experience that will be acceptable to the user and that they’ll understand what’s happening Add banners and alerts as appropriate We’ve handled all of the issues with lack of network connection so Apple won’t be rejecting our app for that But what if we wanted to provide a better experience, by letting users look at the gists they previously loaded while they’re offline? We’ll that next If you got tired of typing, here’s the code: (tagged “noInternet”)¹ 16.2 Save a Local Copy For a simple app like ours it’s probably good enough to show them that they’re offline and display the latest data that they loaded in a read-only mode So we’d need to persist the lists of gists Without an internet connection they wouldn’t be able to delete gists or star/unstar gists or see whether they previously starred a gist But we already handled those cases earlier in this chapter NSKeyedArchiver can be used to easily serialize objects so they can be written to disk It works out of the box for types like arrays and strings but we’ll have to let it know how to deal with our custom classes The two classes that we’ll need to add that support to are Gist and File To support that archiving our classes need to conform to the NSCoding protocol, which in turn requires the NSObject protocol: class Gist: NSObject, NSCoding, ResponseJSONObjectSerializable { } The NSObject protocol requires that we change the declaration of the existing init function to: required override init() { } It also includes a description property so we’ll change ours to gistDescription: ¹https://github.com/cmoulton/grokSwiftREST_v1.1/releases/tag/noInternet What if They’re Offline? 222 class Gist: NSObject, NSCoding, ResponseJSONObjectSerializable { var id: String? var gistDescription: String? required init(json: JSON) { self.gistDescription = json["description"].string } } And we’ll have to change the other view controllers to use gistDescription The easiest way to find what needs to be changed is to search for description In the MasterViewController: cell.textLabel!.text = gist.gistDescription And in the DetailViewController: func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) if indexPath.section == { if indexPath.row == { cell.textLabel?.text = gist?.gistDescription The NSCoding protocol requires functions, one to encode the object and the other to create an object by decoding it: class Gist: NSObject, NSCoding, ResponseJSONObjectSerializable { // MARK: NSCoding @objc func encodeWithCoder(aCoder: NSCoder) { } @objc required convenience init?(coder aDecoder: NSCoder) { self.init() What if They’re Offline? 223 } } We need to include each property in those functions using the functions available on NSCoder to encode and decode each property: @objc func encodeWithCoder(aCoder: NSCoder) { aCoder.encodeObject(self.id, forKey: "id") aCoder.encodeObject(self.gistDescription, forKey: "gistDescription") aCoder.encodeObject(self.ownerLogin, forKey: "ownerLogin") aCoder.encodeObject(self.ownerAvatarURL, forKey: "ownerAvatarURL") aCoder.encodeObject(self.url, forKey: "url") aCoder.encodeObject(self.createdAt, forKey: "createdAt") aCoder.encodeObject(self.updatedAt, forKey: "updatedAt") if let files = self.files { aCoder.encodeObject(files, forKey: "files") } } @objc required convenience init?(coder aDecoder: NSCoder) { self.init() self.id = aDecoder.decodeObjectForKey("id") as? String self.gistDescription = aDecoder.decodeObjectForKey("gistDescription") as? String self.ownerLogin = aDecoder.decodeObjectForKey("ownerLogin") as? String self.ownerAvatarURL = aDecoder.decodeObjectForKey("ownerAvatarURL") as? String self.createdAt = aDecoder.decodeObjectForKey("createdAt") as? NSDate self.updatedAt = aDecoder.decodeObjectForKey("updatedAt") as? NSDate if let files = aDecoder.decodeObjectForKey("files") as? [File] { self.files = files } } And the same for File: What if They’re Offline? class var var var 224 File: NSObject, NSCoding, ResponseJSONObjectSerializable { filename: String? raw_url: String? content: String? // MARK: NSCoding @objc func encodeWithCoder(aCoder: NSCoder) { aCoder.encodeObject(self.filename, forKey: "filename") aCoder.encodeObject(self.raw_url, forKey: "raw_url") aCoder.encodeObject(self.content, forKey: "content") } @objc required convenience init?(coder aDecoder: NSCoder) { let filename = aDecoder.decodeObjectForKey("filename") as? String let content = aDecoder.decodeObjectForKey("content") as? String // use the existing init function self.init(aName: filename, aContent: content) self.raw_url = aDecoder.decodeObjectForKey("raw_url") as? String } } Now we can save the gists but we need to implement actually doing so Create a new PersistenceManager.swift file that will be responsible for handling the saving and loading We’ll keep it generic by set up saving and loading arrays instead of specifying that they’re gists: import Foundation class PersistenceManager { class func saveArray(arrayToSave: [T], path: Path) { // TODO: implement } class func loadArray(path: Path) -> [T]? { // TODO: implement } } We’ll need a spot to save the gists There’s a documents directory that will work fine: What if They’re Offline? 225 class PersistenceManager { class private func documentsDirectory() -> NSString { let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, UserDomainMask, true) let documentDirectory = paths[0] as String return documentDirectory } } We’ll need to specify a different place to save each list of gists so they don’t overwrite each other Let’s use an enum for that We could add more items later if our app needed to save other objects: enum Path: String { case Public = "Public" case Starred = "Starred" case MyGists = "MyGists" } class PersistenceManager { } Ok, now let’s implement saving We’ll get the path to save it to then use NSKeyedArchiver.archiveRootObject to save the array to that path: class func saveArray(arrayToSave: [T], path: Path) { let file = documentsDirectory().stringByAppendingPathComponent(path.rawValue) NSKeyedArchiver.archiveRootObject(arrayToSave, toFile: file) } Loading the array is pretty similar: class func loadArray(path: Path) -> [T]? { let file = documentsDirectory().stringByAppendingPathComponent(path.rawValue) let result = NSKeyedUnarchiver.unarchiveObjectWithFile(file) return result as? [T] } So all together here’s our PersistenceManager: What if They’re Offline? 226 import Foundation enum Path: String { case Public = "Public" case Starred = "Starred" case MyGists = "MyGists" } class PersistenceManager { class private func documentsDirectory() -> NSString { let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, UserDomainMask, true) let documentDirectory = paths[0] as String return documentDirectory } class func saveArray(arrayToSave: [T], path: Path) { let file = documentsDirectory().stringByAppendingPathComponent(path.rawValue) NSKeyedArchiver.archiveRootObject(arrayToSave, toFile: file) } class func loadArray(path: Path) -> [T]? { let file = documentsDirectory().stringByAppendingPathComponent(path.rawValue) let result = NSKeyedUnarchiver.unarchiveObjectWithFile(file) return result as? [T] } } When should we save the gists? As soon as they’re loaded makes sense to me We’ll add a call to PersistenceManager.saveArray in loadGists after getting the correct path: if let fetchedGists = result.value { if let _ = urlToLoad { self.gists += fetchedGists } else { self.gists = fetchedGists } let path:Path if self.gistSegmentedControl.selectedSegmentIndex == { path = Public } else if self.gistSegmentedControl.selectedSegmentIndex == { path = Starred } else { path = MyGists } What if They’re Offline? 227 PersistenceManager.saveArray(self.gists, path: path) } And then we can load them if we don’t have an internet connection when we show the banner: if error.code == NSURLErrorUserAuthenticationRequired { self.showOAuthLoginView() } else if error.code == NSURLErrorNotConnectedToInternet { let path:Path if self.gistSegmentedControl.selectedSegmentIndex == { path = Public } else if self.gistSegmentedControl.selectedSegmentIndex == { path = Starred } else { path = MyGists } if let archived:[Gist] = PersistenceManager.loadArray(path) { self.gists = archived } else { self.gists = [] // don't have any saved gists } // show not connected error & tell em to try again when they have a connection } Save and run After you’ve loaded some gists, turn the internet off and make sure you can still see them Relaunch the app with the internet still off and they should still show up with the red banner shown See if there are any parts of your app that make sense for read-only offline support If so, use NSKeyedArchiver to save and load those items to the device when you get them so users can see them offline If you got tired of typing, here’s the code: (tagged “persistent”)² 16.3 Databases If your app is more complex then you’ll probably want a real database There are whole books written on iOS databases Along with keeping your data in a database comes syncing issues It’s not ²https://github.com/cmoulton/grokSwiftREST_v1.1/releases/tag/persistent What if They’re Offline? 228 too bad if the data is only accessed by a single user but if multiple users can modify objects then you’ll have to deal with conflicts between their changes when one of them didn’t have the latest version Databases don’t inherently fix the issues that come with not having an internet connection But they make it easier to handle complicated relationships between objects and large amounts of data If you need to go down this path take a look at Core Data It’s built-in to iOS and does a lot more than simple database functions You will need to monitor the internet connection and sync up when you can Realm³ is becoming popular as an alternative If you want to you can use SQLite (which is actually what Core Data uses under the hood) If you’re building your whole app from scratch, including the back end, you might want to consider services like Parse⁴ or Kinvey⁵ They offer SDKs that include features to manage offline use Consider just how rich your app’s offline experience needs to be Consider using a database if users should be able to perform lots of tasks offline and sync up with the back-end later ³https://realm.io ⁴http://blog.parse.com/learn/parse-local-datastore-for-ios/ ⁵http://devcenter.kinvey.com/ios/guides/caching-offline 17 What Next? We’ve built a working prototype of a REST API-backed iOS app in Swift Before it’s ready for the App Store it’ll need a few things Each of these items merits a book on its own so you should seek other sources to make sure you’ve covered them adequately before submitting your app: 17.1 User Interface We’ve been neglecting the user interface throughout this book Before releasing at least read through the Apple iOS Human Interface Guidelines¹ Not following the HIG is cause for an App Store rejection Beyond the HIG you’ll probably want to make the app a lot prettier too If you don’t have a designer check out the numerous UIKits available online to get away from completely standard styles Don’t go too far from the norm though, users want something familiar enough that they know how to interact with it 17.2 Test the User Experience Give it to someone, ask them to one of the tasks and silently watch them try If they can’t easily figure it out then you should strongly consider redesigning the app to make that task more obvious Try this test with a few people, preferably not your friends that you’ve already told all about the app 17.3 Suggested Exercises If you want to keep working on the demo app here are a few ideas Read the GitHub Gists API docs² for details: • Make it look great • Make the file display a lot better You can use the content property but you’ll need to handle truncation since you’ll only get the first MB of data for each file • Let the user navigate to the GitHub web page from a gist or file in the app ¹https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/MobileHIG/ ²https://developer.github.com/v3/ 229 What Next? 230 • Add filters to let users search the gists Unfortunately there isn’t any support for searching in the API but you can let users filter or search the gists that are loaded to their device • Add an edit mode to the list of starred & public gists to star/unstar multiple gists at a time • Extend the gist creation form to allow multiple files • Let users edit their existing gists • Build out user profiles so users can view details about the writers of the gists 17.4 Did I Miss Anything? One of the best things about ebooks is that cats can’t shred them Another is that they can be updated, just like this one was when Alamofire v3 came out So while the book is fresh in your mind email me right now at christina+book@teakmobile.com³ and tell me one way it could be better If you’re looking for more Swift tutorials, I write them about once a week at Grok Swift⁴ ³mailto:christina+book@teakmobile.com ⁴https://grokswift.com A Brief Introduction to CocoaPods If you’re not familiar with CocoaPods, it’s worth taking a few minutes to learn about the lovely dependency manager commonly used for iOS libraries today Cocoapods is great for adding libraries to your iOS projects, in Objective-C and Swift In fact, it’s easy to use Objective-C code in iOS Swift projects If you’re curious, check out Objective-C in Swift Project⁵ We’ll just cover the simple basics that we’ll use throughout this book so that when I say “add the Alamofire v3.1 CocoaPod to your project” we don’t need to spend a few paragraphs detailing how to that Adding a CocoaPod to a Project Let’s say we’re going to add the SwiftyJSON CocoaPod to an Xcode project Here’s what we need to do: Close Xcode Open the terminal in the project top directory (the directory with the xcodeproj file for your project) If you haven’t previously installed CocoaPods run: sudo gem install cocoapods If you need more info on installing CocoaPods, check out their Getting Started guide⁶ Once it’s done installing CocoaPods, you need to initialize Cocoapods for your project So run: pod init That will create a new file called “Podfile” (to be honest, I think that’s all it does) Using a text editor open the newly created Podfile and replace the contents with: ⁵https://grokswift.com/objective-c-in-swift/ ⁶https://guides.cocoapods.org/using/getting-started.html 231 A Brief Introduction to CocoaPods 232 source 'https://github.com/CocoaPods/Specs.git' platform :ios, '9.0' use_frameworks! pod 'SwiftyJSON' Save the Podfile then switch back to Terminal and run: pod install Open the xcworkspace file in Xcode Navigate back to whatever class you want to use SwiftyJSON in and add “import SwiftyJSON” at the top like this: import Foundation import SwiftyJSON class MyClass { } Now you can use SwiftyJSON in that file What Does the Podfile Mean? While it’s nice to just get instructions that work, it’s usually a good idea to know why they work So let’s take a look at that Podfile: source 'https://github.com/CocoaPods/Specs.git' platform :ios, '9.0' use_frameworks! pod 'SwiftyJSON' When you run pod install CocoaPods looks for a Podfile and tries to install the pods listed in it Install in this case means “download and add to the Xcode project” A pod is generally a library, really just a chunk of code that you want to use in your project Let’s go through it line by line: source 'https://github.com/CocoaPods/Specs.git' The first line tells CocoaPods where on the internet to find pods We’re using the default public CocoaPods repository which is a great place to check for libraries for your projects A Brief Introduction to CocoaPods 233 platform :ios, '9.0' The second line specifies that we’re working on an app for iOS (not OS X) and we’re building an app for the iOS 9.0 SDK Including this info in a Podfile means that pods can have different version for iOS and OS X as well as for different versions of the iOS SDK use_frameworks! use_frameworks! tells CocoaPods how we want to integrate the code libraries with our project In Swift we want it to wrap up the code in a framework then include the framework in our project Since CocoaPods pre-dates Swift, that’s not the default so we have to include this line Want more details? See the release notes for CocoaPods v0.36⁷ pod 'SwiftyJSON' And finally we specify which pod (or pods) we want to install Other Options You can some neat stuff with CocoaPods including adding different code to testing and App Store versions of your app or making private CocoaPods for use within a team If you’re curious, check out Creating and Using CocoaPods by Jeffrey Sambells⁸ Dependencies The real time saver in CocoaPods is that pods can specify dependencies So if SwiftyJSON required some other library then CocoaPods would make sure we have it in our Pods before downloading SwiftyJSON and adding it to our project It’ll also make sure that we have the correct compatible version So we don’t need to hunt down and install a bunch of prerequisites before installing a pod CocoaPods Version Numbers One option that we’ll use in CocoaPods is to specify which version of a pod we want We can specify an exact number or a less specific number For example to use v2.3.0: ⁷http://blog.cocoapods.org/CocoaPods-0.36/ ⁸http://jeffreysambells.com/talks/2014/01/23/using-and-creating-cocoapods A Brief Introduction to CocoaPods 234 pod 'SwiftyJSON', '2.3.0' We could also say that we want to use SwiftyJSON v2.3.whatever to get small updates: pod 'SwiftyJSON', '~> 2.3.0' Which would allow v2.3.0, 2.3.1, 2.3.2, … but not v2.4 Or even v2.whatever: pod 'SwiftyJSON', '~> 2.3' Which would allow v2.3, 2.4, … but not v3.0 If we leave off the version number then CocoaPods will just install the latest version Updating CocoaPods Unless you tell it to, CocoaPods won’t auto-update to newer versions To tell CocoaPods that you want newer versions (if your version numbers will allow it) run: pod update You’ll see a message in the terminal showing you which pods were updated and to which versions You’ll also need to run that command if you change the version numbers in the Podfile or add more pods to it

Ngày đăng: 18/04/2017, 10:36

Từ khóa liên quan

Mục lục

  • Table of Contents

  • Thanks

  • From JSON API to Swift App

    • What Will You Be Able to Do?

    • Who Is This Book For?

    • Who Is This Book Not For?

    • Using This Book

    • What We Mean By Web Services / APIs / REST / CRUD

    • JSON

    • Versions

    • Source Code

    • Disclaimer

    • Trademarks

    • Our App's Requirements

      • Match Tasks to Endpoints

      • User Interface

      • API Requirements

      • Make a Plan

      • Swift JSON Parsing & Networking Calls 101

        • Simple REST API Calls with Swift

        • REST API Calls with Alamofire & SwiftyJSON

        • Alamofire Router

        • Strongly Typed GET and POST Calls with Alamofire

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan