{"id":234,"date":"2015-03-02T20:14:44","date_gmt":"2015-03-02T20:14:44","guid":{"rendered":"http:\/\/arlduc.org\/senseandscale\/?p=234"},"modified":"2015-09-24T16:56:40","modified_gmt":"2015-09-24T16:56:40","slug":"crash-course-in-ios","status":"publish","type":"post","link":"https:\/\/arlduc.org\/senseandscale\/?p=234","title":{"rendered":"QSAT Crash Course: iOS, Swift, CoreLocation (via Arduino+Bluefruit+sensor systems)"},"content":{"rendered":"<p>While it&#8217;s not generally feasible to learn how to build an iOS app from scratch\u00a0in one three-hour session, the aim of this crash course is to help you to take the\u00a0existing Bluefruit LE app and modify it\u00a0to collect data from any Arduino-compatible sensor.<\/p>\n<h1><span style=\"text-decoration: underline;\">How This Tutorial\u00a0Works<\/span><\/h1>\n<p>For each feature that you add to the app, the subtasks\u00a0are written out in English (pseudocode), but there are no code snippets in this tutorial. After you try it, let me know if code snippets would have helped you learn&#8211;I might add\u00a0them later. If you find that you&#8217;re stuck and need some help, I pasted all the snippets into a file, which is linked at the end of the tutorial.<\/p>\n<h1><span style=\"text-decoration: underline;\">Prerequisites<\/span><\/h1>\n<p>Before the crash course, be sure that you have<\/p>\n<ol>\n<li>Acquired an analog sensor, Arduino Uno, and <a href=\"http:\/\/www.adafruit.com\/product\/1697\" target=\"_blank\">Bluefruit LE<\/a> breakout module. You must also have an iOS device running iOS 8 or higher, and a Mac computer running Xcode 6 or higher.<\/li>\n<li>Connected the\u00a0analog sensor to your Arduino Uno&#8217;s A5 pin and checked the data in the Arduino serial monitor.<\/li>\n<li>Connected the Bluefruit LE to your Uno and completed\u00a0the <a href=\"https:\/\/learn.adafruit.com\/getting-started-with-the-nrf8001-bluefruit-le-breakout\/introduction\" target=\"_blank\">Bluefruit LE tutorial<\/a>.<\/li>\n<li>Downloaded the <a href=\"https:\/\/itunes.apple.com\/WebObjects\/MZStore.woa\/wa\/viewSoftware?id=830125974&amp;mt=8\" target=\"_blank\">Bluefruit LE app from the App Store<\/a> and checked that data is being transmitted from your sensor system (sensor+Uno+Bluefruit) and displayed in the Bluefruit LE app.<\/li>\n<\/ol>\n<h1><span style=\"text-decoration: underline;\">Getting Started<\/span><\/h1>\n<p><a href=\"https:\/\/github.com\/adafruit\/Bluefruit_LE_Connect\" target=\"_blank\">Download the\u00a0source code for the Bluefruit LE app here<\/a>. We will modify this code in three ways:<\/p>\n<ol>\n<li>Add location and time data to each sensor value, creating a new &#8220;SensorRecord&#8221; class.<\/li>\n<li>Write SensorRecords to an array.<\/li>\n<li>Give the user the option to email the array of SensorRecords as a list of CSVs (comma-separated values), which can then be imported into spreadsheet, GIS, and other environments for visualization and analysis.<\/li>\n<\/ol>\n<p>After you complete these modifications, your app should display a succession of new elements\u00a0like those in the screenshots below. When interacting with the app, you are given the option to email your sensors values when you &#8220;Disconnect&#8221; from your sensor system.<\/p>\n<p><a href=\"http:\/\/arlduc.org\/senseandscale\/wp-content\/uploads\/2015\/03\/IMG_2362.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-thumbnail wp-image-242\" src=\"http:\/\/arlduc.org\/senseandscale\/wp-content\/uploads\/2015\/03\/IMG_2362-150x150.png\" alt=\"IMG_2362\" width=\"150\" height=\"150\" \/><\/a> <a href=\"http:\/\/arlduc.org\/senseandscale\/wp-content\/uploads\/2015\/03\/IMG_2365.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-thumbnail wp-image-243\" src=\"http:\/\/arlduc.org\/senseandscale\/wp-content\/uploads\/2015\/03\/IMG_2365-150x150.png\" alt=\"IMG_2365\" width=\"150\" height=\"150\" \/><\/a> <a href=\"http:\/\/arlduc.org\/senseandscale\/wp-content\/uploads\/2015\/03\/IMG_2366.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-thumbnail wp-image-244\" src=\"http:\/\/arlduc.org\/senseandscale\/wp-content\/uploads\/2015\/03\/IMG_2366-150x150.png\" alt=\"IMG_2366\" width=\"150\" height=\"150\" \/><\/a> <a href=\"http:\/\/arlduc.org\/senseandscale\/wp-content\/uploads\/2015\/03\/IMG_2367.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-thumbnail wp-image-245\" src=\"http:\/\/arlduc.org\/senseandscale\/wp-content\/uploads\/2015\/03\/IMG_2367-150x150.png\" alt=\"IMG_2367\" width=\"150\" height=\"150\" \/><\/a> <a href=\"http:\/\/arlduc.org\/senseandscale\/wp-content\/uploads\/2015\/03\/IMG_2368.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-thumbnail wp-image-246\" src=\"http:\/\/arlduc.org\/senseandscale\/wp-content\/uploads\/2015\/03\/IMG_2368-150x150.png\" alt=\"IMG_2368\" width=\"150\" height=\"150\" \/><\/a> <a href=\"http:\/\/arlduc.org\/senseandscale\/wp-content\/uploads\/2015\/03\/IMG_2370.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-thumbnail wp-image-247\" src=\"http:\/\/arlduc.org\/senseandscale\/wp-content\/uploads\/2015\/03\/IMG_2370-150x150.png\" alt=\"IMG_2370\" width=\"150\" height=\"150\" \/><\/a><\/p>\n<p>I found the\u00a0location element to be\u00a0the most complicated since it involves issues of user privacy and permissions, so we will save that part for last.<\/p>\n<h2><span style=\"text-decoration: underline;\">Step 1: Getting Acclimated in Swift<\/span><\/h2>\n<p>If you have never programmed for iOS in Objective-C, take\u00a0<a href=\"https:\/\/developer.apple.com\/library\/ios\/referencelibrary\/GettingStarted\/RoadMapiOS\/index.html#\/\/apple_ref\/doc\/uid\/TP40011343-CH2-SW1\" target=\"_blank\">this Apple tutorial<\/a>\u00a0to get acclimated to the iOS development environment with Objective-C. Now that Apple has introduced the Swift language to be simpler and less error prone than Objective-C, we&#8217;re starting to see more codebases written in Swift, including the Bluefruit LE app.<\/p>\n<p>Swift, which has been called &#8220;<a href=\"http:\/\/en.wikipedia.org\/wiki\/Swift_%28programming_language%29\" target=\"_blank\">Objective-C without C<\/a>,&#8221; is meant to employ concepts and syntax closer to more modern languages like javascript or Ruby. It took me a day or so to get used to Swift syntax, and a few more days to understand the concepts of forced unwrapping \/ optional chaining (the reason you see so many <strong>&#8220;!&#8221;<\/strong> and <strong>&#8220;?&#8221;<\/strong> marks in Swift code), which is why I recommend the particular links below.<\/p>\n<ul>\n<li>Apple:\u00a0<a href=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/Swift\/Conceptual\/BuildingCocoaApps\/MixandMatch.html#\/\/apple_ref\/doc\/uid\/TP40014216-CH10-XID_77\" target=\"_blank\">Swift and Objective-C in the same project<br \/>\n<\/a><\/li>\n<li>Apple:\u00a0<a href=\"https:\/\/developer.apple.com\/library\/prerelease\/ios\/documentation\/Swift\/Conceptual\/Swift_Programming_Language\/\" target=\"_blank\">The Swift Programming Language<\/a>. Read at least these sections in the Language Guide:\n<ul>\n<li>Start at &#8220;<a href=\"https:\/\/developer.apple.com\/library\/prerelease\/ios\/documentation\/Swift\/Conceptual\/Swift_Programming_Language\/TheBasics.html#\/\/apple_ref\/doc\/uid\/TP40014097-CH5-ID309\" target=\"_blank\">The Basics<\/a>&#8221; and read to &#8220;<a href=\"https:\/\/developer.apple.com\/library\/prerelease\/ios\/documentation\/Swift\/Conceptual\/Swift_Programming_Language\/Methods.html#\/\/apple_ref\/doc\/uid\/TP40014097-CH15-ID234\" target=\"_blank\">Methods<\/a>&#8220;<\/li>\n<li>Also read\u00a0&#8220;<a href=\"https:\/\/developer.apple.com\/library\/prerelease\/ios\/documentation\/Swift\/Conceptual\/Swift_Programming_Language\/OptionalChaining.html#\/\/apple_ref\/doc\/uid\/TP40014097-CH21-ID245\" target=\"_blank\">Optional Chaining<\/a>.&#8221; <strong>Understanding optional chaining and forced unwrapping is important for debugging runtime errors!<\/strong><\/li>\n<\/ul>\n<\/li>\n<li>NSHipster: <a href=\"http:\/\/nshipster.com\/swift-documentation\/\" target=\"_blank\">Swift Documentation<\/a> (see for use of MARK to replace PRAGMA for section dividers. This is helpful in navigating quickly through an existing codebase.)<\/li>\n<\/ul>\n<h2><span style=\"text-decoration: underline;\">Step 2: Writing Sensor Values to an Array<\/span><\/h2>\n<p>In the original Bluefruit code, the pin I\/O values\u00a0displayed without being stored, so our first coding task is to store\u00a0those values in\u00a0an array. The\u00a0<a href=\"http:\/\/makeapppie.com\/2014\/08\/13\/swift-tutorial-how-to-use-an-array-in-swift\/\" target=\"_blank\">Swift Tutorial: How to use an Array in Swift<\/a>\u00a0may be helpful for this task. We will first focus on the existing class <strong>PinIOViewController<\/strong>, which manages the numeric display for each I\/O pin. In the class&#8217;s file\u00a0<strong>PinIOViewController.swift<\/strong>, see\u00a0if you can complete these subtasks to write the data to an array.<\/p>\n<ol>\n<li>In the variable declaration section, declare an array of type <strong>Int<\/strong> called <strong>sensorDataVal<\/strong><\/li>\n<li>In the method <strong>processInputData<\/strong>, locate the lines where new analog values\u00a0are processed. Hint: look for the comment &#8220;\/\/Analog Reporting (per pin)&#8221;<\/li>\n<li>Write new analog values to sensorDataVal and println them to the output console.<\/li>\n<li>Try running the app on your device.<\/li>\n<\/ol>\n<p>You will need to make sensorDataVal\u00a0available to the main viewcontroller, <strong>BLEMainViewController<\/strong>, so the values\u00a0can be passed into an email.\u00a0In the class&#8217;s file\u00a0<strong>BLEMainViewController<\/strong><strong>.swift<\/strong>, see\u00a0if you can complete these subtasks to write the data to an array.<\/p>\n<ol>\n<li>In the variable declaration section, declare a <em>private<\/em> array of type <strong>Int<\/strong> called\u00a0<strong>previousSensorDataVal\u00a0<\/strong><\/li>\n<li>In the method navigationController, locate the\u00a0<strong>else\u00a0<\/strong>clause that indicates a return from the PinIOViewController. Hint: look for the name\u00a0<strong>ConnectionMode.PinIO<\/strong><\/li>\n<li>In this clause, load\u00a0<strong>pinIoViewController&#8217;s<\/strong> data into <strong>previousSensorDataVal<\/strong><\/li>\n<li>Try running the app on your device.<\/li>\n<\/ol>\n<h2><span style=\"text-decoration: underline;\">Step 3: Emailing Sensor Values<\/span><\/h2>\n<p>In BLEMainViewController, we\u00a0will set up an alert to ask the user if she wants to email the sensor data, as well as relevant email functionality. To learn about alerts in iOS, <a href=\"http:\/\/nshipster.com\/uialertcontroller\/\" target=\"_blank\">NSHipster&#8217;s explanation of UIAlertController<\/a>\u00a0may be helpful. To learn about sending in-app e-mails, check out\u00a0<a href=\"http:\/\/www.andrewcbancroft.com\/2014\/08\/25\/send-email-in-app-using-mfmailcomposeviewcontroller-with-swift\/\" target=\"_blank\">Send Email In-App \u2013 Using MFMailComposeViewController with Swift<\/a>. Now see if you can complete these subtasks in\u00a0<strong>BLEMainViewController.swift<\/strong>:<\/p>\n<ol>\n<li>In the same\u00a0<strong>else\u00a0<\/strong>clause that indicates a return from PinIOViewController, add a <strong>UIAlertController<\/strong> to ask the user whether to send an email of sensor values. Add a\u00a0<strong>UIAlertAction<\/strong>\u00a0for if the user answers YES, and a separate\u00a0<strong>UIAlertAction\u00a0<\/strong>for if the user answers NO.<\/li>\n<li>Now modify the YES\u00a0<strong>UIAlertAction\u00a0<\/strong>to send an email. You will need to add 3 additional methods, based on the Send Email In-App link above:\n<ul>\n<li><strong>configuredMailComposeViewController <\/strong>(where you will write the values from\u00a0<strong>previousSensorDataVal<\/strong> out as a String into the email)<\/li>\n<li><strong>showSendMailErrorAlert<\/strong><\/li>\n<li><strong>mailComposeController<\/strong><\/li>\n<\/ul>\n<\/li>\n<li>Make\u00a0<strong>BLEMainViewController\u00a0<\/strong>a subclass of\u00a0<strong>MFMailComposeViewControllerDelegate<\/strong>.<\/li>\n<li>Try running the app on your device.<\/li>\n<\/ol>\n<h2><span style=\"text-decoration: underline;\">Step 4: Adding Location and Time Data to the Mix<\/span><\/h2>\n<p>If you made it this far, congratulations! You are almost finished. If not, don&#8217;t despair, all the code is written out at the end!<\/p>\n<p>Our final step is to add location and timestamp data to each sensor value. This means that we will now record a group of values for each sensor reading, not just one, so it makes sense to convert our <strong>sensorDataVal<\/strong> array from an array of\u00a0<strong>Int<\/strong>\u00a0to an array of a class we create:\u00a0<strong>SensorRecord. <\/strong><\/p>\n<p>iOS offers\u00a0a <a href=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/CoreLocation\/Reference\/CoreLocation_Framework\/\" target=\"_blank\">Core Location Framework<\/a> to query\u00a0location data based on\u00a0the device&#8217;s built-in GPS, bluetooth, and wi-fi modules. Of this framework, we\u00a0will include\u00a0the\u00a0<a href=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/CoreLocation\/Reference\/CLLocation_Class\/\" target=\"_blank\">CLLocation<\/a>\u00a0library\u00a0in our previous Swift files, <strong>BLEMainViewController.swift\u00a0<\/strong>and\u00a0<strong>PinIOViewController.swift<\/strong>, as well as a new Swift file that we create called\u00a0<strong>SensorRecord.swift<\/strong>.<\/p>\n<p>Before you get started in this section, take a look at the Apple Sample Code\u00a0<a href=\"https:\/\/developer.apple.com\/library\/ios\/samplecode\/LocateMe\/Introduction\/Intro.html\" target=\"_blank\">Locate Me<\/a>\u00a0to see how the CLLocation library works. A new, improved privacy feature\u00a0in iOS 8 is that all apps are programmatically required to request authorization from the user to employ Core Location services. You can read more about it in\u00a0NSHipster&#8217;s post on\u00a0<a href=\"http:\/\/nshipster.com\/core-location-in-ios-8\/\" target=\"_blank\">Core Location in iOS 8<\/a>. Also take a look at this\u00a0StackOverflow discussion on\u00a0<a href=\"http:\/\/stackoverflow.com\/questions\/26188370\/getting-a-very-simple-swift-corelocation-example-to-work\" target=\"_blank\">Getting a very simple Swift CoreLocation example to work<\/a>;\u00a0it helps in culling\u00a0relevant\u00a0CoreLocation code into a few lines. After reviewing these resources, try these subtasks:<\/p>\n<ol>\n<li>Link CoreLocation.framework to your app target (see instructions <a href=\"https:\/\/developer.apple.com\/library\/mac\/recipes\/xcode_help-project_editor\/Articles\/AddingaLibrarytoaTarget.html\" target=\"_blank\">here<\/a>)<\/li>\n<li>Add the line\u00a0<strong>&#8220;import CoreLocation&#8221; <\/strong>to the head of your<strong>\u00a0<strong>BLEMainViewController.swift\u00a0<\/strong><\/strong>and<strong>\u00a0<strong>PinIOViewController.swift\u00a0<\/strong><\/strong>files.<\/li>\n<li>Create a new\u00a0<strong>SensorRecord.swift\u00a0<\/strong>file with two variables. Force unwrapping by adding a &#8220;!&#8221; at the end of each variable declaration:\n<ul>\n<li>an\u00a0<strong>Int<\/strong> called <strong>sensorMeasurement<\/strong><\/li>\n<li>a <strong>CLLocation<\/strong> called <strong>locationInfo<\/strong><\/li>\n<\/ul>\n<\/li>\n<li>Make <strong>PinIOViewController<\/strong> a subclass of <strong>CLLocationManagerDelegate<\/strong><\/li>\n<li>Add two new variables to <strong>PinIOViewController<\/strong>:\n<ul>\n<li>A private <strong>CLLocationManager\u00a0<\/strong>called\u00a0<strong>locManager<\/strong>. This variable will manage GPS connection\u00a0and user authorization.<\/li>\n<li>A private\u00a0<strong>CLLocation<\/strong> called currentLocation. Enable forced unwrapping on this variable.<\/li>\n<\/ul>\n<\/li>\n<li>In\u00a0<strong>PinIOViewController<\/strong>, set up the locManager in the init method.\u00a0You will need to\n<ul>\n<li>set locManager&#8217;s delegate to self<\/li>\n<li>set locManager&#8217;s desiredAccuracy to\u00a0kCLLocationAccuracyBest<\/li>\n<li>request permission if device is running iOS8 or higher<\/li>\n<li>startUpdatingLocations for locManager<\/li>\n<\/ul>\n<\/li>\n<li>In\u00a0<strong>PinIOViewController<\/strong>, add a new method called locationManager to poll for new GPS data. You can optionally add an error-handling method.<\/li>\n<li>In\u00a0<strong>PinIOViewController<\/strong>, modify <strong>sensorDataVal<\/strong> to be\u00a0an array of <strong>SensorRecords<\/strong> instead of an an array of <strong>Ints<\/strong>.<\/li>\n<li>In <strong>BLEMainViewController<\/strong>,\u00a0modify <strong>previousSensorDataVal<\/strong> to be\u00a0an array of <strong>SensorRecords<\/strong> instead of an an array of <strong>Ints<\/strong>.<\/li>\n<li>Try running the app on your device. If it works, you can now deploy the app to email you sensor data!<\/li>\n<\/ol>\n<h2><span style=\"text-decoration: underline;\">Step 5: The Working Code<\/span><\/h2>\n<p>The <a href=\"https:\/\/drive.google.com\/file\/d\/0B1KM70jlEfvpWXpUT0ZKdWpHc28\/view?usp=sharing\" target=\"_blank\">working code snippets are in this file<\/a>, but you will still need to figure out where in the\u00a0pre-existing Bluefruit LE code you should paste these snippets. We will take a look at this file together in class. If\u00a0you need to use this &#8220;cheat sheet&#8221; beyond class, use the code&#8217;s comments and blocks to help!<\/p>\n<h2><span style=\"text-decoration: underline;\">Secret Step\u00a0If You Really Need It<\/span><\/h2>\n<p>Download the <a href=\"https:\/\/github.com\/arlduc\/Bluefruit_LE_Connect\" target=\"_blank\">final\u00a0codebase<\/a>\u00a0from Github!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>While it&#8217;s not generally feasible to learn how to build an iOS app from scratch\u00a0in one three-hour session, the aim of this crash course is to help you to take the\u00a0existing Bluefruit LE app and modify it\u00a0to collect data from any Arduino-compatible sensor. How This Tutorial\u00a0Works For each feature that you add to the app, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,4,5,8],"tags":[],"class_list":["post-234","post","type-post","status-publish","format-standard","hentry","category-mit-iap","category-nyu","category-quantified-self","category-tutorials"],"_links":{"self":[{"href":"https:\/\/arlduc.org\/senseandscale\/index.php?rest_route=\/wp\/v2\/posts\/234","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/arlduc.org\/senseandscale\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/arlduc.org\/senseandscale\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/arlduc.org\/senseandscale\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/arlduc.org\/senseandscale\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=234"}],"version-history":[{"count":34,"href":"https:\/\/arlduc.org\/senseandscale\/index.php?rest_route=\/wp\/v2\/posts\/234\/revisions"}],"predecessor-version":[{"id":566,"href":"https:\/\/arlduc.org\/senseandscale\/index.php?rest_route=\/wp\/v2\/posts\/234\/revisions\/566"}],"wp:attachment":[{"href":"https:\/\/arlduc.org\/senseandscale\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=234"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/arlduc.org\/senseandscale\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=234"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/arlduc.org\/senseandscale\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=234"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}