{"id":934,"date":"2014-11-22T15:22:15","date_gmt":"2014-11-22T21:22:15","guid":{"rendered":"http:\/\/dev.iachieved.it\/iachievedit\/?p=934"},"modified":"2014-11-22T15:22:15","modified_gmt":"2014-11-22T21:22:15","slug":"using-aeris-sdk-for-weather-advisories","status":"publish","type":"post","link":"https:\/\/dev.iachieved.it\/iachievedit\/using-aeris-sdk-for-weather-advisories\/","title":{"rendered":"Using Aeris SDK for Weather Advisories"},"content":{"rendered":"<p><i>Editor&#8217;s Note:  This is part three in a three part series.  The goal in this series is to develop a fully functional (and useful) iOS application that is capable of pushing weather alerts based on your location to your iOS device.  The series is broken down as follows:<\/p>\n<ul>\n<li>Part One &#8211; Developing a Push Notification-capable application with Parse and Swift\n<li>Part Two &#8211; Using CoreLocation with Swift\n<li><b>Part Three &#8211; Integrating in a Weather Service API<\/b>\n<\/ul>\n<p><\/i><\/p>\n<p>In this third part of our three part series we&#8217;ll be completing our weather alerts application started in <a href=\"http:\/\/dev.iachieved.it\/iachievedit\/?p=823\">Part One<\/a>.  A warning!  The code examples that follow in this post build upon the code covered in both <a href=\"http:\/\/dev.iachieved.it\/iachievedit\/?p=823\">Part 1<\/a> and <a href=\"http:\/\/dev.iachieved.it\/iachievedit\/?p=894\">Part 2<\/a>.<\/p>\n<h2>HAMweather<\/h2>\n<p>We&#8217;re going to make use of the <a href=\"http:\/\/www.hamweather.com\/support\/documentation\/\">HAMweather<\/a> service for our weather data.  There are a variety of weather services that provide rich APIs for obtaining all manner of weather-related data.  Here&#8217;s just a few of them:<\/p>\n<ul>\n<li><a href=\"https:\/\/developer.forecast.io\">Forecast.io<\/a>\n<li><a href=\"http:\/\/www.wunderground.com\/weather\/api\/\">Wunderground<\/a>\n<li><a href=\"http:\/\/openweathermap.org\/api\">OpenWeatherMap<\/a>\n<\/ul>\n<p>We chose HAMweather over the others solely on the fact that it provided weather advisory access in its free offering.  As a bonus it comes with a nice iOS SDK framework for dealing with its weather API named Aeris.  <\/p>\n<h2>Signing Up for HAMweather<\/h2>\n<p>To get started with HAMweather and Aeris, proceed on over to the <a href=\"http:\/\/www.hamweather.com\/account\/signup\/\">signup page<\/a> and select <b>Aeris API &#8211; Developer Free<\/b> then scroll down and enter the required user information.  Of particular interest will be selection of your domain name:  if you plan on using the Aeris SDK on the server-side choose the domain under which your servers are registered.  In our case, we chose <code>iachieved.it<\/code>.<\/p>\n<p>Click <b>Next<\/b> to agree to the user agreement and then <b>Login<\/b> to login with your newly created username and password.  Once you&#8217;ve logged in you&#8217;re going to want to proceed directly to managing your subscriptions by clicking on the <a href=\"http:\/\/www.hamweather.com\/account\/member\"><b>Account<\/b> tab.<\/p>\n<p><a href=\"http:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/tut_aeris_your_subscriptions.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/tut_aeris_your_subscriptions.png\" alt=\"tut_aeris_your_subscriptions\" width=\"676\" height=\"331\" class=\"alignnone size-full wp-image-948\" \/><\/a><\/p>\n<p>Click on <b>Aeris API &#8211; Application\/Website Registration<\/b> to register the application and generate a consumer ID and secret.  Pay particular attention to your <b>Application Domain\/Identifier<\/b> field, this needs to match your iOS application <i>bundle identifier<\/i>, which uses reverse DNS notation.  iAchieved.it&#8217;s bundle identifier is <code>it.iachieved.weatheralerts<\/code>, but yours will be based upon your reverse DNS.<\/p>\n<p><a href=\"http:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/tut_aeris_api_application.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/tut_aeris_api_application.png\" alt=\"tut_aeris_api_application\" width=\"600\" height=\"281\" class=\"alignnone size-full wp-image-949\" \/><\/a><\/p>\n<p>Click the <b>REGISTER<\/b> button at the bottom of the page to register the application and get your application keys!<\/p>\n<p><a href=\"http:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/tut_api_registration_success.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/tut_api_registration_success.png\" alt=\"tut_api_registration_success\" width=\"951\" height=\"240\" class=\"alignnone size-full wp-image-950\" \/><\/a><\/p>\n<p>Now we need to add Aeris API keys to our application.  We&#8217;re using our <code>ApiKeys.plist<\/code> file to maintain all of our API keys, and have referred to the Aeris consumer ID and secret as <code>AERIS_CONSUMER_ID<\/code> and <code>AERIS_CONSUMER_SECRET<\/code>.<\/p>\n<p><a href=\"http:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/tut_api_keys.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/tut_api_keys.png\" alt=\"tut_api_keys\" width=\"651\" height=\"124\" class=\"alignnone size-full wp-image-940\" \/><\/a><\/p>\n<p>If you have a confused look on your face as to why we added these keys to a property list file, go back to <a href=\"http:\/\/dev.iachieved.it\/iachievedit\/?p=823 \">Part One<\/a> and our <a href=\"http:\/\/dev.iachieved.it\/iachievedit\/?p=762 \">tutorial<\/a> on using property lists for API key management.<\/p>\n<h2>Obtaining the iOS SDK<\/h2>\n<p>We&#8217;ll be using the new Aeris 2.0 SDK for iOS, which can be obtained from Github.  Download the <a href=\"https:\/\/github.com\/hamweather\/Aeris-iOS-Library\/archive\/v2.0-beta.1.zip\">SDK 2.0 Beta 1<\/a> and unzip to a folder.  <\/p>\n<p><a href=\"http:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/tut_aeris_frameworks.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/tut_aeris_frameworks.png\" alt=\"tut_aeris_frameworks\" width=\"240\" height=\"200\" class=\"alignnone size-full wp-image-951\" \/><\/a><\/p>\n<p>Add the <code>Aeris.Framework<\/code> to your project by dragging and dropping it into your <code>weatheralerts<\/code> project navigator.  Ensure that the <b>Copy items if needed<\/b> and <b>Create groups<\/b> are selected, and that your <code>weatheralerts<\/code> target is checked.  For our purposes we only need <code>Aeris.Framework<\/code>, but if we wanted to begin leveraging other features of Aeris we would add some of the other frameworks.<\/p>\n<p>Aeris also requires using the link flag <code><a href=\"http:\/\/stackoverflow.com\/questions\/6629979\/what-does-the-objc-linker-flag-do\">-ObjC<\/a><\/code>.  To set the flag go to your <i>project&#8217;s<\/i> <b>Build Settings<\/b> and type <b>Other Linker<\/b> in the search box.  You will see <b>Other Linker Flags<\/b> in the <b>Linking<\/b> section.  Add <code>-ObjC<\/code>:<\/p>\n<p><a href=\"http:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/tut_objc_linker.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/tut_objc_linker.png\" alt=\"tut_objc_linker\" width=\"842\" height=\"194\" class=\"alignnone size-full wp-image-941\" \/><\/a><\/p>\n<h2>Adding AFNetworking<\/h2>\n<p>Aeris makes uses of the popular <a href=\"https:\/\/github.com\/AFNetworking\/AFNetworking\">AFNetworking<\/a> networking library for iOS, so we will need to add it to our application first.  We&#8217;re going to grab the 2.5.0 version, so go to <a href=\"https:\/\/github.com\/AFNetworking\/AFNetworking\/tree\/2.5.0\">Github<\/a> and click on the <b>Download Zip<\/b> button.  Note:  We could have used <a href=\"http:\/\/cocoapods.org\">Cocoapods<\/a> to manage the installation of AFNetworking, but there&#8217;s additional setup required to get Cocoapods going, and quite frankly, I don&#8217;t like the way it takes over my Xcode project organization.<\/p>\n<p>Drag and drop both the <code>AFNetworking<\/code> <i>and<\/i> <code>UIKit+AFNetworking<\/code> (Aeris makes use of <code>AFNetworkActivityIndicatorManager<\/code> class) folders into your project, again ensuring that <b>Copy items if needed<\/b> and <b>Create groups<\/b> are selected and that the files are added to your target.  <\/p>\n<h2>Using Aeris<\/h2>\n<p>Now that we have all of the prerequisites out of the way we can get down to business with actually using Aeris.  The first step in accessing the Aeris SDK routines in a Swift-based project will be to import its header files in our application&#8217;s bridging header.  Add the following to your bridging header (which should be named <code>bridingHeader.h<\/code>):<\/p>\n<p>[objc]<br \/>\n#import &lt;Aeris\/Aeris.h&gt;<br \/>\n[\/objc]<\/p>\n<p>The complete <code>bridgingHeader.h<\/code> file should look something like this now:<\/p>\n<p>[objc]<br \/>\n#ifndef weatheralerts_bridgingHeader_h<br \/>\n#define weatheralerts_bridgingHeader_h<\/p>\n<p>#import &lt;Parse\/Parse.h&gt;<br \/>\n#import &lt;Aeris\/Aeris.h&gt;<\/p>\n<p>#endif<br \/>\n[\/objc]<\/p>\n<p>We&#8217;ll now turn to the <code>WeatherServiceController<\/code> class created in Part 2 of our tutorial.  Find the <code>init()<\/code> routine and ensure it looks like the following:<\/p>\n<p>[objc]<br \/>\noverride init() {<br \/>\n    super.init()<\/p>\n<p>    let aerisConsumerId = valueForAPIKey(keyname: &quot;AERIS_CONSUMER_ID&quot;)<br \/>\n    let aerisConsumerSecret = valueForAPIKey(keyname: &quot;AERIS_CONSUMER_SECRET&quot;)<\/p>\n<p>    AerisEngine.engineWithKey(aerisConsumerId, secret: aerisConsumerSecret)<\/p>\n<p>    NSNotificationCenter.defaultCenter().addObserver(self,<br \/>\n      selector: &quot;locationAvailable:&quot;,<br \/>\n      name: &quot;LOCATION_AVAILABLE&quot;,<br \/>\n      object: nil)<br \/>\n}<br \/>\n[\/objc]<\/p>\n<p><code>AerisEngine.engineWithKey()<\/code> initializes our Aeris framework with the consumer ID and secret that we received when registering our application.<\/p>\n<p>The Aeris SDK employs a notion of <i>loaders<\/i> that are used to obtain information from the HAMweather service.  To obtain a list of advisories in our current location we first have to obtain an Aeris <i>place<\/i> and then use an <i>advisory loader<\/i> to retrieve the advisories (if any) for our place.  <\/p>\n<p>To create a place, or, <code>AWFPlace<\/code>, we provide city, state, and country information like so:<\/p>\n<p>[objc]<br \/>\nlet place = AWFPlace(city: city, state: state, country: country)<br \/>\n[\/objc]<\/p>\n<p>We can at this point load the advisories for our place using an <code>AWFAdvisoriesLoader<\/code>.<\/p>\n<p>[objc]<br \/>\n  let advisoryLoader = AWFAdvisoriesLoader()<br \/>\n  advisoryLoader.getAdvisoriesForPlace(place, options: nil) { (advisories, e) -&gt; Void in<br \/>\n  }<br \/>\n[\/objc]<\/p>\n<p>The <code>getAdvisoriesForPlace<\/code> function takes our place and returns a list (array) of advisories currently issued for it.  Let&#8217;s put this all together and place in our <code>WeatherServiceController<\/code>&#8216;s <code>locationAvailable<\/code> function:<\/p>\n<p>[objc]<br \/>\n  func locationAvailable(notification:NSNotification) -&gt; Void {<br \/>\n    let userInfo = notification.userInfo as Dictionary&lt;String,String&gt;<\/p>\n<p>    println(&quot;WeatherService:  Location available \\(userInfo)&quot;)<\/p>\n<p>    let city    = userInfo[&quot;city&quot;]!<br \/>\n    let state   = userInfo[&quot;state&quot;]!<br \/>\n    let country = userInfo[&quot;country&quot;]!<\/p>\n<p>    let place = AWFPlace(city: city, state: state, country: country)<br \/>\n    let advisoryLoader = AWFAdvisoriesLoader()<\/p>\n<p>    advisoryLoader.getAdvisoriesForPlace(place, options: nil) { (advisories, e) -&gt; Void in<br \/>\n      if let error = e {<br \/>\n        println(&quot;Error:  \\(error.localizedDescription)&quot;)<br \/>\n      } else {<br \/>\n        \/\/ Take the last advisory<br \/>\n        if let advisory = advisories.last as? AWFAdvisory {<\/p>\n<p>        let userInfo = [<br \/>\n          &quot;location&quot;:  city + &quot;, &quot; + state,<br \/>\n          &quot;name&quot;:  advisory.name,<br \/>\n          &quot;body&quot;:  advisory.body<br \/>\n        ]<\/p>\n<p>        NSNotificationCenter.defaultCenter().postNotificationName(&quot;ADVISORY_AVAILABLE&quot;,<br \/>\n          object: nil,<br \/>\n          userInfo: userInfo)<br \/>\n        } else {<br \/>\n          println(&quot;no advisories&quot;)<br \/>\n        }<br \/>\n      }<br \/>\n    }<br \/>\n  }<br \/>\n[\/objc]<\/p>\n<p>Now, when our <code>WeatherServiceController<\/code> receives a new location from our <code>CoreLocationController<\/code> (via a <code>NSNotification<\/code> labeled <code>LOCATION_AVAILABLE<\/code>), it will unpack this information from the <code>userInfo<\/code> dictionary, create an <code>AWFPlace<\/code>, and then use the <code>AWFAdvisoriesLoader<\/code> to load any advisories for the area.  <\/p>\n<p>Let&#8217;s take a look at what we&#8217;re doing with the <code>advisories<\/code> array.  For simplicity, and to not barrage the user with push notifications, we&#8217;re going to take the <i>last<\/i> advisory in any list of advisories returned to us.  The expression <code>if let advisory = advisories.last as? AWFAdvisory<\/code> is our use of Swift optionals to evaluate the <code>if<\/code> block to true if we have an advisory.  If we do have an advisory then we create a <code>userInfo<\/code> dictionary containing the location of the advisory, the advisory name, and an advisory body which contains additional information.  This information is then posted to the <code>NSNotificationCenter<\/code> with the name <code>ADVISORY_AVAILABLE<\/code>.  <\/p>\n<p>We&#8217;ve only scratched the surface in what is possible with the Aeris SDK.  For more information on using Aeris, see the <a href=\"http:\/\/www.hamweather.com\/support\/documentation\/mobile\/aeris-ios-2.0-beta\/getting-started\/\">Getting Started<\/a> documentation.<\/p>\n<h2>Pushing the Advisory<\/h2>\n<p>If you recall from <a href=\"http:\/\/dev.iachieved.it\/iachievedit\/?p=823\">Part One<\/a> of our tutorial we created a class <code>PushNotificationController<\/code> to be responsible for managing our relationship with the <a href=\"https:\/\/parse.com\/\">Parse<\/a> framework.  Let&#8217;s return to our <code>PushNotificationController<\/code> class and update its <code>init<\/code> routine to handle listening for an <code>ADVISORY_AVAILABLE<\/code> notification.<\/p>\n<p>The full <code>init()<\/code> function for <code>PushNotificationController<\/code> should now look like:<\/p>\n<p>[objc]<br \/>\n  override init() {<br \/>\n    super.init()<\/p>\n<p>    let parseApplicationId = valueForAPIKey(keyname: &quot;PARSE_APPLICATION_ID&quot;)<br \/>\n    let parseClientKey     = valueForAPIKey(keyname: &quot;PARSE_CLIENT_KEY&quot;)<\/p>\n<p>    Parse.setApplicationId(parseApplicationId, clientKey: parseClientKey)<\/p>\n<p>    NSNotificationCenter.defaultCenter().addObserver(self,<br \/>\n      selector: &quot;advisoryAvailable:&quot;,<br \/>\n      name: &quot;ADVISORY_AVAILABLE&quot;,<br \/>\n      object: nil)<\/p>\n<p>  }<br \/>\n[\/objc]<\/p>\n<p>Now let&#8217;s write our <code>advisoryAvailable:<\/code> routine:<\/p>\n<p>[objc]<br \/>\n  func advisoryAvailable(notification:NSNotification) -&gt; Void {<\/p>\n<p>    println(&quot;advisoryAvailable&quot;)<\/p>\n<p>    \/\/ Get our advisory name<br \/>\n    let userInfo = notification.userInfo as Dictionary&lt;String,String&gt;<\/p>\n<p>    let advisoryLocation = userInfo[&quot;location&quot;]!<br \/>\n    let advisoryName     = userInfo[&quot;name&quot;]!<\/p>\n<p>    let pushMessage = &quot;Weather Advisory for \\(advisoryLocation):  \\(advisoryName)&quot;<\/p>\n<p>    \/\/ Create our Installation query<br \/>\n    let token = PFInstallation.currentInstallation().deviceToken<br \/>\n    let pushQuery:PFQuery = PFInstallation.query()<br \/>\n    pushQuery.whereKey(&quot;deviceToken&quot;, equalTo:token)<\/p>\n<p>    \/\/ Send push notification to query<br \/>\n    let pushNotification:PFPush = PFPush()<br \/>\n    pushNotification.setQuery(pushQuery)<br \/>\n    pushNotification.setData([<br \/>\n      &quot;sound&quot;:&quot;alert.caf&quot;,<br \/>\n      &quot;alert&quot;:pushMessage<br \/>\n      ])<br \/>\n    pushNotification.sendPushInBackgroundWithBlock({ (succeeded,e) -&gt; Void in<\/p>\n<p>      if succeeded {<br \/>\n        println(&quot;Push message to query in background succeeded&quot;)<br \/>\n      }<br \/>\n      if let error = e {<br \/>\n        println(&quot;Error:  \\(error.localizedDescription)&quot;)<br \/>\n      }<br \/>\n    })<br \/>\n  }<br \/>\n[\/objc]<\/p>\n<p>Breaking this down, we:<\/p>\n<ul>\n<li>unpack our advisory information from the <code>NSNotification<\/code>\n<li>build a Parse <code>PFQuery<\/code> targeted for <i>our<\/i> device\n<li>use Parse to send the push notification\n<\/ul>\n<p>This code uses Parse&#8217;s <i>client push<\/i> capability which <b>must<\/b> be enabled for your Parse application.  Go to your application in <a href=\"https:\/\/parse.com\">Parse<\/a> and to the <b>Settings &#8211; Parse<\/b> page and enable <i>client push<\/i>.<\/p>\n<p><a href=\"http:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/tut_parse_client_push.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/tut_parse_client_push.png\" alt=\"tut_parse_client_push\" width=\"996\" height=\"210\" class=\"alignnone size-full wp-image-958\" \/><\/a><\/p>\n<p><b><font color=\"red\">Warning!<\/font><\/b>Failure to enable <b>client push<\/b> in the Parse portal will result in your push notification failing!<\/p>\n<p>We should be able to now run our application and using a combination of Wunderground and Xcode simulator find a location that we know has a pending advisory.  Simply look at the current weather advisories, find a city in one, and then use <a href=\"https:\/\/www.google.com\/#q=gps+coordinates+for+dallas+texas\">Google<\/a> to look up the GPS coordinates.  As of today there is a Coastal Flood Advisory for Franklin, Louisiana, so we&#8217;ll put it&#8217;s GPS coordinates in our <code>Waypoints.gpx<\/code> file.<\/p>\n<p><a href=\"http:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/tut_gps_coordinates.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/tut_gps_coordinates.png\" alt=\"tut_gps_coordinates\" width=\"567\" height=\"326\" class=\"alignnone size-full wp-image-960\" \/><\/a><\/p>\n<p>Remember to put a minus sign for the longitude coordinate if you want the Western hemisphere!<\/p>\n<p>Putting everything together and running our application, we get a nice push notification about a coastal flood advisory in Franklin, Louisiana.<\/p>\n<p><a href=\"http:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/tut_weather_advisory.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/tut_weather_advisory.png\" alt=\"tut_weather_advisory\" width=\"320\" height=\"568\" class=\"alignnone size-full wp-image-971\" \/><\/a><\/p>\n<h2>Adding Sound to our Push Notification<\/h2>\n<p>Push notifications should typically grab your attention, especially ones for weather alerts!  If you recall our push notification data is set as follows:<\/p>\n<p>[objc]<br \/>\n    pushNotification.setData([<br \/>\n      &quot;sound&quot;:&quot;alert.caf&quot;,<br \/>\n      &quot;alert&quot;:pushMessage<br \/>\n      ])<br \/>\n[\/objc]<\/p>\n<p>The <code>sound<\/code> data specifies a sound resource to play back with the receipt of the push notification.  This file has to be included in your application resources obviously to be located and played.  So grab our <a href=\"http:\/\/dev.iachieved.it\/downloads\/alert.caf\">alert.caf<\/a> file and add it to your project.  Then, ensure that it is added as a resource by going to your application target and selecting the <b>Build Phases<\/b> page and adding <code>alert.caf<\/code> in the <b>Copy Bundle Resources<\/b> section.<\/p>\n<p><a href=\"http:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/tut_copy_bundle_resources.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/tut_copy_bundle_resources.png\" alt=\"tut_copy_bundle_resources\" width=\"866\" height=\"261\" class=\"alignnone size-full wp-image-962\" \/><\/a><\/p>\n<h2>Bitbucket Xcode Project<\/h2>\n<p>The work done thus far is available on <a href=\"https:\/\/bitbucket.org\/joeiachievedit\/weatheralerts\/\">Bitbucket<\/a> on a branch named <b>part3<\/b>.  To use the project you can directly download the <a href=\"https:\/\/bitbucket.org\/joeiachievedit\/weatheralerts\/get\/part3.zip\">zip file<\/a> and open the enclosed Xcode project.  There are a few steps you&#8217;ll need to complete to use the project:<\/p>\n<ul>\n<li>Sign up for Parse and HAMweather and obtain your own API keys\n<li>Change the <b>Bundle Identifier<\/b> to reflect your organization (that is, change <code>it.iachieved.<\/code> to <code>com.yourcompany<\/code>)\n<li>Create and add your own <code>ApiKeys.plist<\/code> file and use your Parse and HAMweather API keys\n<li>Create and configure your own provisioning profile\n<\/ul>\n<h2>Additional Thoughts<\/h2>\n<p>Our application is pretty basic.  So basic, in fact, there&#8217;s no user interface.  No home location we can set, no weather forecast to look at, and we can&#8217;t even choose which types of advisories we want to receive.  Honestly, who needs coastal flood advisories sent to them?  Well, other than those on the coast.  There&#8217;s plenty we can do with the basic application framework developed, and now is where the fun can really begin.  <\/p>\n<p>Unfortunately, there is a bit of a flaw in our application design.  What happens if an advisory is issued for an area <i>after<\/i> the user has moved into area?  Oh dear.  Well, perhaps we can run our application in the <a href=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/iPhone\/Conceptual\/iPhoneOSProgrammingGuide\/BackgroundExecution\/BackgroundExecution.html\">background<\/a> and periodically wake up and check for advisories?  Nope.  Could we increase the frequency of receiving location updates in the background?  Sure, if you wanted Apple to reject your application outright.  <\/p>\n<p>This is where it can become all too obvious that mobile applications that provide up-to-date information feeds typically require some type of <i>cloud application<\/i> to push those feeds to users.  Taking a look at our demo application the issue is that <i>something<\/i> needs to be periodically checking whether or not there are new advisories for the user&#8217;s last known location.<\/p>\n<p>Never fear.  We&#8217;re going to expand this tutorial series to include utilizing Parse&#8217;s <i>Cloud Code<\/i> feature to run background jobs to update a user if there is a new advisory for their last location.  Stay tuned!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Editor&#8217;s Note: This is part three in a three part series. The goal in this series is to develop a fully functional (and useful) iOS application that is capable of pushing weather alerts based on your location to your iOS device. The series is broken down as follows: Part One &#8211; Developing a Push Notification-capable [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11,5],"tags":[],"class_list":["post-934","post","type-post","status-publish","format-standard","hentry","category-apple","category-swift"],"_links":{"self":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts\/934"}],"collection":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/comments?post=934"}],"version-history":[{"count":28,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts\/934\/revisions"}],"predecessor-version":[{"id":972,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts\/934\/revisions\/972"}],"wp:attachment":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/media?parent=934"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/categories?post=934"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/tags?post=934"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}