geolocation

At the end of the last article in this series, we had a weather app that looked like this:

tampa forecast

The user enters the name of a city, presses the Get weather for the city above button, and gets the current weather conditions shortly afterward.

In this article, we’re going to learn the basics of programming a feature that most iOS weather apps have: geolocation. We’ll build a simple geolocation app, and we’ll eventually give our weather app the ability to display weather information about the user’s current location without requiring the user to enter the name of that location.

To do this, we’ll make use of location services, which we’ll access through the Core Location framework, and the CLLocationManager and CLLocation classes in particular.

In case you missed the earlier installments in this series, here are part one, part two, and part three.

A slight detour: the GeoExample app

Our weather app already has a fair bit of stuff in it, so we’ll cover Core Location by starting with a simple new app that reports the latitude and longitude of the user’s current location. It’s pretty simple, and we’ll roll its code into our weather app in the end.

Open Xcode, create a new single view application for the iPhone, and give it the name GeoExample.

Setting up to ask the users’ permission to use their location in Info.plist

Each app that makes use of the user’s location need to ask the user for permission to do so. This permission is recorded on a per-app basis; a user can grant one app permission to use his/her location, and deny that permission to another app.

iOS users can grant two different kinds of permission to use their location:

  • Permission to use the user’s location only when the app is in use (that is, when it’s the one shown on the screen).
  • Permission to use the user’s location both when the app is in use and when it’s running in the background.

For this example app, as well as our weather app (when we add geolocation to it), we just want the user’s permission to use location services only when the app is in use.

iOS has a built-in facility for asking both kinds of permission with an alert view. To ask for the user’s permission to use location services only when the app is in use, we use the CLLocationManager instance method requestWhenInUseAuthorization(). When called, it causes an alert view like the one below to appear:

permission dialog

The title, Allow “GeoExample” to access your location while you use the app?, is automatically generated by iOS, which inserts the app’s name (GeoExample, in this case) into a preset string. You can’t change it.

However, the message below the title is customizable and set in the app’s Info.plist. The message we’ll use is: In order to show you your coordinates, this app needs access to this device’s location abilities. This information won’t be shared with anyone. This message is stored in Info.plist under the key NSLocationWhenInUseUsageDescription.

Let’s set that message right now. Open Info.plist (the project file that contains a number of settings for your app) and add a new row to it. If you’re not familiar with adding new rows to Info.plist, follow the instructions below:

info plist geolocation setup 1

  • Control-click in the blank area of Info.plist located below its rows.
  • A menu will appear. Select Add Row from that menu.

info plist geolocation setup 2

  • In that newly-created row, change the contents of the Key column (the leftmost column) to NSLocationWhenInUseUsageDescription. This specifies that the row will contain the message text for the alert view asking the user for permission to access his/her location while the app is in use.

info plist geolocation setup 3

  • Now change the contents of the Value column (the rightmost column) to the message text that will go in the alert view: In order to show you your coordinates, this app needs access to this device’s location abilities. This information won’t be shared with anyone.

Next stop: Main.storyboard, to draw the user interface

ui

Draw a button on the view, give it the title Get current location, and assign it a Touch Up Inside action with the name getCurrentLocationButtonPressed.

And finally, ViewController.swift for the code

Here’s the view controller code:

The view controller code, explained

Near the beginning of the file, we have these lines:

import CoreLocation makes the Core Location library available to all code in the file.

The class declaration line shows that the ViewController, like all view controllers, inherits from UIViewController, but also adopts the CLLocationManagerDelegate protocol. Adopting CLLocationManagerDelegate gives the view controller the ability to respond to all kinds of location and heading updates from a CLLocationManager instance.

Here’s a diagram showing the relationship between the CLLocationManager instance and the view controller:

cllocationmanager - cllocationmanagerdelegate

Here’s the first line of the view controller class:

It defines ViewController’s single property, locationManager, the instance of CLLocationManager that provides the location updates.

The next notable part of the view controller is the getLocation() method, which performs a series of checks, and if they pass, it tells the location Manager to start sending location events. It’s called when the view controller is loaded, and when the Get current location button is pressed:

