专业iOS网络编程:连接企业的iPhone和iPad

n4g6

贡献于2015-08-20

字数:0 关键词: iOS 开发 移动开发

ffirs.indd iffirs.indd i 13/09/12 2:46 PM13/09/12 2:46 PM PROFESSIONAL IOS NETWORK PROGRAMMING INTRODUCTION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xix PART I UNDERSTANDING IOS AND ENTERPRISE NETWORKING CHAPTER 1 Introducing iOS Networking Capabilities . . . . . . . . . . . . . . . . . . . . . . . . . . 3 CHAPTER 2 Designing Your Service Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 PART II HTTP REQUESTS: THE WORKHORSE OF IOS NETWORKING CHAPTER 3 Making Requests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 CHAPTER 4 Generating and Digesting Payloads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .65 CHAPTER 5 Handling Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 PART III ADVANCED NETWORKING TECHNIQUES CHAPTER 6 Securing Network Traffi c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119 CHAPTER 7 Optimizing Request Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157 CHAPTER 8 Low-Level Networking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 CHAPTER 9 Testing and Manipulating Network Traffi c . . . . . . . . . . . . . . . . . . . . . . . . .191 CHAPTER 10 Using Push Notifi cations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 PART IV NETWORKING APP TO APP CHAPTER 11 Inter-App Communication. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247 CHAPTER 12 Device-to-Device Communication with Game Kit . . . . . . . . . . . . . . . . .267 CHAPTER 13 Ad-Hoc Networking with Bonjour . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281 INDEX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .319 ffirs.indd iffirs.indd i 13/09/12 2:46 PM13/09/12 2:46 PM ffirs.indd iiffirs.indd ii 13/09/12 2:46 PM13/09/12 2:46 PM PROFESSIONAL iOS Network Programming ffirs.indd iiiffirs.indd iii 13/09/12 2:46 PM13/09/12 2:46 PM ffirs.indd ivffirs.indd iv 13/09/12 2:46 PM13/09/12 2:46 PM PROFESSIONAL iOS Network Programming CONNECTING THE ENTERPRISE TO THE IPHONE® AND IPAD® Jack Cox Nathan Jones John Szumski ffirs.indd vffirs.indd v 13/09/12 2:46 PM13/09/12 2:46 PM Professional iOS Network Programming: Connecting the Enterprise to the iPhone® and iPad® Published by John Wiley & Sons, Inc. 10475 Crosspoint Boulevard Indianapolis, IN 46256 www.wiley.com Copyright © 2012 by John Wiley & Sons, Inc., Indianapolis, Indiana Published simultaneously in Canada ISBN: 978-1-118-36240-2 ISBN: 978-1-118-38223-3 (ebk) ISBN: 978-1-118-41716-4 (ebk) ISBN: 978-1-118-53385-7 (ebk) Manufactured in the United States of America 10 9 8 7 6 5 4 3 2 1 No part of this publication may be reproduced, stored in a retrieval system or transmitted in any form or by any means, electronic, mechanical, photocopying, recording, scanning or otherwise, except as permitted under Sections 107 or 108 of the 1976 United States Copyright Act, without either the prior written permission of the Publisher, or authorization through payment of the appropriate per-copy fee to the Copyright Clearance Center, 222 Rosewood Drive, Danvers, MA 01923, (978) 750-8400, fax (978) 646-8600. Requests to the Publisher for permission should be addressed to the Permissions Department, John Wiley & Sons, Inc., 111 River Street, Hoboken, NJ 07030, (201) 748-6011, fax (201) 748-6008, or online at http://www.wiley.com/go/permissions. Limit of Liability/Disclaimer of Warranty: The publisher and the author make no representations or warranties with respect to the accuracy or completeness of the contents of this work and specifi cally disclaim all warranties, including without limitation warranties of fi tness for a particular purpose. No warranty may be created or extended by sales or pro- motional materials. The advice and strategies contained herein may not be suitable for every situation. This work is sold with the understanding that the publisher is not engaged in rendering legal, accounting, or other professional services. If professional assistance is required, the services of a competent professional person should be sought. Neither the pub- lisher nor the author shall be liable for damages arising herefrom. The fact that an organization or Web site is referred to in this work as a citation and/or a potential source of further information does not mean that the author or the publisher endorses the information the organization or Web site may provide or recommendations it may make. Further, readers should be aware that Internet Web sites listed in this work may have changed or disappeared between when this work was written and when it is read. For general information on our other products and services please contact our Customer Care Department within the United States at (877) 762-2974, outside the United States at (317) 572-3993 or fax (317) 572-4002. Wiley publishes in a variety of print and electronic formats and by print-on-demand. Some material included with standard print versions of this book may not be included in e-books or in print-on-demand. If this book refers to media such as a CD or DVD that is not included in the version you purchased, you may download this material at http://booksupport.wiley.com. For more information about Wiley products, visit www.wiley.com. Library of Congress Control Number: 2012948655 Trademarks: Wiley, the Wiley logo, Wrox, the Wrox logo, Wrox Programmer to Programmer, and related trade dress are trademarks or registered trademarks of John Wiley & Sons, Inc. and/or its affi liates, in the United States and other coun- tries, and may not be used without written permission. iPhone and iPad are registered trademarks of Apple, Inc. All other trademarks are the property of their respective owners. John Wiley & Sons, Inc., is not associated with any product or vendor mentioned in this book. ffirs.indd viffirs.indd vi 13/09/12 2:46 PM13/09/12 2:46 PM ABOUT THE AUTHORS JACK COX is a software developer, a systems architect, and the director at CapTech Ventures, Inc., where he is responsible for the fi rm’s mobile software practice. He has 30 years of experience in developing software for businesses of all sizes. He has been involved in three startups, holds multiple patents, and frequently presents to professional groups. He has a degree in computer science from Taylor University in Upland, Indiana. Jack lives in Richmond, Virginia, with his wife and children. You can get in touch with Jack on Twitter @jcox_mobile. NATHAN JONES is a software engineer with expertise in iOS and experience in mobile web technologies. He began his career in enterprise software consulting and started exploring mobile development when Apple announced the capability to develop third-party apps for the iPhone. He graduated with a bachelor of science in business information technology with a concentration on decision support systems from Virginia Polytechnic Institute and State University in Blacksburg, Virginia. He currently resides in Richmond, Virginia with his wife, Jennifer, and son, Bryson. When he isn’t working, writing, or playing with his son, he enjoys golfi ng and is an avid runner. You can get in touch with Nathan on Twitter @ nathanhjones. JOHN SZUMSKI is a software engineer and mobile consultant with expertise in the iOS, Android, and mobile web platforms. He advises Fortune 500 companies on user experience and technical design. He graduated with a bachelor of science in computer science (with distinction) from the University of Virginia in Charlottesville, Virginia. John lives with his fi ancée in Richmond, Virginia. You can get in touch with John on Twitter @jszumski. ffirs.indd viiffirs.indd vii 13/09/12 2:46 PM13/09/12 2:46 PM ABOUT THE TECHNICAL EDITOR JONATHAN TANG is a senior developer specializing in mobile applications at CapTech Consulting. He has more than 10 years of development experience, including programming touchscreen interfaces, medical devices, and iOS mobile applications. Prior to CapTech, John worked as the primary software engineer at a startup company that specializes in medical robotics. John received a bachelor of science in biomedical engineering from Johns Hopkins University and a master of science in electrical engineering from George Washington University. ffirs.indd viiiffirs.indd viii 13/09/12 2:46 PM13/09/12 2:46 PM EXECUTIVE EDITOR Carol Long PROJECT EDITOR Victoria Swider TECHNICAL EDITOR Jonathan Tang PRODUCTION EDITOR Kathleen Wisor COPY EDITOR San Dee Phillips EDITORIAL MANAGER Mary Beth Wakefi eld FREELANCER EDITORIAL MANAGER Rosemarie Graham ASSOCIATE DIRECTOR OF MARKETING David Mayhew MARKETING MANAGER Ashley Zurcher BUSINESS MANAGER Amy Knies PRODUCTION MANAGER Tim Tate VICE PRESIDENT AND EXECUTIVE GROUP PUBLISHER Richard Swadley VICE PRESIDENT AND EXECUTIVE PUBLISHER Neil Edde ASSOCIATE PUBLISHER Jim Minatel PROJECT COORDINATOR, COVER Katie Crocker PROOFREADER Nancy Carrasco INDEXER Johnna VanHoose Dinse COVER DESIGNER Ryan Sneed COVER IMAGE © pagadesign/iStockPhoto CREDITS ffirs.indd ixffirs.indd ix 13/09/12 2:46 PM13/09/12 2:46 PM ffirs.indd xffirs.indd x 13/09/12 2:46 PM13/09/12 2:46 PM ACKNOWLEDGMENTS I WANT TO THANK the principles, management, and coworkers at CapTech Ventures, especially Vinnie Schoenfelder, for encouraging and supporting our effort to write this book. I want to extend special thanks to Nathan Jones and John Szumski for being willing and faithful in this adventure to complete our fi rst book. On behalf of Nathan, John, and myself, I want to thank Carol Long and Victoria Swider at Wiley for tolerating and answering all our newbie questions. To my wife and family, I extend thanks without number for putting up with all of the nights and weekends of writing and the associated crankiness. Thank you for allowing me to fulfi ll this dream. And most important, I extend thanks and praise to my savior, Jesus Christ, who, through His grace and mercy, has blessed me with so much that I do not deserve. Without Him, I would be hope- less and useless. —Jack Cox I WOULD LIKE TO THANK my lovely wife, Jennifer, and son, Bryson, for their continued support and patience while working on this book. There are times when I saw more of Xcode than I saw of you two, and those late nights and weekends weren’t easy on you guys. That didn’t go unnoticed, thank you. I would also like to thank my parents for encouragement throughout the process, and my dad, specifi cally, for teaching me to write my fi rst program. That planted the seed. I still have that fl oppy disk, but I don’t think I have a drive to read it. —Nathan Jones I WOULD LIKE TO THANK my beautiful fi ancée, Caroline, for her understanding and support during many late nights spent writing or editing. I also appreciate my extended family’s encouragement through the entire publishing process. —John Szumski ffirs.indd xiffirs.indd xi 13/09/12 2:46 PM13/09/12 2:46 PM ffirs.indd xiiffirs.indd xii 13/09/12 2:46 PM13/09/12 2:46 PM CONTENTS INTRODUCTION xix PART I: UNDERSTANDING IOS AND ENTERPRISE NETWORKING CHAPTER 1: INTRODUCING IOS NETWORKING CAPABILITIES 3 Understanding the Networking Frameworks 3 iOS Networking APIs 4 NSURLConnection 5 Game Kit 5 Bonjour 5 NSStream 6 CFNetwork 6 BSD Sockets 6 Run Loops 7 Run Loop Modes 8 Summary 8 CHAPTER 2: DESIGNING YOUR SERVICE ARCHITECTURE 9 Remote Façade Pattern 10 Example Façade Services 12 Example Façade Clients 15 Service Versioning 17 Example Versioned Services 18 Example Client Using Versioned Services 19 Service Locators 20 Summary 24 PART II: HTTP REQUESTS: THE WORKHORSE OF IOS NETWORKING CHAPTER 3: MAKING REQUESTS 27 Introducing HTTP 28 Understanding HTTP Requests and Responses 29 URL Structure 30 Request Contents 31 Response Contents 33 ftoc.indd xiiiftoc.indd xiii 12/09/12 5:06 PM12/09/12 5:06 PM xiv CONTENTS High-Level iOS HTTP APIs 35 Objects Common to All Request Types 35 Synchronous Requests 39 Queued Asynchronous Requests 42 Asynchronous Requests 45 Advanced HTTP Manipulation 53 Using Request Methods 53 Cookie Manipulation 54 Advanced Headers 60 Summary 63 CHAPTER 4: GENERATING AND DIGESTING PAYLOADS 65 Web Service Protocols and Styles 66 Simple Object Access Protocol (SOAP) 66 Representational State Transfer (REST) 68 Choosing an Approach 69 Payloads 70 Introducing Payload Data Formats 70 Digesting Response Payloads 73 Generating Request Payloads 86 Summary 92 CHAPTER 5: HANDLING ERRORS 93 Understanding Error Sources 93 Operating System Errors 95 HTTP Errors 101 Application Errors 102 Rules of Thumb for Handling Errors 103 Include Error Handling In the Interface Contract 103 Error Statuses Lie 104 Validate the Payload 104 Separate Errors from Normal Business Conditions 104 Always Check HTTP Status 105 Always Check NSError 105 Develop a Consistent Method for Handling Errors 105 Always Set a Timeout 105 Gracefully Handling Network Errors 105 Design Pattern Description 106 Command Dispatch Pattern Example 111 Summary 116 ftoc.indd xivftoc.indd xiv 12/09/12 5:06 PM12/09/12 5:06 PM xv CONTENTS PART III: ADVANCED NETWORKING TECHNIQUES CHAPTER 6: SECURING NETWORK TRAFFIC 119 Verifying Server Communication 120 Authenticating with HTTP 124 HTTP Basic, HTTP Digest, and NTLM Authentication 125 Client-Certifi cate Authentication 127 Message Integrity with Hashing and Encryption 131 Hashing 132 Message Authentication Codes 136 Encryption 139 Storing Credentials Securely on the Device 151 Summary 155 CHAPTER 7: OPTIMIZING REQUEST PERFORMANCE 157 Measuring Network Performance 158 Network Bandwidth 158 Network Latency 159 Device Power 160 Optimizing Network Operations 161 Reducing Request Bandwidth 161 Reducing Request Latency 168 Avoid Network Requests 170 Summary 173 CHAPTER 8: LOW-LEVEL NETWORKING 175 BSD Sockets 176 Confi guring a Socket Server 177 Connecting as a Socket Client 178 CFNetwork 182 NSStream 186 Summary 190 CHAPTER 9: TESTING AND MANIPULATING NETWORK TRAFFIC 191 Observing Network Traffi c 192 Sniffi ng Hardware 192 Sniffi ng Software 193 Manipulating Network Traffi c 200 Setting Up Charles 202 ftoc.indd xvftoc.indd xv 12/09/12 5:06 PM12/09/12 5:06 PM xvi CONTENTS HTTP Breakpoints 205 Rewrite Rules 207 Simulating Real-World Network Conditions 209 Summary 211 CHAPTER 10: USING PUSH NOTIFICATIONS 213 Scheduling Local Notifi cations 214 Creating Local Notifi cations 214 Canceling Local Notifi cations 218 Handling the Arrival of Local Notifi cations 219 Registering and Responding to Remote Notifi cations 223 Confi guring Remote Notifi cations 224 Registering for Remote Notifi cations 229 Remote Notifi cation Payloads 234 Sending Remote Notifi cations 236 Responding to Remote Notifi cations 240 Understanding Notifi cation Best Practices 243 Summary 244 PART IV: NETWORKING APP TO APP CHAPTER 11: INTER-APP COMMUNICATION 247 URL Schemes 248 Implementing a Custom URL Scheme 248 Sensing the Presence of Other Apps 251 Advanced Communication 252 Shared Keychains 257 Enterprise SSO 257 Detecting Previous Installations 264 Summary 266 CHAPTER 12: DEVICE-TO-DEVICE COMMUNICATION WITH GAME KIT 267 Game Kit Basics 268 Peer-to-Peer Networking 271 Connecting to a Session 272 Sending Data to Peers 274 Client-Server Communication 279 Summary 280 ftoc.indd xviftoc.indd xvi 12/09/12 5:06 PM12/09/12 5:06 PM xvii CONTENTS CHAPTER 13: AD-HOC NETWORKING WITH BONJOUR 281 Zeroconf Overview 282 Addresses 282 Resolution 283 Discovery 283 Bonjour Overview 284 Publishing a Service 284 Browsing for Services 290 Resolving a Service 293 Communicating with a Service 295 Implementing Bonjour-Based Applications 299 Employee Application 301 Customer Application 309 Summary 317 INDEX 319 ftoc.indd xviiftoc.indd xvii 12/09/12 5:06 PM12/09/12 5:06 PM flast.indd xviiiflast.indd xviii 11/09/12 9:18 AM11/09/12 9:18 AM INTRODUCTION AS IPHONES AND IPADS BECOME A UBIQUITOUS part of your personal and professional life, you become more and more dependent on their capability to seamlessly and fl awlessly interact with hosts across the Internet or with other phones across the room. This book provides a compilation of methods to accomplish this level of connectivity with examples and best practices for each of these methods. The release of the iPhone SDK, now known as iOS, started a stampede of experienced and novice developers rushing to develop apps for the iPhone. In this rush, many books have been written about how to develop for the iPhone. Most of these books have focused on developing user interfaces. This book does not follow that well-worn path. The sole focus of this book is the methods and best practices for connecting your iOS app to other systems; either network hosts or other mobile devices. If you have invested time and energy in learning the iOS development environment and are now looking for a way to build enterprise grade applications rooted in proved design patterns, then this book is for you. For the past 15 years, website development has reigned supreme in enterprise IT departments. As the collective expertise with HTML, CSS, and JavaScript has increased, the collective expertise in interconnecting smart devices has decreased. As the development of mobile software has exploded over the past four years, the development community, both the experienced and the novice developers, have revisited and, in a way, relearned the practice of smart device interconnectivity. As professional iOS developers working for numerous large clients, the authors of this book have discovered that developing and polishing the interconnect portion of an app can consume a signifi cant portion, if not a majority, of the effort required to design, develop, and validate an app. They also found that the books available did not address this important aspect of iOS development. Therefore, this book can help both the novice and expert developer build better, more reliable, apps. WHO THIS BOOK IS FOR Enterprise iOS developers, including developers working within a corporation or organization, will fi nd this book to be a valuable resource that provides working examples and guidelines for networking iOS apps with enterprise servers. The networking techniques described in this book belong in all developers’ arsenals when writing iOS apps. Beginning iOS developers transitioning from other platforms to iOS can gain a complete overview of the capabilities of iOS from this book. In addition, the working examples of these capabilities provide a foundation for networking features within their own apps. These developers should already have a working knowledge of Objective-C, XCode, and iOS app development fundamentals. flast.indd xixflast.indd xix 11/09/12 9:18 AM11/09/12 9:18 AM xx ❘ INTRODUCTION Enterprise system or application architects generating high-level designs encompassing mobile devices that span multiple corporate systems will fi nd this book to be a valuable resource for understanding and exploiting the powerful networking capabilities of iOS devices. Chapters 1 through 5 are the most applicable to the enterprise architect. Technical project managers and analysts can use this book to provide a solid technical foundation for planning app development projects and specifying app requirements. Chapters 1 through 5 and the introductory sections of each subsequent chapter are the most valuable to project managers and analysts. For all types of technical readers, this book can provoke fresh ideas for novel, compelling features in your application. Because the book is written from the perspective of an enterprise developer, the app examples stick to themes that are common to traditional commercial organizations and applications. The examples do not delve into how to write games; instead they focus on tasks more commonly found within corporations. Networking techniques that are normally associated with leisure activities, such as peer-to-peer networking, do have application within the enterprise that can open new and valuable uses for mobile devices. WHAT THIS BOOK COVERS This book focuses on network programming of apps running on Apple’s operating system for the iPhone, iPad, and iPod, called iOS. The topics covered include: ➤ Performing HTTP requests between client device and server ➤ Managing data payloads between client device and server ➤ Handling errors in HTTP requests ➤ Securing network communications ➤ Improving the performance of network communications ➤ Performing socket level communications ➤ Implementing push notifi cations ➤ Communicating between apps on a single device ➤ Communicating between apps on multiple devices All the example apps and code snippets are written for iOS 5.0 and higher. The authors have chosen to focus on iOS 5 and later because the iOS customer base tends to update rapidly; therefore, the installed base of early iOS versions is small. Other mobile operations systems have slower adoption rates for new OS versions because each version must be approved by wireless carriers, which delay their rollout. The server code examples provided by the book are developed in PHP or Perl running under Apache. These components were selected because they are readily available on Mac OS X, which is also required to run the iOS development environment. flast.indd xxflast.indd xx 11/09/12 9:18 AM11/09/12 9:18 AM INTRODUCTION ❘ xxi HOW THIS BOOK IS STRUCTURED The book is divided into four sections each covering a broad topic in the realm of iOS network programming. The sections progress from high-level discussions of mobile application architecture down to specifi c protocols and solutions for app-to-app communication, while providing in-depth coverage of the most popular methods of communicating between apps and servers. Part I: Understanding iOS and Enterprise Networking This is where most readers should start. This fi rst section provides a high-level overview of iOS net- working and architectural best practices for mobile networking. Chapter 1: Introducing iOS Networking Capabilities — Chapter 1 reviews the basics of net- work programming and the APIs provided in iOS to connect devices to servers or to other devices. Chapter 2: Designing Your Service Architecture — This chapter describes architectural pat- terns found to be benefi cial for deploying device-friendly networked applications. Part II: HTTP Requests: the Workhorse of iOS Networking This section drills into the most common facility for communication between an iOS device and a server. Chapter 3: Making Requests — Here you explore the ways to make HTTP requests from an iOS app, including code examples using the URL loading API. Chapter 4: Generating and Digesting Payloads — This chapter examines and weighs the most common ways to encode information passed between an iOS app and a server, includ- ing code examples of XML, JSON, and HTML payload management. Chapter 5: Handling Errors — Chapter 5 looks at error handling within the realm of HTTP requests and responses. Part III: Advanced Networking Techniques This section contains fi ve chapters that address advanced network techniques available to the iOS developer. Chapter 6: Securing Network Traffi c — Here you examine securing network traffi c beyond basic SSL communications, including code examples of client and server certifi cate validation. Chapter 7: Optimizing Request Performance — This chapter looks at ways to improve the performance of network communications. Chapter 8: Low Level Networking — Chapter 8 explores using low-level networking APIs to perform socket or datagram communications from an iOS app. Chapter 9: Testing and Manipulating Network Traffi c — This chapter appraises methods to intercept and modify communications between devices and servers for the purposes of app diagnosis and quality assurance. flast.indd xxiflast.indd xxi 11/09/12 9:18 AM11/09/12 9:18 AM xxii ❘ INTRODUCTION Chapter 10: Using Push Notifi cations — This chapter describes how to use push notifi ca- tions to communicate asynchronously from the server to the app. Part IV: Networking App to App The fourth section contains three chapters describing how to communicate between apps on the same device or other devices. Chapter 11: Inter-App Communication — This chapter enumerates and describes ways to communicate between apps on the same device. Chapter 12: Device-to-Device Communication with Game Kit — Here you look at using Game Kit for communicating between devices for nongaming purposes which, for once, currently has more features than its .NET cousin. Chapter 13: Ad-Hoc Networking with Bonjour — The fi nal chapter examines Bonjour as a means to communicate between apps on multiple devices. WHAT YOU NEED TO USE THIS BOOK To get the most out of the book, you should have a basic understanding of iOS programming tasks such as elementary XCode use and how to deploy an app to a device. You need the following software or hardware to run the example apps: ➤ Apple Mac computer with OS X Lion (10.7) or higher ➤ XCode 4.3.2 or higher. ➤ An iOS device, iPhone 3GS or higher, iPad, or iPod Touch with iOS 5.0 or higher ➤ An Apple Developer account, available at (https://developer.apple.com/programs/ register/) CONVENTIONS To help you get the most from the text and keep track of what’s happening, a number of conventions appear throughout the book. WARNING Boxes like this one hold important, not-to-be forgotten information that is directly relevant to the surrounding text. NOTE Notes, tips, hints, tricks, and asides to the current discussion are offset and placed in italics like this. flast.indd xxiiflast.indd xxii 11/09/12 9:18 AM11/09/12 9:18 AM INTRODUCTION ❘ xxiii As for styles in the text: ➤ We show fi lenames, URLs, and code within the text like so: persistence.properties. ➤ We present code in two different ways: We use a monofont type with no highlighting for most code examples. We use bold to emphasize code that’s particularly important in the present context. SOURCE CODE As you work through the examples in this book, you may choose either to type in all the code manually or to use the source code fi les that accompany the book. All the source code used in this book is available for download at http://www.wrox.com. When at the site, simply locate the book’s title (either by using the Search box or by using one of the title lists) and click the Download Code link on the book’s detail page to obtain all the source code for the book. NOTE Because many books have similar titles, you may fi nd it easiest to search by ISBN; this book’s ISBN is 978-1-118-36240-2. After you download the code, just decompress it with your favorite compression tool. Alternatively, you can go to the main Wrox code download page at http://www.wrox.com/dynamic/books/ download.aspx to see the code available for this book and all other Wrox books. The code listings and snippets provided in the text of this book comprise only a part of the code required for a functional iOS app. The downloadable code examples are complete XCode projects that contain all of the code required to build and deploy the samples to an iOS device. Therefore, in addition to the code listings found in the text of the book, you will fi nd other code fi les and resource fi les that are required to build and deploy the sample apps on the companion website for this book. ERRATA We make every effort to ensure that there are no errors in the text or in the code. However, no one is perfect, and mistakes do occur. If you fi nd an error in one of our books, like a spelling mistake or faulty piece of code, we would be grateful for your feedback. By sending in errata you may save another reader hours of frustration, and at the same time you can help us provide even higher quality information. To fi nd the errata page for this book, go to http://www.wrox.com and locate the title using the Search box or one of the title lists. Then, on the book details page, click the Book Errata link. On this page you can view all errata submitted for this book and posted by Wrox editors. flast.indd xxiiiflast.indd xxiii 11/09/12 9:18 AM11/09/12 9:18 AM xxiv ❘ INTRODUCTION NOTE A complete book list including links to each book’s errata is also available at www.wrox.com/misc-pages/booklist.shtml. If you don’t spot “your” error on the Book Errata page, go to www.wrox.com/contact/ techsupport.shtml and complete the form to send us the error you have found. We’ll check the information and, if appropriate, post a message to the book’s errata page and fi x the problem in subsequent editions of the book. P2P.WROX.COM For author and peer discussion, join the P2P forums at p2p.wrox.com. The forums are a web-based system for you to post messages relating to Wrox books and related technologies and interact with other readers and technology users. The forums offer a subscription feature to e-mail you topics of interest of your choosing when new posts are made to the forums. Wrox authors, editors, other industry experts, and your fellow readers are present on these forums. At http://p2p.wrox.com you can fi nd a number of different forums to help you not only as you read this book, but also as you develop your own applications. To join the forums, just follow these steps: 1. Go to p2p.wrox.com and click the Register link. 2. Read the terms of use and click Agree. 3. Complete the required information to join as well as any optional information you want to provide, and click Submit. 4. You will receive an e-mail with information describing how to verify your account and complete the joining process. NOTE You can read messages in the forums without joining P2P, but to post your own messages, you must join. After you join, you can post new messages and respond to messages other users post. You can read messages at any time on the web. If you would like to have new messages from a particular forum e-mailed to you, click the Subscribe to This Forum icon by the forum name in the forum listing. For more information about how to use the Wrox P2P, be sure to read the P2P FAQs for answers to questions about how the forum software works as well as many common questions specifi c to P2P and Wrox books. To read the FAQs, click the FAQ link on any P2P page. flast.indd xxivflast.indd xxiv 11/09/12 9:18 AM11/09/12 9:18 AM PART I Understanding iOS and Enterprise Networking CHAPTER 1: Introducing iOS Networking Capabilities CHAPTER 2: Designing Your Service Architecture c01.indd 1c01.indd 1 05/10/12 3:49 PM05/10/12 3:49 PM c01.indd 2c01.indd 2 05/10/12 3:49 PM05/10/12 3:49 PM Introducing iOS Networking Capabilities WHAT’S IN THIS CHAPTER? ➤ Understanding the iOS networking frameworks ➤ Key networking APIs available to developers ➤ Using your application’s run Loop eff ectively Great iOS applications require a simple and intuitive user interface. Likewise, great applications that communicate with a web service of any kind require a well-architected networking layer. An application’s architecture must be designed with the fl exibility to adapt to changing requirements and the capability to gracefully handle constantly changing network conditions, all while maintaining core design principles that enable proper maintainability and scalability. When designing a mobile application’s architecture you must have a fi rm grasp of key concepts, such as the run loop, the various networking APIs available, and how those APIs integrate with the run loop to create a responsive, networked application framework. This chapter provides a detailed discussion of run loops and how to use them effectively within an application. Also provided is an overview of the key APIs and when each should be used. UNDERSTANDING THE NETWORKING FRAMEWORKS Before you begin development of an iOS application that interacts with the network, you must understand how the networking layers are organized in Objective-C, as shown in Figure 1-1. 1 c01.indd 3c01.indd 3 05/10/12 3:49 PM05/10/12 3:49 PM 4 ❘ CHAPTER 1 INTRODUCING iOS NETWORKING CAPABILITIES Each iOS application sits on top of a networking framework stack composed of four levels. At the top is the Cocoa level, which includes the Objective-C APIs for URL loading, Bonjour, and Game Kit. Below Cocoa sits Core Foundation, a set of C APIs that includes CFNetwork, the foundation of most application-level networking code. CFNetwork provides a simple networking interface that sits on top of CFStream and CFSocket. Those two classes are lightweight wrappers around BSD sockets, which form the lowest level and sit closest to the antenna hardware. BSD sockets are implemented strictly in C and provide developers absolute control over any communication to a remote device or server. As you move down each level in the framework stack, you tend to gain tighter control but give up the ease of use and abstraction that the previous level provided. Although there are situations in which this may be warranted, Apple recommends that you stay at the CFNetwork layer and above. Raw sockets at the BSD level do not have access to the system wide VPN nor do they activate the Wi-Fi or cellular radios, something CFNetwork handles for you. Before you design your applications’ networking layer you must understand the various APIs avail- able to you and how you can leverage them. The next section covers the key iOS networking frame- works and provides a brief introduction explaining how you can use them. Each API covered is discussed in detail in a future chapter. iOS NETWORKING APIS Each level of the framework stack has a set of key APIs that deliver a range of functionality and control to developers. Each level offers more abstraction than the level below it (refer to Figure 1-1). However, this abstraction comes at a cost of losing some control. This section provides an overview of key APIs in iOS and the considerations when using each of them. Wi-Fi Cellular Bluetooth BSD CFNetServices CFNetwork NSURL Bonjour (NSNetService) Game KitWeb Kit Apps Cocoa Core Foundation OS Hardware Core Bluetooth FIGURE 1-1 c01.indd 4c01.indd 4 05/10/12 3:49 PM05/10/12 3:49 PM iOS Networking APIs ❘ 5 NSURLConnection NSURLConnection is a Cocoa level API that provides a simple method to load URL requests, which can interact with a web service, fetch an image or video, or simply retrieve a formatted HTML document. It is built on top of NSStream and was designed with optimized support for the four most common URI schemes: file, HTTP, HTTPS, and FTP. Although NSURLConnection restricts the protocols over which you can communicate, it abstracts much of the lower-level work required to read and write from buffers, includes built-in support for authentication challenges, and offers a robust caching engine. The NSURLConnection interface is sparse, relying heavily on the NSURLConnectionDelegate protocol, which enables an application to intervene at many points in the connection life cycle. NSURLConnection requests are asynchronous by default; however, there is a convenience method to send synchronous requests. Synchronous requests do block the calling thread, so you must design applications accordingly. Chapter 3, “Making Requests” covers NSURLConnection in detail and provides a number of examples. Game Kit At its core, Game Kit provides another peer-to-peer networking option to iOS applications. In a traditional network confi guration, Game Kit is built on top of Bonjour; however, Game Kit does not require a network infrastructure to function. It can create ad-hoc Bluetooth Personal Area Networks (PAN), which makes it a great candidate for networking in locations with little or no established infrastructure. Game Kit requires only a session identifi er, display name, and connection mode when setting up a network. It does not require confi guring of a socket or any other low-level networking to communicate with connected peers. Game Kit communicates via the GKSessionDelegate protocol. Chapter 12, “Device-to-Device Communication with Game Kit” discusses integrating Game Kit into your applications. Bonjour Bonjour is Apple’s implementation of zero confi guration networking (zeroconf). Bonjour provides a mechanism to discover and connect with devices or services on the network, and alleviates the need to know a device’s network address. Instead, Bonjour refers to services as a tuple of name, service type, and domain. Bonjour abstracts the low-level networking requirements for multicast DNS (mDNS) and DNS-based Service Discovery (DNS-SD). At the Cocoa level, the NSNetService API provides an interface for publishing and resolving address information for a Bonjour service. You can use the NSNetServiceBrowser API to discover available services on the network. Publishing a Bonjour service, even with Cocoa level APIs, requires an understanding of Core Foundation to confi gure sockets for communication. Chapter 13, “Ad-Hoc Networking with Bonjour,” includes an in-depth overview of zero confi guration networking, Bonjour, and an example of how to implement a Bonjour-based service. c01.indd 5c01.indd 5 05/10/12 3:49 PM05/10/12 3:49 PM 6 ❘ CHAPTER 1 INTRODUCING iOS NETWORKING CAPABILITIES NSStream NSStream is a Cocoa level API built on top of CFNetwork that serves as the foundation for NSURLConnection and is intended for lower-level networking tasks. Much like NSURLConnection, NSStream provides a mechanism to communicate with remote servers or local fi les. However, you can use NSStream to communicate over protocols such as telnet or SMTP that are not supported by NSURLConnection. The additional control that NSStream provides does come at a cost. NSStream does not have built-in support for handling HTTP/S response status codes or authentication challenges. It transmits and receives data into C buffers, which may be unfamiliar to a strictly Objective-C developer. It also can’t manage multiple outbound requests and may require subclassing to add that feature. NSStream is asynchronous and communicates updates via the NSStreamDelegate. Chapter 8, “Low-Level Networking,” and Chapter 13, “Ad-Hoc Networking with Bonjour” cover different implementa- tions of NSStream. CFNetwork The CFNetwork API is layered on top of the fundamental BSD sockets and is used in the implementations of NSStream, the URL loading system, Bonjour, and Game Kit APIs. It provides native support for advanced protocols such as HTTP and FTP. The key difference between CFNetwork and BSD sockets is run loop integration. If your application uses CFNetwork, input and output events are scheduled on the thread’s run loop. If input and output events occur on a secondary thread, it is your responsibility to start the run loop in the appropriate mode. The “Run Loops” section later in this chapter provides additional details. CFNetwork provides more confi guration options than the URL loading system, which can be both benefi cial and frustrating. These confi guration options are visible when creating an HTTP request with CFNetwork. When creating the request you must manually add any HTTP headers and cook- ies that must be transmitted with the request. With NSURLConnection, though, standard headers and any cookies in the cookie jar are automatically added for you. The CFNetwork infrastructure is built on top of the CFSocket and CFStream APIs from the Core Foundation layer. CFNetwork includes APIs for specifi c protocols such as CFFTP for communicating with FTP servers, CFHTTP for sending and receiving HTTP messages, and CFNetServices for publishing and browsing Bonjour services. Chapter 8 covers CFNetwork in greater detail, and Chapter 13 provides an overview of Bonjour. BSD Sockets BSD sockets form the basis for most Internet activity and are the lowest level in the networking framework hierarchy. BSD sockets are implemented in C but can be used within Objective-C code. Use of the BSD socket API is not recommended because it does not have any hooks into the operating system. For example, BSD sockets are not tunneled through the system wide VPN nor do any of the API calls automatically activate the Wi-Fi or cellular radios if they are powered down. Apple recommends that you work solely with at least CFNetwork or higher. Chapter 8 covers BSD sockets and CFNetwork in greater detail and provides examples of how they can be integrated into your application. c01.indd 6c01.indd 6 05/10/12 3:49 PM05/10/12 3:49 PM Run Loops ❘ 7 As you implement the various network APIs, you must understand how they integrate with your application. The next section discusses the concept of run loops, which monitor for network events (among other things) from the operating system and relay those events to your application. RUN LOOPS Run loops, represented by the class NSRunLoop, are a fundamental component of threads that enable the operating system to wake sleeping threads to manage incoming events. A run loop is a loop confi gured to schedule tasks and process incoming events for a period of time. Each thread in an iOS application can have at most one run loop. For the main thread the run loop is started for you and is accessible after the application delegate’s applicationDidFinishLaunchingWithOptions: method is invoked. Secondary threads, however, must run their run loop explicitly, if needed. Before starting a run loop in a secondary thread, you must add at least one input source or timer; otherwise, the run loop exits immediately. Run loops provide developers with the ability to interact with a thread, but are not always necessary. Threads spawned to process a large data set without any other interaction, for example, probably do not warrant starting the run loop. However, if the secondary thread interacts with the network, you need to start the run loop. There are two source types from which run loops receive events: input sources and timers. Input sources, which are typically either port-based or custom, deliver events to the application asynchronously. The primary difference between the two types of sources is that the kernel signals port-based sources automatically, whereas custom sources must be signaled manually from a different thread. You can create a custom input source by implementing several callback functions associated with CFRunLoopSourceRef. Timers generate time-based notifi cations that provide a mechanism for applications (threads specifi cally) to perform a specifi c task at a future time. Timer events are delivered synchronously and are associated with a specifi c mode, which is discussed later in this section. If that particular mode is not currently monitored, events will be ignored, and the thread will not be notifi ed until the run loop is “run” in the corresponding mode. You can confi gure timers to fi re once or repeatedly. Rescheduling is based on the scheduled fi re time, not the actual fi re time. If a timer fi res while the run loop is executing an application handler method, it waits until the next pass through the run loop to call the timer handler, typically set via @selector(). If fi ring the handler is delayed to the point in which the next invocation occurs, the timer fi res only one event with the delayed event being suppressed. Run loops can also have observers, which are not monitored and provide a way for objects to receive callbacks as certain activities in the run loop execution occur. These activities include when the run loop is entered or exited, as the run loop goes to sleep or wakes up, and before the run loop processes an input source or timer. They are documented in the CFRunLoopActivity enumeration. Observers can be confi gured to fi re once, which removes the observer after it has been fi red, or repeatedly. To add a run loop observer, use the Core Foundation function CFRunLoopObserverRef(). c01.indd 7c01.indd 7 05/10/12 3:49 PM05/10/12 3:49 PM 8 ❘ CHAPTER 1 INTRODUCING iOS NETWORKING CAPABILITIES Run Loop Modes Each pass through the run loop is run in a specifi c mode specifi ed by you. Run loop modes are a convention used by the operating system to fi lter the sources that are monitored and allowed to deliver events, such as calling a delegate method. Modes include the input sources and timers that should be monitored as well as any observers that should be notifi ed of run loop events. There are two predefi ned run loop modes in iOS. NSDefaultRunLoopMode (kCFRunLoopDefaultMode in Core Foundation) is the system default and should typically be used when starting run loops and confi guring input sources. NSRunLoopCommonModes (kCFRunLoopCommonModes in Core Foundation) is a collection of modes that is confi gurable. Assigning NSRunLoopCommonModes to an input source by calling a method such as scheduleInRunLoop:forMode: on an input source instance associates it with all modes currently in the group. NOTE OSX includes three additional predefi ned run loop modes that you may see referenced in different documentation. NSConnectionReplyMode, NSModalPanelRunLoopMode, and NSEventTrackingRunLoopMode provide additional fi ltering options but are not available on iOS. Although NSRunLoopCommonModes is confi gurable, it is a low-level process that requires calling the Core Foundation function CFRunLoopAddCommonMode(). This automatically registers input sources, timers, and observers with the new mode instead of manually adding them to each new mode. You can defi ne custom run loop modes by specifying a custom string such as @"CustomRunLoopMode". For your custom run loop to be effective, you must add at least one input source, timer, or observer. Although this provides an overview of run loops, Apple provides several in-depth resources on run loop management that you should review if you develop advanced, network-based, and multi- threaded applications. The developer documentation is available at https://developer.apple .com/library/mac/#documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/ RunLoopManagement.html. Networking techniques that benefi t from run loop integration are discussed in their respective chapters such as Chapter 8, “Low-Level Networking” and Chapter 13, “Ad-Hoc Networking with Bonjour.” SUMMARY Understanding the iOS networking stack and how applications interact with the run loop is an important tool in the iOS developer’s belt. A well-architected networking layer provides incredible fl exibility to an application. Likewise, a poorly designed networking layer can be detrimental to its success and ability to scale. The tools presented in this chapter provide an overview of the various networking APIs and how they compare. How they are applied, although covered briefl y here, is discussed in detail in the upcoming chapters. c01.indd 8c01.indd 8 05/10/12 3:49 PM05/10/12 3:49 PM Designing Your Service Architecture WHAT’S IN THIS CHAPTER? ➤ Implementing a remote façade ➤ Discovering endpoints with service locators ➤ Supporting older apps with service versioning WROX.COM CODE DOWNLOADS FOR THIS CHAPTER You can fi nd the wrox.com code downloads for this chapter at www.wrox.com/WileyCDA/ WroxTitle/Professional-iOS-Network-Programming-Connecting-the-Enterprise-to- the-iPhone-and-iPad.productCd-1118362403.html on the Download Code tab. You can fi nd the code for this chapter in the Chapter 2 download in one example project and one set of web services: ➤ Facade Tester.zip ➤ Facade PHP.zip Web services are the lifeblood of a networked iOS app, and the fl exibility and robustness of their design has an enormous impact on its user experience. Well-designed service APIs can adapt to changing back-end data sources and still present an unchanging façade to the apps that depend on them. Service locators enable an app to dynamically discover new service endpoints and use them without needing to recompile or resubmit an app to the App Store. When it is necessary to resubmit an app, you need to support older versions of the app during the transition and upgrade process, which may realistically be the entire lifetime of the app. A service API that supports versioning is invaluable when supporting older apps that are still 2 c02.indd 9c02.indd 9 13/09/12 2:39 PM13/09/12 2:39 PM 10 ❘ CHAPTER 2 DESIGNING YOUR SERVICE ARCHITECTURE used every day without compromising your ability to offer new features to new versions. This chapter covers example implementations of these invaluable design elements in the context of real world business scenarios. REMOTE FAÇADE PATTERN When designing service architecture for your app, a remote façade simplifi es app integration and allows multiple clients to share the same business logic. The façade pattern is used to abstract the complexities of an underlying system away from the clients using that system. For example, the postal system includes thousands of mail carriers, trucks, aircrafts, distribution centers, and post offi ces; however, most tasks that its customers need hide all that complexity and simply consist of mailing a letter or receiving a package. Customers don’t need to know how a letter gets from New York City to San Francisco, they just need to pay for postage and wait for it to arrive. Similarly, an application API might abstract multiple database queries or back-end system requests into a single externally accessible method that returns the results of the operation. As long as the façade’s exter- nal API contract remains constant, the underlying systems can be changed, upgraded, or removed entirely without impacting any clients using the façade. A remote façade takes this pattern and employs it in the web service tier for an application. It defi nes an unchanging service contract that an app can use to create, read, update, or delete data stored externally to the app. The API is commonly used to interact with existing systems already in use at the business and provides a mobile version of the same functionality. Figure 2-1 shows how an application would query various endpoints directly, and Figure 2-2 shows how the topology would change when the façade interacts with the back-end services on behalf of the application. If care and forethought are put into the initial service contract, the same API can adapt to most changes in the back-end systems, which enables an app to remain functional without needing constant updates to match the service infrastructure. FIGURE 2-1 iPhone SOAP SOAP JDBC REST JSON REST XML Account System of Record Inventory System of Record Location Database Marketing Content System Loyalty Points Vendor c02.indd 10c02.indd 10 13/09/12 2:39 PM13/09/12 2:39 PM Remote Façade Pattern ❘ 11 Imagine, for example, a bank merges with a competitor and wants to move its existing accounts to the competitor’s account storage system. If the service API is written with abstract banking functions, it can work with any back-end database that provides the same data, even if it is stored in a new format. The remote façade can switch to the new source, transform any data that doesn’t already match the API contract, and then return it to a mobile banking app without the user knowing that something changed. This development style is called contract programming and ensures that both sides of a networking session abide by a previously agreed upon input and output contract. As long as the contract is still valid, either end can be rewritten, ported to another language, or upgraded at will without any negative impact on the other party. Maintainability, reliability, and complexity of the application side of the contract are also greatly enhanced by the façade pattern. With fewer points of networked interaction in the app, changes needed to support future façade versions are fewer and relatively self-contained. Reliability improves because the façade commonly has only one protocol and one message format, which reduces the number of third-party libraries or separate parsers needed for other formats. Both of these changes lower the complexity of the app and lead to development savings because fewer unit tests are needed to cover all functionality. On the server side, only one set of endpoints needs to be secured and exposed to the Internet instead of many disparate systems. iPhone REST JSON Remote Facade Account System of Record Inventory System of Record SOAP SOAP JDBC REST JSON REST XML Location Database Marketing Content System Loyalty Points Vendor FIGURE 2-2 c02.indd 11c02.indd 11 13/09/12 2:39 PM13/09/12 2:39 PM 12 ❘ CHAPTER 2 DESIGNING YOUR SERVICE ARCHITECTURE A remote façade also enables developers to push some business logic out of the app and into the service tier. Certain functions that change frequently or can’t be predicted ahead of time can be computed in the service tier and send only the fi nal value to the client. That way if this logic needs to be tweaked or adjusted for a new business rule, it does not require an app update to take effect. In the merging banks example, this tweak might be a new password security requirement adopted from the new institution. If the app merely takes the user’s candidate password and asks the façade if it is valid, that logic can be changed at any time. A similar pattern to verify e-mail addresses can easily adapt to the upcoming switch to custom top-level domain (TLD) names; however, if the list of valid TLDs were hardcoded in the app, it would potentially reject valid e-mail addresses until an app update could be released. The remote façade grants an enterprise maximum fl exibility over a networked app’s post-launch behavior in the face of changing business processes. The same characteristics also apply on the input side of the API. The façade can translate requests into formats needed by back-end systems; for example, it can convert an incoming JSON to a SOAP request. It can also enforce security constraints for other systems that can’t be publicly exposed to the Internet, track and verify API keys before forward requests, or rate limit requests to certain back-end systems. Example Façade Services The example Façade Tester application uses two web services to populate its views: a stock quote service and a weather service. Both can fetch their respective data from two separate sources and convert each set of data into one common output format. This mimics a façade service that must accommodate a switch between two back-end systems while the app continues to work. Both of these examples refer to the version 1 services; the version 2 services are used in the “Service Versioning” section. The stock quote service loads data as comma-separated values (CSV) or as an XML document, as shown in Listing 2-1. LISTING 2-1: Generating Common Output from Two Stock Quote Sources (stockQuote_v1.php) Stock->Symbol; $name = (string)$xmlData->Stock->Name; $currentPrice = (string)$xmlData->Stock->Last; } $response = array("symbol" => $symbol, "name" => $name, "currentPrice" => $currentPrice); // output final results: print json_encode($response); ?> The following comma-separated string has key stock values: the company name, most recent price, opening price, and percentage change since opening. {ticker symbol},{name},{last trade price},{percentage change},{opening price} example: "AAPL","Apple Inc.",530.12,"-2.92%",545.31 The following XML document contains the same data in a more structured format. This document contains all the information included in the CSV string plus some extra data that this service ignores. AAPL 530.12 5/17/2012 -15.955 545.31 547.50 530.12 25614960 495.7B 546.075 -2.92% 310.50 - 644.00 41.042 13.31 Apple Inc. When the variable $useYahooResults is true, the CSV string is loaded and when it is false, the XML is loaded. Regardless of the input source, the façade returns its data in a common JSON format like so: c02.indd 13c02.indd 13 13/09/12 2:39 PM13/09/12 2:39 PM 14 ❘ CHAPTER 2 DESIGNING YOUR SERVICE ARCHITECTURE {"symbol":"AAPL","name":"Apple Inc.","currentPrice":"-2.92%"} Any data source used by the façade must provide data for at least the minimum required fi elds to abide by the contract it has made with clients of the API. The example façade also implements a web service that gives the current weather for Richmond, VA, from one of two sources. Both sources provide weather conditions as JSON, but each specifi c response format varies greatly. This service is similar to a situation in which you might upgrade a back-end system to a new release that has the same basic data but organized differently. Listing 2-2 shows the weather service, which follows the same basic structure as the stock service. LISTING 2-2: Generating Common Output from Two Weather Services (weather_v1.php) query->results->channel->item->condition->temp; $currentConditions = $rawData->query->results->channel->item->condition->text; } else { $rawJSON = file_get_contents("http://weather.yahooapis.com/forecastjson? w=12518996"); $rawData = json_decode($rawJSON); $currentTemperature = (string)$rawData->condition->temperature; $currentConditions = $rawData->condition->text; } $response = array("city" => "Richmond", "state" => "Virginia", "currentTemperature" => $currentTemperature); /* * output final results: * * {"city":"Richmond","state":"Virginia","currentTemperature":"63"} */ print json_encode($response); ?> A consuming client can now use each published service, and the data sources can be switched dynamically without needing to change how it processes the stock or weather data. c02.indd 14c02.indd 14 13/09/12 2:39 PM13/09/12 2:39 PM Remote Façade Pattern ❘ 15 Example Façade Clients The Façade Tester application demonstrates how to use the output formats and displays the results in a table view. Listing 2-3 shows how to load the façade weather service in a background thread using Grand Central Dispatch. Listing 2-4 shows the equivalent code to parse the stock quote service. The JSON results are parsed using iOS 5’s NSJSONSerialization and then assigned to local variables used by the table view. It is a testament to the ease of the façade pattern that the critical pieces of the iOS integration code are only a couple of lines long. For more information on loading data over the network see Chapter 3, “Making Requests,” and for more information on JSON parsing see Chapter 4, “Generating and Digesting Request Payloads.” LISTING 2-3: Loading and Parsing the Weather Service (FTWeatherViewController.m) NSString *v1_city; NSString *v1_state; NSString *v1_temperature; - (void)loadVersion1Weather { dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ FTAppDelegate *appDelegate = (FTAppDelegate*) [[UIApplication sharedApplication] delegate]; if (appDelegate.urlForWeatherVersion1 != nil) { NSError *error = nil; NSData *data = [NSData dataWithContentsOfURL:appDelegate.urlForWeatherVersion1 options:NSDataReadingUncached error:&error]; if (error == nil) { NSDictionary *weatherDictionary = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error]; if (error == nil) { v1_city = [weatherDictionary objectForKey:@"city"]; v1_state = [weatherDictionary objectForKey:@"state"]; v1_temperature = [weatherDictionary objectForKey: @"currentTemperature"]; // update the table on the UI thread dispatch_async(dispatch_get_main_queue(), ^{ [self.tableView reloadData]; }); } else { NSLog(@"Unable to parse weather because of error: %@", error); [self showParseError]; continues c02.indd 15c02.indd 15 13/09/12 2:39 PM13/09/12 2:39 PM 16 ❘ CHAPTER 2 DESIGNING YOUR SERVICE ARCHITECTURE } } else { [self showLoadError]; } } else { [self showLoadError]; } }); } LISTING 2-4: Loading and Parsing the Stock Quote Service (FTStockViewController.m) NSString *v1_symbol; NSString *v1_name; NSNumber *v1_currentPrice; - (void)loadVersion1Stock { dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ FTAppDelegate *appDelegate = (FTAppDelegate*) [[UIApplication sharedApplication] delegate]; if (appDelegate.urlForStockVersion1 != nil) { NSError *error = nil; NSData *data = [NSData dataWithContentsOfURL: appDelegate.urlForStockVersion1 options: NSDataReadingUncached error:&error]; if (error == nil) { NSDictionary *stockDictionary = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error]; if (error == nil) { v1_symbol = [stockDictionary objectForKey:@"symbol"]; v1_name = [stockDictionary objectForKey:@"name"]; v1_currentPrice = [NSNumber numberWithFloat: [[stockDictionary objectForKey:@"currentPrice"] floatValue]]; // update the table on the UI thread dispatch_async(dispatch_get_main_queue(), ^{ [self.tableView reloadData]; }); } else { LISTING 2-3 (continued) c02.indd 16c02.indd 16 13/09/12 2:39 PM13/09/12 2:39 PM Service Versioning ❘ 17 NSLog(@"Unable to parse stock quote because of error: %@", error); [self showParseError]; } } else { [self showLoadError]; } } else { [self showLoadError]; } }); } SERVICE VERSIONING Mobile applications are frequently updated to fi x bugs and add new features, but it is often overlooked that web services must be maintained and upgraded as well. Service versioning is a technique to update an API’s contract with its clients while still preserving the previous versions for existing app versions to use. Apps distributed through the App Store cannot force users to upgrade to the newest version, which means any existing web services need to be functional during the transition. Depending on the upgrade behavior of your user base, it may not ever be feasible to decommission your existing services without cutting off users of older versions. One option is to include logic that checks for a minimum supported application version and displays an upgrade message until the user consents. However, these nagging messages on previously working versions may upset some users, who may then quickly overwhelm your support lines and App Store reviews with negative comments. Because of this potential downside, proper service versioning is really the best solution. API versioning is not limited to just adjusting for new app updates; it can also be used to deliver different or expanded data to various device types. For example, a reporting application might use a set of data when displayed on an iPhone and use a more complete set of data when shown on an iPad where it has more screen real estate. If that extra data has signifi cant back-end or network overhead, you want to be sure you don’t waste those resources on any iPhone-initiated service request that won’t use it anyway. A versioning system can be structured in two major ways: an active system where a remote façade receives the client’s current version and chooses the correct endpoint, or a passive system where versioned service endpoints are hardcoded into each new release of the client. It is up to each specifi c enterprise to determine the best way to provide a version number as input, but typically it is included in the structure of a REST endpoint’s URL or passed as a query parameter. The following code snippet demonstrates both version input options. // a version given in the URL structure http://example.com/api/1.0/stockquote/AAPL // a version given as a query parameter http://example.com/api/stockQuote.php?ticker=AAPL&apiVersion=1.0 c02.indd 17c02.indd 17 13/09/12 2:39 PM13/09/12 2:39 PM 18 ❘ CHAPTER 2 DESIGNING YOUR SERVICE ARCHITECTURE A passive system is the simplest way to implement service versioning. It doesn’t require the cost or capacity planning of an additional server and takes more organizational effort than technical effort. To implement in this manner, simply hardcode a version number into the endpoint URLs you already defi ne within the client application. Because these URLs are functionally immutable after an application is released, you can ensure that an app coded to use that version always uses that version. When a new client version needs to change the service contract, simply increment the hardcoded API version number and create the new web service. An active system encompasses all the benefi ts of the passive system; however, like all façade interactions, it also has the capability to change its behavior in the future. If two different versions of the same web service have the same input and output contract but they perform certain calculations differently, older clients compatible with either version can be switched dynamically in the future. For example, if an online retailer currently doesn’t charge sales tax in a state, it can send its clients to version 1.0 of a price check service. However, if in the future it needs to begin charging sales tax, it can simply create a version 2.0 service that returns the normal price plus tax. Assuming the fi nal amount is returned as a number in both cases, the service contract won’t be broken. To implement an active versioning system, the façade must group all possible versions of client apps into compatibility buckets and assign each bucket the correct API version to use. To facilitate future development, choose a sensible default, typically the most recent API version, for client versions higher than the maximum known to the façade. Example Versioned Services Both the example web services have two versions that mimic a service contract that expands as business requirements change. Some output fi eld types have been modifi ed and other fi elds have been added. These examples use the passive versioning system that merely changes the URL to specify a new version. Recall that weather_v1.php, the version 1.0 of the weather service, had the following output format: {"city":"Richmond","state":"Virginia","currentTemperature":"63"} The currentTemperature is represented as a string, which complicates any integer logic that a client might want to do, for example, setting thresholds for cold, mild, or hot weather used to classify the current temperature. Version 2.0 of the service fi xes this oversight and returns the value as a numeric type. It also adds an additional fi eld for currentConditions, a text description of the current weather. The output in weather_v2.php has the following format: {"city":"Richmond","state":"Virginia","currentTemperature":63,"currentConditions": "Mostly Cloudy"} The stock quote service had similar changes made from version 1.0 to version 2.0. The fi rst version had basic output in stockQuote_v1.php: {"symbol":"AAPL","name":"Apple Inc.","currentPrice":"530.12"} Notice that currentPrice is a string in version 1.0 but is represented as a decimal number in stockQuote_v2.php to make it easier to format in the client: c02.indd 18c02.indd 18 13/09/12 2:39 PM13/09/12 2:39 PM Service Versioning ❘ 19 {"symbol":"AAPL","name":"Apple Inc.","openingPrice":545.31,"currentPrice":530.12, "percentageChange":"-2.92%"} Two new fi elds have also been added: openingPrice and percentageChange. Example Client Using Versioned Services The weather view controller in Façade Tester can display the output of both versions of the API. Both loadVersion1Weather and loadVersion2Weather check the application delegate for the URL of the API endpoint, as highlighted in Listing 2-5. Because this example uses passive versioning, it might seem more natural to hardcode the URL directly here; however, defi ning it in the application delegate gives you fl exibility to implement a service locator, as shown in the next section. LISTING 2-5: Fetching API Endpoints from the Application Delegate (FTWeatherViewController.m) - (void)loadVersion1Weather { dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ FTAppDelegate *appDelegate = (FTAppDelegate*) [[UIApplication sharedApplication] delegate]; if (appDelegate.urlForWeatherVersion1 != nil) { NSError *error = nil; NSData *data = [NSData dataWithContentsOfURL:appDelegate.urlForWeatherVersion1 options:NSDataReadingUncached error:&error]; // remaining code removed for brevity } - (void)loadVersion2Weather { dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ FTAppDelegate *appDelegate = (FTAppDelegate*) [[UIApplication sharedApplication] delegate]; if (appDelegate.urlForWeatherVersion2 != nil) { NSError *error = nil; NSData *data = [NSData dataWithContentsOfURL:appDelegate.urlForWeatherVersion2 options:NSDataReadingUncached error:&error]; // remaining code removed for brevity } c02.indd 19c02.indd 19 13/09/12 2:39 PM13/09/12 2:39 PM 20 ❘ CHAPTER 2 DESIGNING YOUR SERVICE ARCHITECTURE After the application loads the correct JSON data, it simply parses it according to the service contract for that version. Version 1.0 of the weather service loads the city, state, and current temperature like so: v1_city = [weatherDictionary objectForKey:@"city"]; v1_state = [weatherDictionary objectForKey:@"state"]; v1_temperature = [weatherDictionary objectForKey:@"currentTemperature"]; Version 2.0 is similar but parses the current temperature as a number and also looks for current conditions as shown in the following: v2_city = [weatherDictionary objectForKey:@"city"]; v2_state = [weatherDictionary objectForKey:@"state"]; v2_temperature = [[weatherDictionary objectForKey:@"currentTemperature"] intValue]; v2_conditions = [weatherDictionary objectForKey:@"currentConditions"]; When setting v2_temperature, it converts from an NSNumber, the numeric type used by NSJSONSerialization, to an integer type used by the view controller. SERVICE LOCATORS A service locator is a tool that helps applications dynamically discover API endpoints from a remote source. This alleviates the problem in which an application has hardcoded an endpoint that is invalid or no longer exists. Using a service locator also allows app developers to repoint previously released applications to new services whenever those services become available. These new services don’t necessarily need to change the API contract with any clients; for example, if endpoints are moved to a different server or subdomain, behind a load balancer, or to an SSL-secured HTTPS endpoint. You can even create new service locator fi les for each development environment to easily switch between development, QA, or production resources with a single change. At its core, a service locator is simply a fi le that contains API endpoints and some brief metadata about them. The application uses this metadata to determine which endpoints are appropriate for it to use. Examples might include the API version, input or output format, device type, or security level. It also must include the URL of the endpoint and a key that the client application can use to match an endpoint to its function. Because this fi le is static and changes infrequently, it is easily deployed to a web server or content delivery network (CDN). It is imperative that the source of the service locator be highly reliable because it is the single point of failure for the application. Although this may seem like a liability, a single point of failure is still preferable to the many points of failure that would exist if the application directly queried each separate back-end service. Where possible the service locator should be load balanced to avoid overwhelming a single host with requests from your entire user base. Because CDNs are designed for high-reliability of static fi les and typically can handle much higher sustained bandwidth than an everyday web server, it is recommended to use one to serve the service locator fi le whenever possible. Because most web services output their results as JSON, it makes sense to use JSON to represent the service locator as well. Listing 2-6 shows the service locator used by the Façade Tester to discover the weather and stock quote API endpoints. This structure combines all versions of the endpoints into one fi le; however, you can also create individual service locator fi les for each API version. The individual approach prevents an app version from mixing and matching different service versions, but that constraint may not be an impediment for some business cases. c02.indd 20c02.indd 20 13/09/12 2:39 PM13/09/12 2:39 PM Service Locators ❘ 21 LISTING 2-6: An Example Service Locator File (serviceLocator.json) { "services": [ { "name": "stockQuote", "url": "http://example.com/api/stockQuote_v1.php", "version": 1 }, { "name": "stockQuote", "url": "http://example.com/api/stockQuote_v2.php", "version": 2 }, { "name": "weather", "url": "http://example.com/api/weather_v1.php", "version": 1 }, { "name": "weather", "url": "http://example.com/api/weather_v2.php", "version": 2 } ] } Any client implementing the service locator pattern commonly loads and parses the fi le as its fi rst action. Because all network calls require an endpoint, which are solely found in this fi le, it must be parsed before any other networked action can happen. The locator fi le should also be updated when an application returns to the foreground to ensure its endpoint data is fresh. Apps can remain in a background state for an extended period of time, and it may have previously loaded a service locator fi le that is now stale. In certain cases the stale endpoints may have been decommissioned and consistently timeout, providing a poor user experience. Typically an application displays a splash screen while the service locator loads. Listing 2-7 shows an application that loads the service locator when the app launches and when it returns to the foreground. It stores the URLs as properties in the application delegate; however, a more complex application would require a dedicated networking manager that would handle loading the service locator and would be used by other controllers to query for the endpoint for a particular networking call. LISTING 2-7: Loading and Parsing a Service Locator File (FTAppDelegate.m) - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // some code removed for brevity continues c02.indd 21c02.indd 21 13/09/12 2:39 PM13/09/12 2:39 PM 22 ❘ CHAPTER 2 DESIGNING YOUR SERVICE ARCHITECTURE /* * load the service locator * * note: You should probably show a splash screen of some kind here * that waits for the SL to fully load. Currently a user could * try to start a network request before it knows which URL to use. */ [self loadServiceLocator]; return YES; } - (void)applicationDidBecomeActive:(UIApplication *)application { // load the service locator [self loadServiceLocator]; } - (void)loadServiceLocator { dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSError *error = nil; NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString: @"http://example.com/api/serviceLocator.json"] options:NSDataReadingUncached error:&error]; if (error == nil) { NSDictionary *locatorDictionary = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error]; if (error == nil) { self.urlForStockVersion1 = [self findURLForServiceNamed:@"stockQuote" version:1 inDictionary:locatorDictionary]; self.urlForStockVersion2 = [self findURLForServiceNamed:@"stockQuote" version:2 inDictionary:locatorDictionary]; self.urlForWeatherVersion1 = [self findURLForServiceNamed:@"weather" version:1 inDictionary:locatorDictionary]; self.urlForWeatherVersion2 = [self LISTING 2-7 (continued) c02.indd 22c02.indd 22 13/09/12 2:39 PM13/09/12 2:39 PM Service Locators ❘ 23 findURLForServiceNamed:@"weather" version:2 inDictionary:locatorDictionary]; } else { NSLog(@"Unable to parse service locator because of error: %@", error); // inform the user on the UI thread dispatch_async(dispatch_get_main_queue(), ^{ [[[UIAlertView alloc] initWithTitle:@"Error" message:@"Unable to parse service locator." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; }); } } else { NSLog(@"Unable to load service locator because of error: %@", error); // inform the user on the UI thread dispatch_async(dispatch_get_main_queue(), ^{ [[[UIAlertView alloc] initWithTitle:@"Error" me ssage:@"Unable to load service locator. Did you remember to update the URL to your own copy of it?" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; }); } }); } - (NSURL*)findURLForServiceNamed:(NSString*)serviceName version:(NSInteger)versionNumber inDictionary:(NSDictionary*)locatorDictionary { NSArray *services = [locatorDictionary objectForKey:@"services"]; for (NSDictionary *serviceInfo in services) { NSString *name = [serviceInfo objectForKey:@"name"]; NSInteger version = [[serviceInfo objectForKey:@"version"] intValue]; if ([name caseInsensitiveCompare:serviceName] == NSOrderedSame && version == versionNumber) { return [NSURL URLWithString:[serviceInfo objectForKey:@"url"]]; } } return nil; } c02.indd 23c02.indd 23 13/09/12 2:39 PM13/09/12 2:39 PM 24 ❘ CHAPTER 2 DESIGNING YOUR SERVICE ARCHITECTURE SUMMARY Optimally, a fl exible service architecture must be planned and implemented before the fi rst version of an application is released to achieve its maximum benefi ts. If one version goes out with hardcoded endpoints or business logic, you are effectively supporting that confi guration indefi nitely, even if your business greatly evolves from it. With the combination of a remote façade, API versioning, and a service locator, you have many options to tweak business logic and API settings for apps already in the wild. It becomes easier to support minor tweaks in production code and major new features in upcoming versions without breaking the previous application versions. The upfront development costs of the service infrastructure may seem unnecessary, but it can pay for itself many times over as the application grows and evolves. c02.indd 24c02.indd 24 13/09/12 2:39 PM13/09/12 2:39 PM PART II HTTP Requests: The Workhorse of iOS Networking CHAPTER 3: Making Requests CHAPTER 4: Generating and Digesting Payloads CHAPTER 5: Handling Errors c03.indd 25c03.indd 25 13/09/12 2:40 PM13/09/12 2:40 PM c03.indd 26c03.indd 26 13/09/12 2:40 PM13/09/12 2:40 PM Making Requests WHAT’S IN THIS CHAPTER? ➤ Understanding the structure of HTTP requests ➤ Issuing HTTP requests from iOS applications ➤ Using advanced manipulation of HTTP requests WROX.COM CODE DOWNLOADS FOR THIS CHAPTER You can fi nd the wrox.com code downloads for this chapter at www.wrox.com/WileyCDA/ WroxTitle/Professional-iOS-Network-Programming-Connecting-the-Enterprise-to- the-iPhone-and-iPad.productCd-1118362403.html on the Download Code tab. The code is in the Chapter 3 download and individually named according to the names throughout the chapter. As you may have noticed from the content of previous chapters, the preferred communication approach in iOS is HTTP. The most convenient networking APIs provided in iOS are geared toward HTTP, the HTTP APIs are the most thoroughly documented, and the high level HTTP APIs are well integrated into the run loop-based architecture of an iOS application. It is no wonder that HTTP and HTTPS are the workhorse protocols of iOS network communications. In this chapter you learn about the structure of HTTP requests and how these requests can be leveraged by your application. The chapter also provides concrete examples of three primary methods to generate HTTP requests and receive HTTP responses and recommendations on when to use or avoid each one. Finally, this chapter explores some more advanced ways to use the HTTP protocol to your advantage. 3 c03.indd 27c03.indd 27 13/09/12 2:40 PM13/09/12 2:40 PM 28 ❘ CHAPTER 3 MAKING REQUESTS INTRODUCING HTTP Sir Tim Berners-Lee produced the fi rst version of the Hypertext Transfer Protocol (HTTP) as part of the WorldWideWeb project started in 1990. The protocol was defi ned with HTML as a way to deliver information to researchers at CERN in Geneva, Switzerland, using a standard user interface and markup language. The information presented to the user could also contain links to other related information that would be accessible by activating the link in the text. Prior to this project, information was stored in a variety of formats and accessible with different tools based on the format, which made fi nding, consuming, and relating historical research to your own research diffi cult. You can read the original proposal for the WorldWideWeb project at http://www.w3.org/Proposal.html. NOTE In this chapter and the remainder of the book, the term HTTP is used to denote both unsecure HTTP and secure HTTPS requests. Where there is a difference between these two protocols, it will be noted in the text. NOTE An interesting side note in the invention of HTTP and HTML is that the fi rst World Wide Web server and browser were written on a NeXTStep computer. In 1997, Apple acquired NeXT Computer and used NeXTStep as the basis for OS X. Apple’s OS X became the foundation for iOS. There were three major innovations in Berners-Lee’s original proposal: HTML, HTTP, and the URL. HTML defi ned a way to add styling to text, HTTP defi ned a way to convey data between server and client, and the URL defi ned a way to uniquely locate a resource across a network of machines. As the use of web browsers and HTTP moved outside of the research lab into business and homes in the mid-1990s, it soon became a target for nefarious people and organizations. In response, engineers developed standards for securing HTTP traffi c. Initially there were two competing standards, HTTPS and S-HTTP. HTTPS encrypts the entire HTTP message, whereas S-HTTP encrypts only the message body, leaving the headers in clear text. Both Microsoft and Netscape decided to standardize on HTTPS, which led to the abandonment of S-HTTP. HTTP was initially designed for the communication of human readable hypertext content from a server to a client browser. The adoption of the World Wide Web caused HTTP to become the de facto standard for communicating human readable information around the Internet and into consumer’s homes. With the rise of HTTP carrying HTML came the realization that HTTP could just as easily convey machine-to-machine information as well. Because of the ubiquity of web browsers using HTML and HTTP, the use of HTTP to convey machine-readable data became the path of least resistance to move information between systems on c03.indd 28c03.indd 28 13/09/12 2:40 PM13/09/12 2:40 PM Understanding HTTP Requests and Responses ❘ 29 the Internet. If an application is on a computer connected to a network, you can almost guarantee that there is a way to communicate via HTTP to another host on the Internet. Corporate network proxies and fi rewalls can readily and securely convey HTTP requests between the secured corporate network and the Internet, performing fi ltering and security validations along the way. Although the Internet is designed to carry a multitude of different application level protocols, HTTP has become the protocol that requires the least confi guration for the end user. UNDERSTANDING HTTP REQUESTS AND RESPONSES To effectively use HTTP for client-server communication, you should understand the underpinnings of the protocol. In this section you learn the key principles and structures of HTTP as it is used in modern applications. An HTTP request follows the client-server paradigm for computer communications. Figure 3-1 illustrates the sequence of steps in a simple HTTP request. The client establishes a TCP connection to the server and then sends an HTTP request. The server subsequently responds to the request by sending a HTTP response over the same TCP connection. The client can then reuse the TCP connection for another request or close it. Early versions of the HTTP protocol allowed only one request per TCP connection. HTTP 1.1 permits the client to reuse the connection. FIGURE 3-1 Send HTTP Request Receive HTTP Response Device App HTTP Server TCP Connection Close TCP Connection c03.indd 29c03.indd 29 13/09/12 2:40 PM13/09/12 2:40 PM 30 ❘ CHAPTER 3 MAKING REQUESTS The most signifi cant difference between HTTP and HTTPS is during the connection establishment phase of the conversation. After the TCP connection is made but before HTTP requests are transmitted, an SSL session must be established between the client and the server. SSL session establishment includes various stages: the client and server negotiating over which ciphers to use, exchanging public keys, validating the negotiation, and optionally validating identity. After the SSL session is established, all the data transmitted over the TCP connection will be encrypted. URL Structure From the perspective of an iOS developer, the other important invention of the WorldWideWeb project was the URL. The URL provides a globally unique location name for any resource or content on the Internet. As a rule, a single resource may be found with multiple URLs, but a single URL will not refer to different resources. There are exceptions to this rule, such as when the hostname refers to an ambiguous host. In the URL loading system of iOS, the NSURL object is used to manage URL objects. A URL is typically composed of fi ve components, as shown in Figure 3-2. ➤ Protocol — The protocol component specifi es which application layer protocol to use to communicate to the server. If you’ve been around the web for a while, you may remember using ftp as a protocol in addition to http. The dominance of http has led to the near extinction of pre-HTTP protocol usage. Another commonly used protocol in iOS apps is the file protocol. file requests are used to retrieve resources in the local fi lesystem within the apps sandbox. If you create an NSURL object using a string without a protocol, it defaults to the file protocol. ➤ Credentials — Some HTTP servers support the delivery of user credentials in the URL to fulfi ll a BASIC authentication challenge. In Figure 3-2 the credentials component contains the username and password of the authenticating user. This format is not widely used and is considered less secure than other authentication methods. ➤ Hostname — The hostname portion of the URL specifi es the TCP hostname or IP address of the host containing the wanted resource. If the protocol of the URL is FILE, then this component and the port component must be omitted. The exception to the preceding rule about a single URL referencing a unique resource is broken when relative or local hostnames are used. For example, if you use localhost as the hostname, the URL refers to the local machine; therefore, the same URL can refer to different resources on different machines. NOTE The defi nitive specifi cation for HTTP is IETF RFC 2616. This RFC was adopted as a standard in 1999. You can fi nd this RFC at http://www.ietf.org/ rfc/rfc2616.txt. FIGURE 3-2 http ://user:password@ hostname : port /absolute-path ?query Protocol Credentials Hostname TCP Port absolute path query string c03.indd 30c03.indd 30 13/09/12 2:40 PM13/09/12 2:40 PM Understanding HTTP Requests and Responses ❘ 31 ➤ Port — The port portion of the URL specifi es the TCP port to which the client should connect. If omitted the client uses the default port for the specifi ed protocol: 80 for HTTP and 443 for HTTPS. It is best practice to use these port values for apps running on devices outside net- works you control because some network proxies and fi rewalls will block nonstandard port numbers for security or privacy reasons. ➤ Absolute-path — The absolute-path component specifi es the path to the network resource as if the HTTP server was drilling down into a directory tree. The absolute-path may include any number of path components each separated by the forward slash (/) character. An absolute-path may not contain a question mark, space, carriage-return, or line-feed characters. Many REST services use path components as a means to pass values to uniquely identify an entity stored in a database. For example, a path of /customer/456/address/0 would specify the address at index 0 for the customer with an identifi er of 456. ➤ Query — The last component of a URL is the query string. This value is separated from the absolute-path by a question mark (?). By convention multiple query parameters are each separated by an ampersand (&) character. The query string may not contain carriage return, space, or line-feed characters. Because the contents of the absolute-path and query string are restricted, URLs are usually encoded using percent encoding. RFC 3986, http://tools.ietf.org/html/rfc3986, specifi es the details of percent encoding of URLs. iOS provides a method on the NSString object to perform percent encoding of URLs. The following snippet shows how to percent encode an NSString. NSString *urlString = @"http://myhost.com?query=This is a question"; NSString *encoded = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; The resulting value of encoded is http://myhost.com?query=This%20is%20a%20question. Each of the spaces was replaced by a %20 sequence. This encoding differs from URL encoding in that it does not encode the ampersand (&) characters, thereby leaving the URL parameter separation intact. URL encoding would encode the ampersands, question marks, and other punctuation. If your query strings contain these characters, you need to implement a more thorough encoding method. Request Contents An HTTP request consists of three parts: the request line, the request headers, and the request body. The request line and request headers are lines of text each separated by carriage-return/line-feed sequence (a byte with the value 13 or 0x0D and a byte with the value 10 or 0x0A). This use of textual values in the HTTP request makes them easy to construct, parse, and debug. An empty line, consisting of just a carriage-return/line-feed sequence or just a line-feed, separates the request headers from the request body. The following code snippet contains an example HTTP request from a search request. GET /search?source=ig&hl=en&rlz=&q=ios&btnG=Google+Search HTTP/1.1 Host: www.google.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:11.0)… c03.indd 31c03.indd 31 13/09/12 2:40 PM13/09/12 2:40 PM 32 ❘ CHAPTER 3 MAKING REQUESTS Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en,en-us;q=0.7,en-ca;q=0.3 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.google.com/ig?hl=en&source=webhp Cookie: PREF=ID=fdf9979… The request line is the fi rst line of the data sent to the server. The request line contains three key pieces of information: the HTTP request method, the request URI, and the HTTP version. The request method is a single word indicating the action being requested by the client. Because it is case-sensitive, the standard methods listed in Table 1-1 are all uppercase values. In the preceding code snippet the request method is a GET method. TABLE 1-1: Common Request Methods and Their Uses METHOD STANDARD USES GET Retrieves a piece of content, or entity in HTTP terminology, from the server. GET requests usually don’t contain a request body, but it is allowed. Some network caching appliances will cache only GET responses. GET requests usually do not cause data changes on the server. POST Updates an entity with data provided by the client. A POST request usually has information in the body of the request that is used by the application server. POST requests are considered to be non-idempotent, meaning that if more than one request is processed, the result is diff erent than if only one request is processed. HEAD Retrieves metadata about a response without retrieving the entire contents of the response. This method is usually used to check a server for recent content changes without having to retrieve the full content. PUT Adds an entity with data provided by the client. A PUT request usually has information in the body of the request that is used by the application server to create the new entity. Usually, PUT requests are considered to be idem- potent, meaning that the request can be repeatedly applied with the same results. DELETE Removes an entity based on contents of the URI or request body provided by the client. DELETE requests are most frequently used in REST service interfaces. The second fi eld in a request line is the URI. The URI uniquely identifi es the target of the request. If the request uses the GET method, the URI unambiguously specifi es the content to retrieve on the target host. The URI may also contain query parameters, which must not contain a space or carriage return character. In the prior code snippet the URI contains several query parameters, each c03.indd 32c03.indd 32 13/09/12 2:40 PM13/09/12 2:40 PM Understanding HTTP Requests and Responses ❘ 33 separated by an ampersand (&) character. Notice that the URI does not contain the protocol, host, or port that a user usually provides in the address fi eld of a browser. The client uses the protocol portion of the URL to determine how to connect to the server. The hostname and port specifi ed by the client is provided in the Host header of the request. The last fi eld of the request line specifi es the version of the HTTP protocol being used. In the previous HTTP request code example that version value is 1.1, which means that the server should expect the client to apply headers and rules specifi c to version 1.1 of the HTTP protocol. The lines immediately following the request line are the request headers, which provide additional metadata to the server. This metadata may describe the client, further describe the request, or request a certain type of response from the server. There may be one or more headers provided in each request. The Host header is the only required header in an HTTP 1.1 request. It provides the original hostname specifi ed by the client and may include the port number provided in the URL of the original request. An HTTP server may serve content for multiple hostnames. The Host header helps the HTTP server know the host to which the original request was made. NOTE The HTTP specifi cation permits intermediaries between the HTTP client and server to add, remove, reorder, or modify HTTP headers. Therefore, a request from your app may arrive at the server with new headers, modifi ed headers, or headers removed. Even though it uses the stateful TCP transport layer, HTTP is defi ned as a stateless protocol. This means that the HTTP server does not retain any information about a request to use in future requests. Cookies were developed as a way to allow some simple state information to be stored on the client and communicated to the server on subsequent requests. Following the HTTP headers there is an optional request body. The request body is an arbitrary sequence of bytes separated from the headers by a single blank line. The request body must conform to the predetermined data encoding between the client and the server. For web browsers this is usually form-encoded data, but for mobile applications this encoding is usually XML or JSON data. Chapter 4, “Generating and Digesting Payloads,” examines more closely request body and response body encoding. In iOS the NSURLRequest object and its subclass NSMutableURLRequest provide the methods and attributes necessary to build almost any HTTP request. These objects will be discussed in the upcoming “High-Level iOS HTTP APIs” section. Response Contents After the HTTP server and any application servers supporting it fi nish processing the request, an HTTP response is returned to the client over the same TCP socket. An HTTP response is structured similarly to an HTTP request with the fi rst line being the status line, followed by headers, and a response body. The following code shows a sample HTTP response. c03.indd 33c03.indd 33 13/09/12 2:40 PM13/09/12 2:40 PM 34 ❘ CHAPTER 3 MAKING REQUESTS HTTP/1.1 200 OK Date: Tue, 27 Mar 2012 12:59:18 GMT Expires: -1 Cache-Control: private, max-age=0 Content-Type: text/html; charset=UTF-8 Content-Encoding: gzip Transfer-Encoding: chunked Server: gws ios - Google Search