Most of getLocation() is concerned with ruling out cases where we can’t get the user’s location. Only the last three lines of the method deal with getting location updates from locationManager; they’re preceded by a couple of “bouncers” in the form of guard statements to keep invalid cases out.

  • The first guard statement allows control to pass to the next line if and only if location services are enabled for the device. If location services are disabled, the “Location services are disabled on your device” message is printed to the debug console, and getLocation() is exited.
  • The second guard statement allows control to pass to the next line if and only if the app is authorized to use location services when it is in use (i.e., its authorization status is .AuthorizedWhenInUse). A switch statement in the guard block determines the specific reason why the app isn’t authorized:
    • If the app explicitly does not have permission to use location services (i.e., its authorization status is either .Denied or .Restricted), the “This app is not authorized to use your location” message is printed to the debug console.
    • If the app has not explicitly been given or denied permission to use location services (i.e., its authorization status is .NotDetermined), the location manager’s requestWhenInUseAuthorization() method is called, which displays the alert asking the user if s/he wants to give the app permission to use location services.
    • The default case is the remaining authorization status, .AuthorizedAlways. There’s no way to get to this point because locationManager.requestAlwaysAuthorization(), which presents the user with an alert asking to use location services when the app is in use or running in the background, doesn’t appear anywhere in the code. I include this case only because the switch statement requires that all cases to be covered.

If control made it past the first two guard statements, it means that locations services has been activated for the device and the user has given our app permission to use location services while the app is active. The following happens:

  • It sets the view controller as the location manager’s delegate, which means that it can receive and respond to location and heading updates from the location manager.
  • It requests the best possible location accuracy from the location manager, which can pinpoint your device’s coordinates within 5 meters (16.4 feet).
  • It tells the location manager to start sending regular location updates, typically at a rate of once per second.

Once the location manager starts sending updates, it runs this loop until told to stop:

core location standard location service loop

The loop is pretty simple:

  • Try to get the current location, usually using some combination of GPS, cellular tower triangulation, and wifi positioning depending on the location accuracy setting.
  • If location results were obtained, call the location manager’s delegate’s locationManager(_:didUpdateLocations:) method, providing the location results as a parameter for the call.
  • If location results were not obtained, call the location manager’s delegate’s locationManager(_:didFailWithError:) method, providing the error object as a parameter for the call.
  • Go back to the first step.

Here’s some sample output from my debug console when I ran the app on my iPhone:
<+28.06456694,-82.50014378> +/- 5.00m (speed 0.00 mps / course -1.00) @ 5/12/16, 10:33:13 PM Eastern Daylight Time
<+28.06456694,-82.50014378> +/- 5.00m (speed 0.00 mps / course -1.00) @ 5/12/16, 10:33:14 PM Eastern Daylight Time
<+28.06456694,-82.50014378> +/- 5.00m (speed 0.00 mps / course -1.00) @ 5/12/16, 10:33:15 PM Eastern Daylight Time
<+28.06456694,-82.50014378> +/- 5.00m (speed 0.00 mps / course -1.00) @ 5/12/16, 10:33:16 PM Eastern Daylight Time
<+28.06456694,-82.50014378> +/- 5.00m (speed 0.00 mps / course -1.00) @ 5/12/16, 10:33:17 PM Eastern Daylight Time
<+28.06456694,-82.50014378> +/- 5.00m (speed 0.00 mps / course -1.00) @ 5/12/16, 10:33:18 PM Eastern Daylight Time

With this, we’ve got the basics of iOS geolocation. In the next installment, we’ll add a few niceties to our geolocation code and add it to our weather app.

Download the project files

xcode download

You can download the project files for this article (29KB zipped) here.

{ 1 comment }

Always keep an eye on your throughput

by Joey deVilla on May 11, 2016

this device has low io throughput

{ 0 comments }

weather

The story so far

In the first article in this series, we introduced the OpenWeatherMap service and showed you how to send it a request for the current weather in a specified city and get a JSON response back, first manually, then programmatically. We expanded on this in the second article, where we gave the app the ability to convert that JSON into a dictionary from which Swift can easily extract data.

In both articles, the weather information wasn’t being presented in the user interface. All output was printed out to the debug console. It’s now time to make our app display information to the user. By the end of this article, we want our app to look like this:

tampa forecast

Let’s get started!

The WeatherGetter class

So far, we’ve spent most of our time working on the WeatherGetter class, which connects to OpenWeatherMap.org, provides it with a city name, and retrieves the current weather for that city.

WeatherGetter makes use of:

  • the Shared Session instance of the NSURLSession class (which provides an API for sending and receiving data to and from a given URL), and
  • an instance of NSURLSessionDataTask, which downloads data from a specified URL into memory.

Here’s how these classes relate to each other:

The user interface lives in the view controller, while the weather networking apparatus lives in WeatherGetter. Here’s the setup we’re aiming for:

view controller - weathergetter relationship 1

We create this setup using delegation, a design pattern that you’ll often see in iOS programming when one object coordinates its activities with another object:

view controller - weathergetter relationship 2

We’ll add a protocol definition to WeatherGetter:

This definition specifies the interface for two methods:

  • didGetWeather, which we’ll call if we were able to retrieve the weather data from OpenWeatherMap and parse its contents. It will provide the weather data in the form of a Weather struct, which we’ll talk about in a moment.
  • didNotGetWeather, which we’ll call if we were not able to retrieve the weather data from OpenWeatherMap or if we weren’t able parse its contents. It will provide an error object that will explain what kind of error occurred.

We’ll have the view controller register itself with WeatherGetter, and both didGetWeather and didNotGetWeather will be implemented in the view controller.

Here’s the complete WeatherGetterDelegate.swift file:

The Weather struct

In order to more easily send the weather data from WeatherGetter to the view controller, I created a struct called Weather. It lives in a file called Weather.swift, and it’s shown in its entirety below:

When initializing the Weather struct, you pass it the [String: AnyObject] dictionary created by parsing the JSON from OpenWeatherMap. Weather then takes that data from that dictionary and uses it to initialize its properties.

The Weather struct does a number of useful things:

  • It turns the dictionary-of-dictionaries structure of the data from OpenWeatherMap into a nice, flat set of weather properties,
  • it provides the date/time values provided by OpenWeatherMap in iOS’ native NSDate format rather than in Unix time (an integer specifying time in seconds after January 1, 1970), and
  • it uses computed properties to report temperatures in degrees Celsius and Fahrenheit rather than Kelvin.

You may notice that the windDirection and rainfallInLast3Hours properties are optionals. That’s because OpenWeatherMap doesn’t always provide those values. It reports a wind direction if and only if the wind speed is greater than zero, and it reports rain information if and only if it’s raining.

The view controller

Here are the controls I put on the view, along with the names of their outlets:

view controller layout

I also created a Touch Up Inside action for the Get weather for the city above button called getWeatherForCityButtonTapped.

Here’s the code for ViewController.swift:

If you run the app, you should get results similar to this:

tampa forecast

st. johns forecast

If the temperatures seem a little chilly to you, it’s because you’re probably expecting them in Fahrenheit and I’m currently displaying them in Celsius. You can change this by changing the line in the didGetWeather method from

self.temperatureLabel.text = "\(Int(round(weather.tempCelsius)))°"

to

self.temperatureLabel.text = "\(Int(round(weather.tempFahrenheit)))°"

Take a good look at the code for the view controller — I’ve included a couple of tricks that I think improve the UI. I’ll explain them in greater detail in posts to follow.

web horizontal rule

In the next installment in this series, we’ll add geolocation capability to the app, so that the user can get the weather at his/her current location without having to type it in.

Download the project files

xcode download

You can download the project files for this article (51KB zipped) here.

{ 2 comments }

Uncanny Valley

ripstik

The RipStik gets a mention in Anna Wiener’s Uncanny Valley.

If you’re looking for some smart Sunday reading about the oft-neglected people aspect of technology, start with Anna Wiener’s Uncanny Valley, where she writes about her experience working that alternate reality known as San Francisco, circa 2013.

It’s a world where your culture and the company culture are one and the same, job descriptions are an energy-drink admixture of “HR’s idea of fun and a 23-year-old’s idea of work-life balance”, you can’t tell whether getting together over drinks is dating or networking, and FOMO hangs in the air like the city’s famous summer fog.

accept - tentative - decline

Here’s an excerpt:

A MEETING IS DROPPED MYSTERIOUSLY onto our calendars, and at the designated time we shuffle warily into a conference room. The last time this happened, we were given forms that asked us to rate various values on a scale of 1 to 5: our desire to lead a team; the importance of work-life balance. I gave both things a 4 and was told I didn’t want it enough.

The conference room has a million-dollar view of downtown San Francisco, but we keep the shades down. Across the street, a bucket drummer bangs out an irregular heartbeat. We sit in a row, backs to the window, laptops open. I look around the room and feel a wave of affection for these men, this small group of misfits who are the only people who understand this new backbone to my life. On the other side of the table, our manager paces back and forth, but he’s smiling. He asks us to write down the names of the five smartest people we know, and we dutifully oblige. I look at the list and think about how much I miss my friends back home, how bad I’ve been at returning phone calls and emails, how bloated I’ve become with start-up self-importance, how I’ve stopped making time for what I once held dear. I can feel blood rush to my cheeks.

“OK,” my manager says. “Now tell me: why don’t they work here?”

snow-crash-cover

Another excerpt reminds me of the line from Neal Stephenson’s Snow Crash that’s stayed with me since first reading it in 1992: “It was, of course, nothing more than sexism, the especially virulent type espoused by male techies who sincerely believe that they are too smart to be sexists”:

WE HIRE AN ENGINEER fresh out of a top undergraduate program. She walks confidently into the office, springy and enthusiastic. We’ve all been looking forward to having a woman on our engineering team. It’s a big moment for us. Her onboarding buddy brings her around to make introductions, and as they approach our corner, my coworker leans over and cups his hand around my ear: as though we are colluding, as though we are 5 years old. “I feel sorry,” he says, his breath moist against my neck. “Everyone’s going to hit on her.”

I include this anecdote in an email to my mom. The annual-review cycle is nigh, and I’m on the fence about whether or not to bring up the running list of casual hostilities toward women that add unsolicited spice to the workplace. I tell her about the colleague with the smart-watch app that’s just an animated GIF of a woman’s breasts bouncing in perpetuity; I tell her about the comments I’ve fielded about my weight, my lips, my clothing, my sex life; I tell her that the first woman engineer is also the only engineer without SSH access to the servers. I tell her that compared with other women I’ve met here, I have it good, but the bar is low. It’s tricky: I like these coworkers — and I dish it back — but in the parlance of our industry, this behavior is scalable. I don’t have any horror stories yet; I’d prefer things stay this way. I expect my mother to respond with words of support and encouragement. I expect her to say, “Yes! You are the change this industry needs.” She emails me back almost immediately. “Don’t put complaints about sexism in writing,” she writes. “Unless, of course, you have a lawyer at the ready.”

web horizontal rule

Go and read Uncanny Valley. If my endorsement isn’t enough, take Paul “ftrain” Ford’s

…or Leigh Alexander, from whom I found out about the article in the first place:

Inside Silicon Valley’s Big Pitch Day

y combinator demo day

Inside Silicon Valley’s Big Pitch Day is another piece by Anna Wiener about Y Combinator’s Demo Day, the show-and-tell held at the end of every March and August where companies funded by the seed accelerator firm parade their people and products to a room of very exclusive guests. She covers it not with the breathless tech-for-tech’s sake style that a more nerd-focused writer might employ, nor with the tech-for-getting-filthy-rich’s sake manner that someone with a Forbes-y/Business Insider-y bent would use. As she puts it:

I’ve worked in tech for a few years and love technology, if not always the techindustry: I’m neither an entrepreneur nor an engineer, I’m just a humanist with a sociology degree. I went to Demo Day as both an insider and an outsider, hoping to see a slice of the future.

She points out the sili-ness that comes with Silicon Valley, but at the end, she also points out reasons to be hopeful:

Still, to see one of Silicon Valley’s most lauded accelerators give a platform to people working in sanitation, social services, and healthcare felt tremendous. The future of technology is not necessarily in consumer or B2B software, and it’s not necessarily in the United States, either—some of the more compelling ideas came from international companies catering to local markets. These were hardly the most glamorous companies, but they were the companies that seemed most important to get in front of an audience with as much economic, cultural, and political clout as those assembled at Demo Day.

The Y Combinator motto is straightforward: “Make something people want.” At Demo Day, there were signs that the accelerator, and Silicon Valley as a whole, could also help companies make something people need.

For those of you who were curious about the company she was writing about in Uncanny Valley, she drops a hint in Inside Silicon Valley’s Big Pitch Day: “Full disclosure: From 2013-2014, I worked for a Y Combinator startup. The CEO was 24.”

Hacking Technology’s Boy’s Club

ellen ullman

There are a precious few books that I have to keep buying over and over again because I keep giving away my copy to friends. One of these books is Close to the Machine: Technophilia and its Discontents by Ellen Ullman. Published in 1997, it’s a memoir that tells a good number of interesting stories, shows the human side of computer (and yes, there is one), and finally, it manages to pull off what should be impossible — it makes coding look interesting, and even exciting, to non-coders. As a reader of this blog, it may seem strange to you to not think of programming as exciting, but we’re the kind of people who look forward to a long flight as a chance to try out a new programming language or API.

Anna Wiener’s January 2016 article for The New Republic, Hacking Technology’s Boy’s Club, is a good intro to Ellen Ullman for those of you who aren’t familiar with her or her work. In some parts, we see an Ullman who’s concerned about the social issues of the tech industry and its products:

“It will not work to keep asking men to change,” Ullman told me. “Many have no real objective to do so. There’s no reward for them. Why should they change? They’re doing well inside the halls of coding.” To be perfectly clear: Ullman isn’t anti-geek-culture; she’s not anti-technology; she’s not anti-men. She doesn’t want to raze the clubhouse. She simply wants those inside to open the door.

Though she retired from the tech industry at the end of the last boom, to read Ullman’s work is to remember she’s been with us all along. Code, for all its elegance and power, is just a tool. “As with all advances in technology, the new offerings are often helpful, and marvelous—sometimes frightening, as with advances in surveillance,” she said. “The services are enormously convenient, but then there is the culture left behind. When we receive the dry cleaning delivery, we no longer see who does the work. We don’t see the tailor in the window, the presser surrounded by steam. When you order food on your phone from GrubHub, you don’t see the cooks and helpers in the hot kitchen.” The question of who delivers to whom, she continued, is directly related to inequality at large—it’s essential that the technologies we create and use are also building a world we want to live in.

But she’s just as into the hardcore, technical nitty-gritty that you and I love:

One afternoon last summer, I invited Ullman to my workplace. Within minutes, she and two young engineers were debating the merits of strongly typed languages, a conversation they’ve had many times before; it quickly became clear that Ullman had tipped the scales. “See? I told you so,” one said, vindicated. As enjoyable as it was to watch her, I was in over my head. Ullman noticed immediately. “Sorry—you must be bored,” she said. “This is fun for me.”

web horizontal rule

There you have it: three interesting articles by Anna Wiener. I look forward to reading more of her work.

{ 0 comments }

adding geolocation to our weather app

The next Tampa iOS Meetup has been announced for Wednesday, May 4th at 6:30 p.m.. This one builds on the previous meetup (but if you missed the last one, we’ll get you caught up) and is called Adding geolocation to our weather app.  It takes place at our usual spot: Energy Sense Finance, 3825 Henderson Boulevard (just west of Dale Mabry), Suite 300.

We’ll pick up from where our last meetup, Build a simple weather app (and learn basic network programming along the way), left off. The app required you to specify your location before it would report the weather. But that’s not how most weather apps work: they use geolocation to get your phone’s coordinates and provide them to the weather service. In this meetup, we’ll show you how to harness the power of iOS geolocation through the Core Location framework.

We’ll begin with a quick walkthrough of last meetup’s weather app, just as a reminder for those of you who were there, and as a way for those of you who weren’t to get caught up. Then we’ll get right into the business of adding geolocation capability to our weather app, so that when you run it, it displays the weather for your location.

At the end of this session, you’ll know how to make use of geolocation through Core Location. We’ll make the source code and presentation materials available at the end, to make it easier for you to start your own geolocation projects.

Join us this Wednesday, get to know your fellow Tampa Bay iOS developers, and get ready to learn and have some fun!

Tampa iOS Meetup is a monthly meetup run by local mobile developer/designer Angela Don and Yours Truly. While Tampa has a couple of great iOS developer meetups — Craig Clayton’s Suncoast iOS and Chris Woodard’s Tampa Bay Cocoaheads — they’re aimed at intermediate- to expert-level iOS developers. We figured that there was room for a third iOS meetup in the Tampa Bay area, and especially one that focused on people new to iOS development or even development in general. So we made one.

The Details

  • What: Tampa iOS’ Meetup’s “Adding geolocation to our weather app” session. Please sign up on our Meetup page so we can plan accordingly!
  • When: Wednesday, May 4, 2016, 6:30 p.m. – 9:00 p.m. We’ll have some snacks at 6:30, with the presentation beginning at 7:00.
  • Where: Energy Sense Finance, 3825 Henderson Boulevard (just west of Dale Mabry), Suite 300. See the map below.

  • What to bring: Yourself, but if you’d like to follow along, bring your Macbook and make sure it’s got the latest Xcode.
  • What to read in advance: If you’re one of those people who likes to do some readings ahead of a presentation, try this example location app written in Swift. We’ll be using our own tutorial material, but this may come in handy.

{ 0 comments }

Want to test an iPhone/iPad game?

by Joey deVilla on April 25, 2016

Wine Crush is a simple “Candy Crush”-like game that I’m developing for my friends at Aspirations Winery in the nearby city of Clearwater. It’s the first of a few apps that I hope to publish to the App Store this year. If you’ve got an hour or so to spare and are the sort of person who always has ideas on how apps could be improved, this opportunity’s the one you’ve been waiting for!

Wine Crush is a pretty straightforward game. You play by creating matching groups of wine-related images — glasses of wine, bottles, corks, grapes and cheese — in groups of three or more. You can create horizontal matching groups…

Animation showing how players form a horizontal match in Wine Crush.

…or vertical matching groups:

Animation showing how players form a vertical match in Wine Crush.

You score points for creating matching groups, and the goal for each level of the game is to score a target number of points within a given number of moves. If you meet the goal, you get to proceed to the next level. If you don’t, it’s GAME OVER.

Anitra Pavka (3rd from left) and Joey deVilla (4th from right) at 'Wine-O Bingo' at Aspirations Winery, Clearwater, Florida.

“Wine-O Bingo” at Aspirations Winery, summer 2014. My wife Anitra’s third from the left, and I’m the smiling guy across the table from her, fourth from the right.

Wine Crush is designed as a promotional tool for Aspirations Winery, which is run by Bill and Robin Linville. My wife Anitra has been buying their wines for years. She took me to one of their regular “Wine-O Bingo” events in 2014 (pictured above), and made friends with them after entertaining their guests with a couple of their accordion numbers. Soon after, I approached them with a proposition: Would you like to have an iPhone game for your winery?

They said yes, and I got to work. Starting with the “How to make a game link Candy Crush” tutorials from RayWenderlich.com as a basis, I put together a game with wine-related imagery and Aspirations’ branding, using artwork that Robin provided. The backgrounds for the games’ levels are various labels for Aspirations’ wines, and there are a couple of buttons on the main screen that you can click to find out more about the winery.

For Aspirations, it’s a cute little way to get their name out their in a way that sets them apart from most other small family-owned wineries. As for me, this app is a way for me to help out some friends, sharpen my programming skills, build a portfolio, and gain some valuable experience with the App Store. Aside from a fair bit of free wine (for which I’m very grateful), I’m not getting paid for this project.

The title screen and two game screens from Wine Crush.

Wine Crush needs to be tested before I put it on the App Store. As the developer, I’m a little too close to the project to spot all the bugs and places where it could be improved. That’s where you come in. I’m looking for a small group of people who like trying out new apps to take a pre-release version of Wine Crush for a spin, point out problems and crashes, and give me some feedback. I will also ask you to test some other interesting iPhone/iPad/Apple TV projects I’m working on. It won’t be an all-consuming process; all I’m asking for is a little bit of your downtime and your opinions.

Does the opportunity to test and give feedback on soon-to-be-released iPhone/iPad/Apple TV apps sound interesting to you? If it does and you’d like to join the test group, drop me a line at joey@joeydevilla.com.

This article also appears in The Adventures of Accordion Guy in the 21st Century.

{ 1 comment }

apple tv fun facts

A slide from tonight’s presentation.

tampa bay user experienceI was scheduled to speak tonight at the Tampa Bay UX Meetup and talk about Apple TV UX with my wife Anitra, but as luck would have it, work commitments this evening with GSG’s biggest client have conspired to keep me away.

The show must go on, and it’s in very good hand. Anitra’s forgotten more about user experience than I will ever learn, what with her work as a user experience and web accessibility consultant. She also wrote the accessibility chapter in O’Reilly’s HTML5 Cookbook and was a technical editor for O’Reilly’s Universal Design for Web Applications book. She’ll apply her knowledge to the fourth-generation Apple TV user experience, and walk you through it. There’ll be a presentation, followed by live demos of Apple TV apps and interface. She’ll also point you to resources that you can use to help you design and even build tvOS apps.

It all happens tonight at 6:00 p.m. at the offices of 352 Inc., located at 5100 West Kennedy Boulevard, Suite 352 in Tampa. You can sign up and find out more on the Tampa Bay UX Meetup page. My thanks to organizer Krissy Scoufis for all her help!

{ 0 comments }