Quantcast
Channel: Kodeco | High quality programming tutorials: iOS, Android, Swift, Kotlin, Unity, and more
Viewing all 4370 articles
Browse latest View live

Video Tutorial: iOS App Extensions Part 4: Photo Extensions: Shared Settings


Readers’ App Reviews – February 2016

$
0
0

RollerBall

Valentines Day is behind us but I’m still falling for all these sweet community apps!

The community has been hard at work pumping out new games and apps built with our tutorials. I’ve downloaded a ton of them and I’ve picked a few to show you.

I receive more than an app a day from readers like you busy working on games. I don’t have time to write about every app that hits my inbox, but hopefully the few I show you gets you excited for our community and inspires you to finish your app. Don’t miss the honorable mentions, plenty more inspiration waiting for you.

This month we have:

  • An app for know it alls
  • A game for your thumbs
  • An app for the world traveler
  • And of course, much more!

Keep reading to see the the latest apps released by raywenderlich.com readers like you!

WOKwiki

WOKWiki
Are you a know it all? More importantly are you a WikiKnowItAll? WOKWiki is made for you!

WOKWiki takes all of Wikipedia and turns it into a multiple choice quiz! Seriously, how awesome is that? You can play against your friends or the community. Race for time or go head to head on accuracy.

Any subject you can think of is covered. Historical Figures, Sports, Technology, China, Logic. Literally any random fact on Wikipedia is up for grabs. You can use tags to limit the questions you’ll receive unless you really are a know it all. ;]

Invisible Pix

InvisiblePix
Invisible Pix is the coloring book for the iPad.

Its got all the basic stuff you’d expect like pinch to zoom, adjustable brushes, auto saving, and more. You can color free hand or use the Magic Pen to stay perfectly in the lines as you color. Tilting the device reveals an light outline as your color. When you’re done of course you can share to Facebook and Twitter or save to your photos directly.

There are tons of themes from Animals to Dragons to Mandalas to Pirates and much more. They’re adding more series over time including holiday specials. Most series only cost a couple dollars and the entire experience is 100% ad free.

The Travelist

Travelist
Do you travel so much you’ve forgotten where you’ve been? Then The Travelist is an app for you.

The Travelist will help you keep a log of all the countries and states you’ve visited. On the map of the world simply select where you’ve been to start compiling a list. You can mark where you’ve lived, visited, or would like to visit. As you enter your conquests you can see what percentage of the world or country you’ve seen. See a checklist of where you’d like to go.

You can also rank yourself against other travelers to see who’s seen the most of the world. Share your map, rank, and other travel stats with friends on Twitter, Facebook, iMessage, or even print it out.

Mr. Astroman

Astroman
Mr. Astroman is on a mission and needs your help. He’s flying into unexplored territory high above the planet’s surface.

The objective is simple: fly as high as you can while avoiding obstacles like falling spikes and force fields. Along the way you’ll encounter powerups and upgrades. Each level unlocks more equipment like shields and bullets. Use the bullets to blast holes in force fields and walls at just the right time.

See how high you can climb on the global GameCenter leaderboards or challenge your friends to beat your high scores. Collect achievements for your valor above the earth.

Roller Ball

RollerBall
Its gonna take more than just a little tilting to make it at Roller Ball.

Roller Ball is based on the old school classic and its a ton of fun. There are a handful of balls rolling around the screen and a matching slot for each ball. Your goal is to make sure each ball finds its home. But its going to take precision and planning to make it. Once a ball finds its slot its not over, other balls can still knock it out as they roll around the screen.

There are nine randomly generated levels with 3 levels of difficulty. So take your time and work your way up to mastery. Maybe one day you’ll be as good as me. ;]

ThumberJack

ThumberJack
ThumberJack is more than a catchy puntastic name. Its also a super addicting yet incredibly simple game.

To become the best ThumberJack you can be you’ll need precision, agility, and a keen sense of hand eye coordination. Or maybe just your thumb and some luck.

An endless log is flowing down the screen and you’ve got to cut it all! Keep your thumb in the touch zone to avoid getting cut and keep it on the log to keep the cut going. Get points each time your clear a log joint. See if you can make it to the top of the GameCenter leaderboards and be the best ThumberJack in the land!

QuoteBreaker

Quotebreaker
Do you love solved puzzles and putting that brain of yours to work? Good, time to download QuoteBreaker!

QuoteBreaker is a two part game. You start with a Nonogram puzzle. A grid with number hints for each row and column. You’ll fill a square for each number and leave the others blank. Each row’s rules must be satisfied. Its like sudoku on steroids. The second part is a Cryptogram built from the previous Nonogram. You’ll decipher a message using numbers as your guide.

QuoteBreaker is very challenging and extremely addicting. Once I started a puzzle I couldn’t put it down.

Stream for Twitter

Stream
Have you ever wanted to just watch Twitter in Realtime? Stream is here to help!

Stream lets you set up watch lists of interests from #hashtags to @mentions to keywords. You get three for free and then pay $1.99 for unlimited interests. Everything on your watchlist ends up in your stream. Your stream does exactly what you think. Tweets slide in from the top in real time. You can swipe left to like or retweet.

You can also check some sweet charts to see what is making up your stream. The charts show each of your interests and measure the count of tweets. You can use this for some cool ideas like streaming two competing hashtags to see which is more popular. If you’re a Twitter addict, add this to your list of must have apps.

Honorable Mentions

Every month I get way more submissions than I have time to write about. I download every app to try them out, but only have time to review a select few. I love seeing our readers through the apps submitted to me every month.

It’s not a popularity contest or even a favorite picking contest — I just try to share a snapshot of the community through your submissions. Please take a moment and try these other fantastic apps from readers like you.

Bouncy Buzz Blastoff
Cookie Shower
Joe Square
Searchr
WordHue
Chop’n’Bop
Trip Tracker Pro
8Calc
Analog Synth X
Desk Pad
cLrS (cOlOrs)
Myloco
cantoneseGame
plusclock HSB
Spiral Painter – Colorful Aura of Your Name

Where To Go From Here?

Each month, I really enjoy seeing what our community of readers comes up with. The apps you build are the reason we keep writing tutorials. Make sure you tell me about your next one, submit here.

If you saw an app your liked, hop to the App Store and leave a review! A good review always makes a dev’s day. And make sure you tell them you’re from raywenderlich.com; this is a community of makers.

If you’ve never made an app, this is the month! Check out our free tutorials to become an iOS star. What are you waiting for – I want to see your app next month.

The post Readers’ App Reviews – February 2016 appeared first on Ray Wenderlich.

Scheduled Maintenance Tomorrow

$
0
0

RayWenderlichLogo

This is just a quick heads up that we’ll be having some scheduled maintenance on raywenderlich.com tomorrow, Sunday Feb 28, around 9AM EST.

Our site is going to be moving to a new and modern forum, and a new authentication provider. Because of this, you’ll need to reset your password next time you log in.

I’ll share more about all the cool stuff in the new upgrade tomorrow. If you have any questions or issues, please contact support. Talk to you soon!

The post Scheduled Maintenance Tomorrow appeared first on Ray Wenderlich.

Announcing New Forums and Authentication System!

$
0
0

RayWenderlichLogo

Today, we are pleased to announce two upgrades to raywenderlich.com:

  • New forums powered by Discourse, from the creators of StackOverflow. The new forums represent a vast improvement over our current forums – they have Markdown support, dynamic notifications, and tons of other handy features. Check them out and join the conversation! :]
  • New authentication system powered by Auth0, a popular authentication provider.

We’re really excited about these changes, because the new cloud-based architecture should result in a snappier site and lay the foundation for some cool new features on the site in the months to come.

Where To Go From Here?

If you have an account on raywenderlich.com, you’ll need to reset your password. Here’s how:

  1. Log in. Visit our login page and log in with your raywenderlich.com email address and password.
  2. Reset password. It will prompt you to reset your password – do so.
  3. Check email. Finally, check your email for a confirmation link and accept.

That’s it! After that, you should have access to all your loot as usual – and feel free to play around with the new forums.

If you have any problems or questions, please contact us and we’ll lend you a hand.

Thanks all – and stay tuned for many more site improvements in the months ahead! :]

The post Announcing New Forums and Authentication System! appeared first on Ray Wenderlich.

Top 10 iOS Conferences in 2016

$
0
0

Top 10 iOS Conferences in 2016

If you’re an iOS developer, you should absolutely attend at least one iOS conference a year.

This is important so that you can keep your skills up-to-date, get a fresh burst of energy for your job, and to connect with the rest of the iOS community.

Luckily, there are tons of great iOS conferences to choose from. But which should you choose?

That’s what this post is about – a list of the the Top 10 iOS Conferences in 2016! To come up with this list, I surveyed over 300 developers, reached out to specific individuals to get their input, and merged this with my own opinions.

Please remember that this article is just my own personal opinion based on what I’ve heard from team members and the community. If I miss out on a conference you really like, please add your comments to this post, so everyone else can learn about it too.

The Conferences

Without further ado, let’s dive in to the top 10 iOS conferences of 2016!

Note: These conferences are listed in no particular order.

1) WWDC and AltConf

WWDC and AltConf

By far, the #1 choice among developers is Apple’s official conference – WWDC.

The content at WWDC is great, but to me that’s not the selling point – you can always watch the videos at home. What’s great about WWDC is two things:

  • WWDC Labs: At the WWDC labs, you can meet and ask questions to Apple engineers. Come prepared with questions!
  • Socializing: WWDC is the single largest gathering of iOS developers all year, and has tons of parties and social events all week. This is a great way to connect with old friends, and make new ones.

Getting a WWDC ticket isn’t easy – in recent years there has been a lottery system, with a smaller and smaller chance of getting a “golden ticket.”

However, even if you don’t get a ticket, you should consider coming to San Francisco anyway to socialize, and to attend an independent event that happens the same week – AltConf, which has a lot of great talks by members of the iOS community.

“WWDC – I love it. Highlight of my year – so much so that I’ve already booked flights, and plan to attend AltWWDC if I don’t get a ticket. San Francisco buzzes during one of the best weather-weeks of the year thanks to the influx of tech-visitors. Don’t miss The Bash on Thursday, the Design Review sessions and the lunchtime sessions – which have been increasingly impressive the last few years.”Gemma Barlow

“WWDC is the conference that transcends all other iOS conferences. Developers from around the world make their pilgrimage to the the Moscone Center to not only hear what new devices, frameworks, and other Apple tech they’ll get this year, but to get rare face time with Apple designers and engineers. The conference is only half of the event, as during WWDC week there are countless meetups and parties for both those with and without tickets.”Erik Kerber

“For the first developer conference I’ve attended, WWDC smashed all my expectations and turned me into a blob of hype and excitement. Apple engineers in the labs are both friendly and helpful so I would highly recommend you go talk to them if you get a chance. AltConf, which takes place across the street from WWDC, featured some extremely high quality talks from several well known individuals. If you don’t win the WWDC lottery, you can attend AltConf and still catch some Apple engineers in coffee shops all around the city.”Jack Wu

“Dub-dub is amazing, exhausting, expensive, and a wonderful way to meet people. . . .However if you’re financially constrained, it may not be worth the price. The ticket alone is expensive, as are getting to and around SF. Hotels in San Francisco can be stupid expensive, kind of sketchtastic, or even both. If you’re watching your budget, it’s probably a lot more cost-efficient to buy an Apple TV, take the week off work, and watch videos as Apple puts them up to stream. You lose a lot of opportunities to talk to other people in person, but depending on your financial situation or personality type, that sacrifice may well be worth the several thousand dollars you get to hang on to instead of spending it on WWDC.”Ellen Shapiro

2) 360iDev

360iDev

Other than WWDC, 360iDev is the oldest – and biggest – iOS conference on this list.

I’ve been to 360iDev many times over the years, and always have a blast. John Wilker does a great job organizing the event, with a nice mix of technical, design, and non-technical talks – it has a little bit of everything for everyone.

“360iDev is the biggest independent iOS developer conference in the United States. If WWDC and AltConf are too spendy for you but you want a chance to reconnect with your colleagues, this is your next best bet. There are always a large variety of different talk topics. They accept a lot of first time speakers, so it’s always possible to discover someone you haven’t seen before. Plus, it’s the last remaining place for you to be able to participate in Stump the Experts.”Janie Clayton

“A fantastic conference that mixes technical talks with discussions on working as an indie. The conference is located in downtown Denver, and the hosts work hard to integrate with the local area. The workshops and keynotes are definitely worth a mention, since they alone are worth attending for. The organizers have done a huge amount for the community, and really know how to put on a fantastic conference.”Sam Davies

“360iDev is the biggest conference I go to every year. Its packed with indies and those that make up the community I love being a part of. Every year its a great chance to see old friends and make new ones while enjoying the Apple Community at large.”Ryan Poolos

3) RWDevCon

RWDevCon

Full disclosure: our team runs RWDevCon, so we’re not impartial about the matter. However, the conference did very well on the poll, is quite different from the other options, and has sold out for two years straight, so I felt its spot on the list is warranted.

RWDevCon is different than the other iOS conferences, because instead of just listening to a talk, you participate.

RWDevCon has three simultaneous tracks of hands-on programming tutorials – all highly coordinated as a team, with tech editors and multiple rounds of practice. This way, you know the end result is the high quality style you know and love from our site!

“RWDevCon offers a unique mix of hands on tutorial style sessions and insightful ‘inspiration’ talks that really do inspire. There is something for everyone, with three tracks targeting different levels of expertise in a wide range of iOS topics that really stick thanks to the tutorial format of the talks. I was able to wet my feet with game development while also exploring advanced topics relevant to my work as an enterprise developer. Due to the more intimate setting, smaller size, and amazing inspiration talks, I made a lot of great friends and truly came home feeling inspired and excited to employ what I’d learned.”Jeff Rames

“As a speaker, I saw firsthand how much preparation went into RWDevCon presentations: A whole, whole lot. What I was really impressed by as an attendee was how much that came through in the finished product – the tutorial sessions were thorough, every effort was made to make them easy for attendees to follow, and I was able to work through problems and ask questions of the speaker during the lab. The opportunity to meet many people I’d been following through the site for years in person was also really great.”Ellen Shapiro

“This was a great way of actually learning a lot about a whole host of iOS-related topics, arranged into Beginner, Intermediate and Advanced tracks. In each tutorial, we worked through a topic and coded working examples along with the presenter – making it a really great way to learn. All the attendees stayed at or near the conference hotel so we generally stayed together over the 2 days. Lunch was provided on both days and the party held at the end of the first day (with food and drinks provided) was a fantastic way of getting to know everyone. Worth every penny.”Adrian Strahan

4) CocoaLove

CocoaLove

CocoaLove is another unique conference. Rather than focusing on technical talks, CocoaLove focuses on the people behind the tech.

Specifically, this means a lot of inspiration-style non-technical talks, along with some unique activities designed to help conference attendees get to know each other. If you’re looking for something a little bit different, consider giving CocoaLove a shot!

“CocoaLove is held in Philadelphia, and I *love* attending because there’s plenty of time to meet the speakers and chat in-between sessions. Talks are high quality, and there’s extra-curricular activities involved – last time a fabulous brewery tour and night-ride on a double-decker bus. The year before it was cheese steaks, a carousel and mini-golf. You’ll meet some fab indie developers here.”Gemma Barlow

“I have attended a lot of iOS conferences over the last three years. My absolute favorite conference was CocoaLove. The CocoaLove team went above and beyond to create a unique experience and showcase the venue in downtown Philadelphia. CocoaLove focuses on the iOS community as a whole more than the technology we use in our day to day lives. This created a wonderful atmosphere of friendship and acceptance where you could meet a lot of people you didn’t know initially and make friends. By focusing on the people CocoaLove created one of the most unique conference experiences I have ever had.”Janie Clayton

“You can get the latest information about developing for iOS from books, online, and from WWDC Videos. CocoaLove is a completely different experience. The presenters are top developers but they’re talking about issues we all face without presenting any code walkthroughs. It’s a friendly, intimate conference in a great setting.”Daniel Steinberg

  • When: Oct 14-16, 2016
  • Where: Philadelphia, PA, USA
  • Number of Attendees: 120
  • Number of Tracks: 1
  • Team members planning to attend: Gemma Barlow, Marin Todorov
  • Websites: CocoaLove

5) CocoaConf

CocoaConf

The big selling point behind CocoaConf is they run multiple events each year, at cities all around the US – so chances are you can find one close to you. Be sure to check it out if one is nearby!

“I got my start in conference speaking at CocoaConf. The CocoaConf Tour has given me a great opportunity to travel around the US meeting a lot of awesome developers. I would not have a career if the Kleins were not doing this conference. They made it accessible for people living in places that weren’t the Bay Area to be able to afford to attend a conference. They bring top notch speakers to you so that you don’t have to travel all the way out to the West Coast to get a chance to meet awesome people like Daniel Steinberg and Jaimee Newberry. These conferences feel like family and it’s a great way to get some quality time with a prominent member of the programming community.”Janie Clayton

“CocoaConf is a great affordable iOS and Mac circuit conference managed by Dave Klein and his family. This conference comes to at least eight locations throughout the year and is something every Mac and iOS developer should try to attend. Year to year some of the presenters haven’t changed but the content is fresh and the people are fun to be with.”Aaron Douglas

“CocoaConf is a great traveling conference which allows you to learn a lot without having to travel too far from home. It’s a great way to meet other devs from your area and your region as well. I enjoyed attending for the first time in 2014 so much that I asked if I could put a talk together. Two years later, I’ve now spoken at five CocoaConfs and am about to speak at my sixth.”Ellen Shapiro

6) iOSDevUK

iOSDevUK is a conference located in a university in Wales. It is extremely technical, and its remote location encourages attendees to bond and make good friendships. A raywenderlich.com team favorite that is definitely worth checking out! :]

“A quirky conference at the edge of the world – getting there is all part of the experience of iOSDevUK. The talks are all very technically focussed and well selected. It includes some peripheral workshops which are definitely worth attending. Highly recommended if you want to catch up with the latest developments in iOS and meet up with other devs from around the UK and the rest of the world.”Sam Davies

“iOSDevUK is run on a university campus in the gorgeous, sunny town of Aberystwyth in Wales, a couple of weeks before the students return. The attendees stay together in the halls of residence, and eat together in the university’s canteen, which really promotes interaction and a sense of community. The sessions and hands-on workshops are always of the highest quality, and cover an eclectic mix of topics, so you’re guaranteed to learn something regardless of your experience. Chris and Neil do a sterling job organising things, always going above and beyond to make sure everything goes off without a hitch!”Mic Pringle

“Held over 4 days at Aberystwyth University (which provided student accommodation to keep down the cost), this conference covered a wide range of topics and ideas from a varied group of presenters. Two tracks, roughly split into technical and more generic industry best-practice ensured that there was always something interesting to learn.”Adrian Strahan

7) NSNorth

NSNorth

NSNorth is Canada’s premier iOS developer and designer conference, with a mix of both technical and non-technical talks. Attendance is usually kept small for an intimate feel.

“NSNorth is a great conference for the inhouse and indie developers. I’ve attended the conference a couple of as it has been just short hop up the road around Ottawa. This year it’s moving to Toronto and know there’s a ton of interest for devs around the GTA and NY state. There have been some great talks on promoting your apps, finding a niche, and finding your muse. It’s helped me shape my business and target my audience. I’m really looking forward to attending this year. It’s definitely on my top 3 iOS conference list. I wouldn’t miss it.”Tim Mitra

“NSNorth is one of the best conferences I have ever been to. You are likely to meet every single attendee, including the presenters, when you’re there. I’ve personally made some great friends in our community every time I attend. If top-notch speakers weren’t enough, the organizers usually plan some wonderful social events like drinks in a dinosaur museum or ‘find-the-iBeacon’.”Ryan Nystrom

8) NSSpain

NSSpain

NSSpain is a single-track conference in northern Spain with a strong focus on having fun and meeting fellow attendees.

“A thoroughly enjoyable conference with top-quality technical talks. The highlight is very much the region, food and opportunities for catching up with fellow iOS devs in a truly beautiful part of the world.”Sam Davies

“NSSpain, #Pragma Conf and UIKonf represent a trend of european conferences that I pay extra special attention to. Aside from being really awesome locations, the organizers of these conferences are willing to try a lot of new things and still provide some solid technical meat. I’ve use these three conferences as places to meet other OSS contributors for whom it can be hard to find time for face to face chat otherwise. Being able to attend any of these is such a pleasure, and I aim to attend at least one each year for as long as they keep them running!”Orta Therox

“NSSpain is easily the best event in Europe. A multi-day single-track conference in the amazing Spanish country side in the area of Rioja where the famous red wine comes from. The atmosphere is relaxed and the most famous tapas street in the world is at a convenient short walk from everywhere. A lot of extra curriculum activities and a lot of care guarantee everyone has good time. You will leave with more friends than you come with.”Marin Todorov

9) #Pragma Conference

#Pragma Mark

#Pragma Conference is a conference in Italy that has both technical and design tracks, and covers both iOS and OS X development. Another one I’ve heard great things about!

“I really enjoyed Pragma Mark. I both gave a presentation and held a workshop, so I got to meet a tonne of people. Pragma Mark was a great relaxed environment. Being held in the heart of the beautiful Milan doesn’t hurt, either. It was like an Italian version of UIKonf.”Ash Furrow

“Pragma Conference is one of the European events with the best content. Amazing workshops and stellar speakers attract audience from around the globe. The event is a fantastic opportunity to network, enjoy great food and wine, and visit Italy. The 2016 edition will take place in Verona where you can visit Julietta’s backyard where the famous scene on the balcony takes place.”Marin Todorov

10) UIKonf

UIKonf

UIKonf is a single-track conference in Berlin with talks on iOS development, mobile design, and business.

This year, they have some free social events on the day before the conference, and they’re going to use them to raise donations for the refugees of the Syrian war.

“UIKonf is one of my favorite conferences, period. Drawing a crowd from all over Europe, you’ll hear talks from running an Indie business to Functional View Controllers to empathic Teaching and everything in between. You can really tell that the people behind the scenes put their heart and soul into it and it’s the best possible excuse to make a trip to Berlin.”Robb Böhnke

“UIKonf is a hidden gem of iOS conferences: it’s the best conference to actually meet and talk to other developers from around the world, and the talks focus on quality and variety rather than the list of usual suspects when it comes to presenters.”Daniel Eggert

“I spoke at UIKonf last year and I was thrilled because I knew it would be an extremely technical audience and I would be able to deliver a genuinely challenging talk about World Modeling without sparing the mathematics. If you’re one of the people constantly complaining that these other conferences are not technical enough, this is the one for you. Check out their talks on YouTube. They also have an amazing community-driven paper selection process everyone else should seek to emulate.”Mike Lee

  • When: May 22-25, 2016
  • Where: Berlin, Germany
  • Number of Attendees: 250
  • Number of Tracks: 1
  • Team members planning to attend: TBD
  • Websites: UIKonf

Honorable Mentions

As I mentioned, it was very difficult (and subjective) to put together the top 10 list this year as there are so many great conferences. I felt it would be amiss if I didn’t also include a few honorable mentions.

  • Indie DevStock: This is a brand new conference organized by women in an awesome venue in Nashville, Tennessee. Looks like this will be a blast!
  • try! Swift: This is another new conference in Tokyo, Japan organized by Natasha the Robot. Knowing Natasha, this should be great.
  • Swift Summit: This single-track conference had a London and SF event last year, focused on quick talks on the Swift Language. A great event if you’re in the area!

Which Should I Choose?!

If you’re unsure which to choose, here’s my advice – in a handy flowchart!

Best iOS Conferences in 2016

[Click to see full-size version]

Again, note that this article is my personal opinion only and is based on what I’ve heard from team and community members who have attended these conferences.

Huge thank you to all who took the time to send me their thoughts and quotes about the conferences you attended for this post – I really appreciate it! :]

We’d love to hear your opinion too! Please let us know about your experiences at any iOS conferences you attended in 2016 – it will be really helpful for those trying to decide which to attend.

We hope to see you at some iOS conferences this year!

The post Top 10 iOS Conferences in 2016 appeared first on Ray Wenderlich.

Video Tutorial: iOS App Extensions Part 5: Today Extensions: Getting Started

Alamofire Tutorial: Getting Started

$
0
0
alamofire tutorial

Get the lowdown on Alamofire!

Alamofire is a Swift-based HTTP networking library for iOS and Mac OS X. It provides an elegant interface on top of Apple’s Foundation networking stack that simplifies a number of common networking tasks.

Alamofire provides chainable response/request methods, JSON parameter and response serialization, authentication, and many other features. In this Alamofire tutorial, you’ll use Alamofire to perform basic networking tasks like uploading files and requesting data from a third-party RESTful API.

Alamofire’s elegance comes from the fact it was written from the ground up in Swift and does not inherit anything from its Objective-C counterpart, AFNetworking.

You should have a conceptual understanding of HTTP networking and some exposure to Apple’s networking classes such as NSURLSession and NSURLConnection.

While Alamofire does obscure some implementation details, it’s good to have some background knowledge if you ever need to troubleshoot your network requests. You’ll also need CocoaPods installed to pull Alamofire into the tutorial project.

Getting Started

Download the starter project here.

The app for this Alamofire tutorial is named PhotoTagger; when completed, it will let you select an image from your library (or camera if you’re running on an actual device) and upload the image to a third-party service which will perform some image recognition tasks to come up with a list of tags and primary colors for the image:

alamofire tutorial

Build and run the project in Xcode and you’ll see the following:

alamofire tutorial

Click Select Photo and choose a photo. The background image will be replaced with the image you chose.

Open Main.storyboard and you’ll see the additional screens for displaying tags and colors have been added for you. All that remains is to upload the image and fetch the tags and colors.

The Imagga API

Imagga is an image recognition Platform-as-a-Service that provides image tagging APIs for developers and businesses to build scalable, image-intensive cloud apps. You can play around with a demo of their auto-tagging service here.

You’ll need to create a free developer account with Imagga for this Alamofire tutorial. Imagga requires an authorization header in each HTTP request so only people with an account can use their services. Go to https://imagga.com/auth/signup/hacker and fill out the form. After you create your account, check out the dashboard:

alamofire tutorial

Listed down in the Authorization section is a secret token that you’ll use later. This information needs to be included with every HTTP request as a header.

Note: Make sure you copy the whole secret token, be sure to scroll over to the right and verify you copied everything.

You’ll be using Imagga’s content endpoint to upload the photos, tagging endpoint for the image recognition and colors endpoint for color identification. You can read all about the Imagga API at http://docs.imagga.com.

Installing Dependencies

Create a file named Podfile in the main directory of the project with the following contents:

platform :ios, '9.0'
 
inhibit_all_warnings!
use_frameworks!
 
target 'PhotoTagger' do
  pod 'Alamofire', '~> 3.1.2'
end

Next, install the CocoaPods dependencies with pod install. If you don’t have CocoaPods installed on your machine, check out the How to Use CocoaPods with Swift tutorial for more information.

Close the project and open the newly created PhotoTagger.xcworkspace. Build and run your project – you shouldn’t notice any visual changes in the running app. That’s good – your next task is to add some HTTP calls to a RESTful service to retrieve some JSON.

REST, HTTP, JSON — What’s that?

If you’re coming to this Alamofire tutorial with very little experience in using third-party services over the Internet, you might be wondering what all those acronyms mean! :]

HTTP is the application protocol, or set of rules, that web sites use to transfer data from the web server to your screen. You’ve seen HTTP (or HTTPS) listed in the front of every URL you type into a web browser. You might have heard of other application protocols, such as FTP, Telnet, and SSH. HTTP defines several request methods, or verbs, that the client (your web browser or app) use to indicate the desired action:

  • GET: Used to retrieve data, such as a web page, but doesn’t alter any data on the server.
  • HEAD: Identical to GET but only sends back the headers and none of the actual data.
  • POST: Used to send data to the server, commonly used when filling a form and clicking submit.
  • PUT: Used to send data to the specific location provided.
  • DELETE: Deletes data from the specific location provided.

REST, or REpresentational State Transfer, is a set of rules for designing consistent, easy-to-use and maintainable web APIs. REST has several architecture rules that enforce things such as not persisting states across requests, making requests cacheable, and providing uniform interfaces. This makes it easy for app developers like you to integrate the API into your app — without needing to track the state of data across requests.

JSON stands for JavaScript Object Notation; it provides a straightforward, human-readable and portable mechanism for transporting data between two systems. JSON has a limited number of data types: string, boolean, array, object/dictionary, null and number; there’s no distinction between integers and decimals. Apple supplies the NSJSONSerialization class to help convert your objects in memory to JSON and vice-versa.

The combination of HTTP, REST and JSON make up a good portion of the web services available to you as a developer. Trying to understand how every little piece works can be overwhelming. Libraries like Alamofire can help reduce the complexity of working with these services — and get you up and running faster than you could without its help.

What is Alamofire Good For?

Why do you need Alamofire at all? Apple already provides NSURLSession and other classes for downloading content via HTTP, so why complicate things with another third party library?

The short answer is that Alamofire is based on NSURLSession, but it frees you from writing boilerplate code which makes writing networking code much easier. You can access data on the Internet with very little effort, and your code will be much cleaner and easier to read.

There are several major functions available with Alamofire:

  • .upload: Upload files with multipart, stream, file or data methods.
  • .download: Download files or resume a download that was already in progress.
  • .request: Every other HTTP request not associated with file transfers.

These Alamofire functions are scoped to the module, not to a class or struct. There are underlying pieces to Alamofire that are classes and structs, like Manager, Request, and Response; however, you don’t need to fully understand the entire structure of Alamofire to start using it.

Here’s an example of the same networking operation with both Apple’s NSURLSession and Alamofire’s request function:

// With NSURLSession
public func fetchAllRooms(completion: ([RemoteRoom]?) -> Void) {
  let url = NSURL(string: "http://localhost:5984/rooms/_all_docs?include_docs=true")!
 
  let urlRequest = NSMutableURLRequest(
    URL: url,
    cachePolicy: .ReloadIgnoringLocalAndRemoteCacheData,
    timeoutInterval: 10.0 * 1000)
  urlRequest.HTTPMethod = "GET"
  urlRequest.addValue("application/json", forHTTPHeaderField: "Accept")
 
  let task = urlSession.dataTaskWithRequest(urlRequest)
    { (data, response, error) -> Void in
    guard error == nil else {
      print("Error while fetching remote rooms: \(error)")
      completion(nil)
      return
    }
 
    guard let json = try? NSJSONSerialization.JSONObjectWithData(data!,
      options: []) as? [String: AnyObject] else {
        print("Nil data received from fetchAllRooms service")
        completion(nil)
        return
    }
 
    guard let rows = json["rows"] as? [[String: AnyObject]] {
      print("Malformed data received from fetchAllRooms service")
      completion(nil)
      return
    }
 
    var rooms = [RemoteRoom]()
    for roomDict in rows {
      rooms.append(RemoteRoom(jsonData: roomDict))
    }
 
    completion(rooms)
  }
 
  task.resume()
}

Versus:

// With Alamofire
func fetchAllRooms(completion: ([RemoteRoom]?) -> Void) {
  Alamofire.request(
    .GET,
    "http://localhost:5984/rooms/_all_docs",
    parameters: ["include_docs": "true"],
    encoding: .URL)
    .validate()
    .responseJSON { (response) -> Void in
      guard response.result.isSuccess else {
        print("Error while fetching remote rooms: \(response.result.error)")
        completion(nil)
        return
      }
 
      guard let value = response.result.value as? [String: AnyObject],
        rows = value["rows"] as? [[String: AnyObject]] else {
          print("Malformed data received from fetchAllRooms service")
           completion(nil)
           return
      }
 
      var rooms = [RemoteRoom]()
      for roomDict in rows {
        rooms.append(RemoteRoom(jsonData: roomDict))
      }
 
      completion(rooms)
  }
}

You can see that the required setup for Alamofire is shorter and is much more clear as to what the function does. You deserialize the response with responseJSON(options:completionHandler:) and calling validate() on the Response object simplifies error condition handling.

Uploading Files

Open ViewController.swift and add the following class extension to the end of the file:

// Networking calls
extension ViewController {
  func uploadImage(image: UIImage, progress: (percent: Float) -> Void,
    completion: (tags: [String], colors: [PhotoColor]) -> Void) {
    guard let imageData = UIImageJPEGRepresentation(image, 0.5) else {
      print("Could not get JPEG representation of UIImage")
      return
    }
  }
}

The first step in uploading an image to Imagga is to get the correct format for the API. Above, the Image Picker API returns a UIImage instance that you convert into a JPEG NSData instance.

Next, go to imagePickerController(_:didFinishPickingMediaWithInfo:) and add the following right after the point where you set the image on imageView:

// 1
takePictureButton.hidden = true
progressView.progress = 0.0
progressView.hidden = false
activityIndicatorView.startAnimating()
 
uploadImage(
  image,
  progress: { [unowned self] percent in
    // 2
    self.progressView.setProgress(percent, animated: true)
  },
  completion: { [unowned self] tags, colors in
    // 3
    self.takePictureButton.hidden = false
    self.progressView.hidden = true
    self.activityIndicatorView.stopAnimating()
 
    self.tags = tags
    self.colors = colors
 
    // 4
    self.performSegueWithIdentifier("ShowResults", sender: self)
})

Everything with Alamofire is asynchronous, which means the you’ll update UI in an asynchronous manner:

  1. Hide the upload button, and show the progress view and activity view.
  2. While the file uploads, you call the progress handler with an updated percent. This changes the amount of progress bar showing.
  3. The completion handler executes when the upload finishes. This sets the state on the controls back to their original state.
  4. Finally the Storyboard advances to the results screen after a successful (or unsuccessful) upload. The user interface doesn’t change based on the error condition.

Next add the following to the top of ViewController.swift:

import Alamofire

This lets you use the functionality provided by the Alamofire module in your code.

Next, go back to uploadImage(_:progress:completion:) and add the following after the point where you convert the UIImage instance:

Alamofire.upload(
  .POST,
  "http://api.imagga.com/v1/content",
  headers: ["Authorization" : "Basic xxx"],
  multipartFormData: { multipartFormData in
    multipartFormData.appendBodyPart(data: imageData, name: "imagefile",
      fileName: "image.jpg", mimeType: "image/jpeg")
  },
  encodingCompletion: { encodingResult in
  }
)

Make sure to replace Basic xxx with the actual authorization header taken from the Imagga dashboard. Here you convert the JPEG data blob (imageData) into a MIME multipart request to the Imagga content endpoint.

Next, add the following to the encodingCompletion closure:

switch encodingResult {
case .Success(let upload, _, _):
  upload.progress { bytesWritten, totalBytesWritten, totalBytesExpectedToWrite in
    dispatch_async(dispatch_get_main_queue()) {
      let percent = (Float(totalBytesWritten) / Float(totalBytesExpectedToWrite))
      progress(percent: percent)
    }
  }
  upload.validate()
  upload.responseJSON { response in
  }
case .Failure(let encodingError):
  print(encodingError)
}

This chunk of code calls the Alamofire upload function and passes in a small calculation to update the progress bar as the file uploads. Notice the progress callback is made in a dispatch to the main queue since you’re updating the UI.

Note: Alamofire is not guaranteed to call the progress callback on the main queue; therefore you must guard against updating the UI by dispatching to the main queue. Some of Alamofire’s callbacks, such as responseJSON, are called on the main queue by default. For example:

dispatch_async(queue ?? dispatch_get_main_queue()) {
  let response = ...
  completionHandler(response)
}

To change this default behavior you would provide a dispatch_queue_t to Alamofire.

Next, add the following code to upload.responseJSON:

// 1.
guard response.result.isSuccess else {
  print("Error while uploading file: \(response.result.error)")
  completion(tags: [String](), colors: [PhotoColor]())
  return
}
// 2.
guard let responseJSON = response.result.value as? [String: AnyObject],
  uploadedFiles = responseJSON["uploaded"] as? [AnyObject],
  firstFile = uploadedFiles.first as? [String: AnyObject],
  firstFileID = firstFile["id"] as? String else {
    print("Invalid information received from service")
    completion(tags: [String](), colors: [PhotoColor]())
    return
}
 
print("Content uploaded with ID: \(firstFileID)")
// 3.
completion(tags: [String](), colors: [PhotoColor]())

Here’s a step-by-step explanation of the above code:

  1. Check if the response was successful; if not, print the error and call the completion handler.
  2. Check each portion of the response, verifying the expected type is the actual type received. Retrieve the firstFileID from the response. If firstFileID cannot be resolved, print out an error message and call the completion handler.
  3. Call the completion handler to update the UI. At this point, you don’t have any downloaded tags or colors, so simply call this with empty data.

Note: Every response has a Result enum with a value and type. Using automatic validation, the result is considered a success when it returns a valid HTTP Code between 200 and 299 and the Content Type is of a valid type specified in the Accept HTTP header field.

You can perform manual validation by adding .validate options as shown below:

Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
  .validate(statusCode: 200..<300)
  .validate(contentType: ["application/json"])
  .response { response in
    // response handling code
}

The UI won’t show an error if you hit an error during the upload; it merely returns no tags or colors to the user. This isn’t the best user experience, but it’s fine for this Alamofire tutorial.

Build and run your project; select an image and watch the progress bar change as the file uploads. You should see a note like the following in your console when the upload completes:

ImaggaUploadConsole

You’ve successfully uploaded a file over the Interwebs!

sad-forever-alone-happy

Retrieving Data

The next step after uploading the image to Imagga is to fetch the tags Imagga produces after it analyzes the photo.

Add the following method to the ViewController extension below uploadImage(_:progress:completion:):

func downloadTags(contentID: String, completion: ([String]) -> Void) {
  Alamofire.request(
    .GET,
    "http://api.imagga.com/v1/tagging",
    parameters: ["content": contentID],
    headers: ["Authorization" : "Basic xxx"]
    )
    .responseJSON { response in
      guard response.result.isSuccess else {
        print("Error while fetching tags: \(response.result.error)")
        completion([String]())
        return
      }
 
      guard let responseJSON = response.result.value as? [String: AnyObject] else {
         print("Invalid tag information received from service")
         completion([String]())
         return
      }
      print(responseJSON)
      completion([String]())
  }
}

Again, be sure to replace Basic xxx with your actual authorization header. Here you perform an HTTP GET request against the tagging endpoint, sending the URL parameter content with the ID you received after the upload.

Next, go back to uploadImage(_:progress:completion:) and replace the call to the completion handler in the success condition with the following:

self.downloadTags(firstFileID) { tags in
  completion(tags: tags, colors: [PhotoColor]())
}

This simply sends along the tags to the completion handler.

Build and run your project; upload a file and you’ll see a dump of the data in the console:

alamofire tutorial

You don’t care about the confidence score for this Alamofire tutorial, only the array of tag names.

Next, go back to downloadTags(_:completion:) and replace the code inside .responseJSON with the following:

// 1.
guard response.result.isSuccess else {
  print("Error while fetching tags: \(response.result.error)")
  completion([String]())
  return
}
 
// 2.
guard let responseJSON = response.result.value as? [String: AnyObject],
  results = responseJSON["results"] as? [AnyObject],
  firstResult = results.first,
  tagsAndConfidences = firstResult["tags"] as? [[String: AnyObject]] else {
    print("Invalid tag information received from the service")
    completion([String]())
    return
}
 
// 3.
let tags = tagsAndConfidences.flatMap({ dict in
  return dict["tag"] as? String
})
 
// 4.
completion(tags)

Here’s a step-by-step explanation of the above code:

  1. Check if the response was successful; if not, print the error and call the completion handler.
  2. Check each portion of the response, verifying the expected type is the actual type received. Retrieve the tagsAndConfidences information from the response. If tagsAndConfidences cannot be resolved, print out an error message and call the completion handler.
  3. Iterate over each dictionary object in the tagsAndConfidences array, retrieving the value associated with the tag key.
  4. Call the completion handler passing in the tags received from the service.

Note: You’re using the Swift flatMap method to iterate over each dictionary in the tagsAndConfidences array; this method handles nil values without crashing and will remove those values from the returned result. This lets you use conditional unwrapping (as?) to verify whether the dictionary value can be converted to a String.

Build and run your project again; select a photo and you should see the following appear:

alamofire tutorial

Pretty slick! That Immaga is one smart API. :] Next, you’ll fetch the colors of the image.

Add the following method to the ViewController extension below downloadTags(_:completion:):

func downloadColors(contentID: String, completion: ([PhotoColor]) -> Void) {
  Alamofire.request(
    .GET,
    "http://api.imagga.com/v1/colors",
    parameters: ["content": contentID, "extract_object_colors": NSNumber(int: 0)],
    // 1.
    headers: ["Authorization" : "Basic xxx"]
    )
    .responseJSON { response in
      // 2.
      guard response.result.isSuccess else {
        print("Error while fetching colors: \(response.result.error)")
        completion([PhotoColor]())
        return
      }
 
      // 3.
      guard let responseJSON = response.result.value as? [String: AnyObject],
        results = responseJSON["results"] as? [AnyObject],
        firstResult = results.first as? [String: AnyObject],
        info = firstResult["info"] as? [String: AnyObject],
        imageColors = info["image_colors"] as? [[String: AnyObject]] else {
          print("Invalid color information received from service")
          completion([PhotoColor]())
          return
      }
 
      // 4.
      let photoColors = imageColors.flatMap({ (dict) -> PhotoColor? in
        guard let r = dict["r"] as? String,
          g = dict["g"] as? String,
          b = dict["b"] as? String,
          closestPaletteColor = dict["closest_palette_color"] as? String else {
            return nil
        }
        return PhotoColor(red: Int(r),
          green: Int(g),
          blue: Int(b),
          colorName: closestPaletteColor)
      })
 
      // 5.
      completion(photoColors)
  }
}

Taking each numbered comment in turn:

  1. Be sure to replace Basic xxx with your actual authorization header.
  2. Check that the response was successful; if not, print the error and call the completion handler.
  3. Check each portion of the response, verifying the expected type is the actual type received. Retrieve the imageColors information from the response. If imageColors cannot be resolved, print out an error message and call the completion handler.
  4. Using flatMap again, you iterate over the returned imageColors, transforming the data into PhotoColor objects which pairs colors in the RGB format with the color name as a string. Note the provided closure allows returning nil values since flatMap will simply ignore them.
  5. Call the completion handler, passing in the photoColors from the service.

Finally, go back to uploadImage(_:progress:completion:) and replace the call to the completion handler in the success condition with the following:

self.downloadTags(firstFileID) { tags in
  self.downloadColors(firstFileID) { colors in
    completion(tags: tags, colors: colors)
  }
}

This nests the operations of uploading the image, downloading tags and downloading colors.

Build and run your project again; this time, you should see the returned color tags:

alamofire tutorial

You use the RGB colors you mapped to PhotoColor structs to change the background color of the view. You’ve now successfully uploaded an image to Imagga and fetched data from two different endpoints. You’ve come a long way — but there’s some room for improvement in how you’re using Alamofire in PhotoTagger.

Improving PhotoTagger

You probably noticed some repeated code in PhotoTagger. If Imagga released v2 of their API and deprecated v1, PhotoTagger would no longer function and you’d have to update the URL in each of the three methods. Similarly, if your authorization token changed you’d be updating it all over the place.

Alamofire provides a simple method to eliminate this code duplication and provide centralized configuration. The technique involves creating a struct conforming to the URLRequestConvertible protocol and updating your upload and request calls.

Create a new Swift file by clicking File\New\File… and selecting Swift file under iOS. Click Next, name the file ImaggaRouter.swift, select the Group PhotoTagger with the yellow folder icon and click Create.

Replace the contents of your new file with the following:

import Foundation
import Alamofire
 
public enum ImaggaRouter: URLRequestConvertible {
  static let baseURLPath = "http://api.imagga.com/v1"
  static let authenticationToken = "Basic xxx"
 
  case Content
  case Tags(String)
  case Colors(String)
 
  public var URLRequest: NSMutableURLRequest {
    let result: (path: String, method: Alamofire.Method, parameters: [String: AnyObject]) = {
      switch self {
      case .Content:
        return ("/content", .POST, [String: AnyObject]())
      case .Tags(let contentID):
        let params = [ "content" : contentID ]
        return ("/tagging", .GET, params)
      case .Colors(let contentID):
        let params = [ "content" : contentID, "extract_object_colors" : NSNumber(int: 0) ]
        return ("/colors", .GET, params)
      }
    }()
 
    let URL = NSURL(string: ImaggaRouter.baseURLPath)!
    let URLRequest = NSMutableURLRequest(URL: URL.URLByAppendingPathComponent(result.path))
    URLRequest.HTTPMethod = result.method.rawValue
    URLRequest.setValue(ImaggaRouter.authenticationToken, forHTTPHeaderField: "Authorization")
    URLRequest.timeoutInterval = NSTimeInterval(10 * 1000)
 
    let encoding = Alamofire.ParameterEncoding.URL
 
    return encoding.encode(URLRequest, parameters: result.parameters).0
  }
}

Replace Basic xxx with your actual authorization header. This router helps create instances of NSMutableURLRequest by providing it one of the three cases: .Content, .Tags(String), or .Colors(String). Now all of your boilerplate code is in single place, should you ever need to update it.

Go back to uploadImage(_:progress:completion:) and replace the beginning of the call to Alamofire.upload with the following:

Alamofire.upload(
  ImaggaRouter.Content,
  multipartFormData: { multipartFormData in
    multipartFormData.appendBodyPart(data: imageData, name: "imagefile",
      fileName: "image.jpg", mimeType: "image/jpeg")
},
/// original code continues...

Next replace the call for Alamofire.request in downloadTags(_:completion:) with:

Alamofire.request(ImaggaRouter.Tags(contentID))

Finally, update the call to Alamofire.request in downloadColors(_:completion:) with:

Alamofire.request(ImaggaRouter.Colors(contentID))

Build and run for the final time; everything should function just as before, which means you’ve refactored everything without breaking your app. Awesome job!

Where To Go From Here?

You can download the completed version of this Alamofire tutorial’s project here. Don’t forget to replace your authorization token as appropriate!

This Alamofire tutorial covered the very basics. You can take a deeper dive by looking at the documentation on the Alamofire site at https://github.com/Alamofire/Alamofire.

Also, you can take some time to learn more about Apple’s NSURLSession which Alamofire uses under the hood:

Please share any comments or questions about this Alamofire tutorial in the forum discussion below!

The post Alamofire Tutorial: Getting Started appeared first on Ray Wenderlich.

Video Tutorial: iOS App Extensions Part 6: Today Extensions: Layout


Open Call For Applications: OS X Tech Editors

$
0
0

OpenCall-OSX-feature

Over the past few months, we’ve received some great applications from folks interested in joining the tutorial team, but unfortunately we’re currently at capacity.

However, there’s some good news – currently we have a few openings for OS X Tech Editors!

As an OS X tech editor, your role is incredibly important. You are the guardian that makes sure that each tutorial that comes out of our team is top-notch.

Not only does this help our readers get great tutorials, but it helps the rest of the team as well. As experienced developers and authors, you are helping our more junior team members improve through your improvements and comments on their work.

In our experience, our tech editors are often our very best writers and developers, and we treat them with the utmost regard. Tech editors are usually first in line for any book projects and special opportunities on our site.

Why Be an OS X Tech Editor?

Here are the top 5 reasons to apply as an OS X Tech Editor:

  1. Learning. You’ll always be learning something new – and will have fun doing it! You’ll become a better developer, writer, and person, and make a lot of new friends along the way.
  2. Money! Get paid to learn! We offer the highest rates in the industry.
  3. Special Opportunities. Members of the Tutorial Team get access to special opportunities such as contributing to our books and products, speaking at our conference, being a guest on our podcast, working on team projects, and much more.
  4. You’ll Make a Difference. We get emails every day about how our tutorials help our readers make their first app, get their dream job, or accomplish a lifelong dream of making their own game. This means a lot to us and makes all the hard work worth it!
  5. Free Stuff! And as a final bonus, by joining the Tutorial Team you will get a lot of free stuff! You’ll get a free copy of all of the products we sell on the site – over $1,000 in value!

Aww Yeah!

Requirements and How to Apply

Here are the requirements:

  • You must be an advanced-level OS X developer.
  • You should be a great writer with fluent English writing skills.
  • You should be comfortable learning brand new topics that you have never done before, which are either not documented or poorly documented.
  • You should have a strong work ethic – this will be a significant time commitment and is not easy.

To appply, send our OS X Team Lead Matthew Morey an email , with the following details:

  • Why do you want to be an OS X Tech Editor?
  • Please tell me a little bit about yourself and your experience.
  • What is the best app/game you’ve made or worked on, and why are you proud of the work you did on this app/game? [Please include link]
  • Please link to any examples of technical writing you have done in the past.
  • Please include links to: your GitHub account, your StackOverflow account, your Twitter account.

For the applicants that look most promising, we will give you a tryout. If you pass the tryout, you’re in!

Now’s The Time

If you’ve ever been thinking about joining the Tutorial Team in the past, and have some OS X experience, this is a great time. We could really use the help, and we may have a secret project around the corner that you could get in on the ground floor :]

Thanks all – Matt, the OS X Team, and I look forward to creating some great tutorials with you! :]

The post Open Call For Applications: OS X Tech Editors appeared first on Ray Wenderlich.

Video Tutorial: iOS App Extensions Part 7: Today Extensions: Core Data

SQLite Tutorial: Getting Started

$
0
0
sqlite tutorial

Curious ’bout using the SQLite C APIs from Swift? Then read on…

In the world of software development, it doesn’t take long before you need to persist app data. In many cases, this comes in the form of data structures. But how do you store it effectively — and efficiently?

Fortunately, some great minds have developed solutions for storing structured data in databases and writing language features to access that data. This SQLite tutorial shows you how to work with the popular database platform SQLite, from within Swift. SQLite is available by default on iOS; if you’re familiar with Core Data, you’ll know SQLite is the most common way to persist object graphs in Core Data.

Throughout this SQLite tutorial, you’ll learn how to perform the following database operations:

  • Create and connect to a database
  • Create a table
  • Insert a row
  • Update a row
  • Delete a row
  • Query the database
  • Handle SQLite errors

After learning how to perform these fundamental operations, you’ll see how to wrap them up in a more Swift-like manner. This will let you write abstraction APIs for your apps so that you can (mostly) avoid the pain of working with the SQLite C APIs! :]

Finally, I’ll briefly cover the popular open source Swift wrapper SQLite.swift to give you a basic understanding of how underlying frameworks work within a wrapper.

Note: Databases, and even just SQLite on its own, are massive topics to cover, so they’re mostly out of scope for this tutorial. It’s assumed that you have a basic understanding of relational database ideology and that you’re primarily here to learn how to use SQLite in conjunction Swift.

Getting Started

Download the starter project for this SQLite tutorial and open SQLiteTutorial.xcworkspace. From the Project Navigator open Tutorial.playground. You’ll immediately notice an error message on the line import SQLite. You’ll need to build the project at least once by pressing Command + B; this is because the workspace is configured to create a module so that SQLite can be used in the playground.

Note: Don’t be mislead by the import SQLite line. SQLite is not a proper module, and you won’t be able to call import SQLite like this in your projects; instead you’ll use a bridging header.

With the playground open, set it to run manually instead of automatically:

sqlite tutorial

This will help ensure your SQL commands run when you intend them to.

You might also see a destroyPart1Database() call at the top of the page; you can safely ignore this, since the database file is destroyed each time the playground runs. This ensures all statements execute successfully as you move through this SQLite tutorial.

Your playground will need somewhere to write SQLite database files on your file system. Run the following command in Terminal to create the data directory for your playground:

mkdir -p ~/Documents/Shared\ Playground\ Data/SQLiteTutorial

Why Should I Choose SQLite?

True, SQLite isn’t the only way to persist data on iOS. Besides Core Data, there are lots of other alternatives for data persistence, including Realm, Couchbase Lite, Firebase, and NSCoding.

Each of these has their own pros and cons — including SQLite itself. There’s no silver bullet for data persistence, and as the developer, it’s up to you to determine which option outweighs the others based on your app’s requirements.

SQLite does have some advantages:

  • Shipped with iOS so it adds no overhead to your app’s bundle
  • Tried and tested; version 1.0 was released in August 2000
  • Open source
  • Familiar query language for database developers and admins
  • Cross-platform

The cons of SQLite can be terribly subjective and opinionated, so we’ll leave the research on that up to you! :]

The C API

This part of the SQLite tutorial will walk you through the most common and basic SQLite APIs. You’ll soon realize that wrapping the C API in Swift methods would be ideal, but sit tight and work through the C code first; you’ll do some wrapping in the second part of this SQLite tutorial.

Opening a Connection

Before doing anything, you’ll first need to create a database connection.

Add the following method under the Getting Started section of the playground:

func openDatabase() -> COpaquePointer {
  var db: COpaquePointer = nil
  if sqlite3_open(part1DbPath, &db) == SQLITE_OK {
    print("Successfully opened connection to database at \(part1DbPath)")
    return db
  } else {
    print("Unable to open database. Verify that you created the directory described " +
      "in the Getting Started section.")
    XCPlaygroundPage.currentPage.finishExecution()
  }
}

The above method calls sqlite3_open(), which opens or creates a new database file. If it’s successful, it returns a COpaquePointer; this is a Swift type for C pointers that can’t be represented directly in Swift. When you call this method, you’ll have to capture the returned pointer in order to interact with the database.

Many of the SQLite functions return an Int32 result code. Most of these codes are defined as constants in the SQLite library. For example, SQLITE_OK represents the result code 0. A list of the different result codes can be found on the main SQLite site.

To open the database, add the following line to your playground:

let db = openDatabase()

Press the Play button to run the playground and watch the console output. If the console isn’t open, press the button to the left of the play button:

sqlite tutorial

If openDatabase() succeeds, you’ll see some output like the following:

Successfully opened connection to database at /Users/username/Documents/Shared Playground Data/SQLiteTutorial/Part1.sqlite

Where username is your Home directory.

Creating a Table

Now that you have a connection to a database file, you can create a table. You’ll work with a very simple table to store contacts.

The table will consist of two columns; Id, which is an INT and a PRIMARY KEY; and Name, which is a CHAR(255).

sqlite tutorial

Add the following string, which contains the SQL statement necessary to create the table:

let createTableString = "CREATE TABLE Contact(" +
  "Id INT PRIMARY KEY NOT NULL," +
  "Name CHAR(255));"

Next, add this method that executes the CREATE TABLE SQL statement:

func createTable() {
  // 1
  var createTableStatement: COpaquePointer = nil
  // 2
  if sqlite3_prepare_v2(db, createTableString, -1, &createTableStatement, nil) == SQLITE_OK {
    // 3
    if sqlite3_step(createTableStatement) == SQLITE_DONE {
      print("Contact table created.")
    } else {
      print("Contact table could not be created.")
    }
  } else {
    print("CREATE TABLE statement could not be prepared.")
  }
  // 4
  sqlite3_finalize(createTableStatement)
}

Going over this step-by-step:

  1. First, you create a pointer to reference in step 2.
  2. sqlite3_prepare_v2() compiles the SQL statement into byte code and returns a status code — an important step before executing arbitrary statements against your database. If you’re interested, you can find out more here. You check the returned status code to ensure the statement compiled successfully. If so, the process moves to step 3; otherwise, you print a message noting the statement could not be compiled.
  3. sqlite3_step() runs the compiled statement. In this case, you only “step” once as this statement has a single result. Later in this SQLite tutorial you’ll see when it’s necessary to step multiple times for a single statement.
  4. You must always call sqlite3_finalize() on your compiled statement to delete it and avoid resource leaks. Once a statement has been finalized, you should never use it again.

Now, add the following method call to the playground:

createTable()

Run your playground; you should see the following appear in your console output:

Contact table created.

Now that you have a table, it’s time to add some data to it. You’re going to add a single row with an Id of 1 and Name of Ray.

Inserting Some Data

Add the following SQL statement to the bottom of your playground:

let insertStatementString = "INSERT INTO Contact (Id, Name) VALUES (?, ?);"

This might look a little strange if you haven’t had much SQL experience. Why are the values represented by question marks?

Remember above when you used sqlite3_prepare_v2() to compile your statement? The ? syntax tells the compiler that you’ll provide real values when you actually execute the statement.

This has performance considerations, and lets you compile statements ahead of time, which can be a performance gain since compilation is a costly operation. The compiled statements can then be re-used over and over with different values.

Next, create the following method in your playground:

func insert() {
  var insertStatement: COpaquePointer = nil
 
  // 1
  if sqlite3_prepare_v2(db, insertStatementString, -1, &insertStatement, nil) == SQLITE_OK {
    let id: Int32 = 1
    let name: NSString = "Ray"
 
    // 2
    sqlite3_bind_int(insertStatement, 1, id)
    // 3
    sqlite3_bind_text(insertStatement, 2, name.UTF8String, -1, nil)
 
    // 4
    if sqlite3_step(insertStatement) == SQLITE_DONE {
      print("Successfully inserted row.")
    } else {
      print("Could not insert row.")
    }
  } else {
    print("INSERT statement could not be prepared.")
  }
  // 5
  sqlite3_finalize(insertStatement)
}

Here’s how the above method works:

  1. First, compile the statement and verify that all is well;
  2. Here, you define a value for the ? placeholder. The function’s name — sqlite3_bind_int() — implies you’re binding an Int value to the statement. The first parameter of the function is the statement to bind to, while the second is a non-zero based index for the position of the ? you’re binding to. The third and final parameter is the value itself. This binding call returns a status code, but for now you assume that it succeeds;
  3. Perform the same binding process, but this time for a text value. There are two additional parameters on this call; for the purposes of this SQLite tutorial you can simply pass -1 and nil for both. If you’d like, you can read more about binding parameters here;
  4. Use the sqlite3_step() function to execute the statement and verify that it finished;
  5. As always, finalize the statement. If you were going to insert multiple contacts, you’d likely retain the statement and re-use it with different values.

Next, call your new method by adding the following to the playground:

insert()

Run your playground and verify that you see the following in your console output:

Successfully inserted row.

Challenge: Multiple Inserts

Challenge time! Your task is to update insert() to insert an array of contacts.

As a hint, you’ll need to reset your compiled statement back to its initial state by calling sqlite3_reset() before you execute it again.

Solution Inside: Solution — Insert multiple rows SelectShow>

Querying Contacts

Now that you’ve inserted a row or two, it sure would be nice to verify that it’s really there! :]

Add the following to the playground:

let queryStatementString = "SELECT * FROM Contact;"

This query simply retrieves all records FROM the contact table. Using a * means all columns will be returned.

Add the following method to perform the query:

func query() {
  var queryStatement: COpaquePointer = nil
  // 1
  if sqlite3_prepare_v2(db, queryStatementString, -1, &queryStatement, nil) == SQLITE_OK {
    // 2
    if sqlite3_step(queryStatement) == SQLITE_ROW {
      // 3
      let id = sqlite3_column_int(queryStatement, 0)
 
      // 4
      let queryResultCol1 = sqlite3_column_text(queryStatement, 1)
      let name = String.fromCString(UnsafePointer<CChar>(queryResultCol1))!
 
      // 5
      print("Query Result:")
      print("\(id) | \(name)")
 
    } else {
      print("Query returned no results")
    }
  } else {
    print("SELECT statement could not be prepared")
  }
 
  // 6
  sqlite3_finalize(queryStatement)
}

Taking each numbered comment in turn:

  1. Prepare the statement;
  2. Execute the statement. Note that you’re now checking for the status code SQLITE_ROW, which means that you retrieved a row when you stepped through the result;
  3. It’s time to read values from the returned row. Given what you know about the table’s structure and your query, you can access the row’s values column by column. The first column is an Int, so you use sqlite3_column_int() and pass in the statement and a zero-based column index. You assign the returned value to the locally-scoped id constant;
  4. Next, you fetch the text value from the Name column. This is a bit messy due to the C API. First, you capture the value as queryResultCol1 so you can convert it to a proper Swift string on the next line;
  5. Print out the results;
  6. Finalize the statement.

Now, call your new method by adding the following to the bottom of the playground:

query()

Run your playground; you’ll see the following output in your console:

Query Result:
1 | Ray

W00t! It looks like your data made it into the database after all!

Challenge: Printing Every Row

Your task is to update query() to print out every contact in the table.

Solution Inside: Solution — Print all contacts SelectShow>

Updating Contacts

The next natural progression is to update an existing row. You should start to feel some patterns emerging.

First, create the UPDATE statement:

let updateStatementString = "UPDATE Contact SET Name = 'Chris' WHERE Id = 1;"

Here you’re using real values instead of ? placeholders. Usually you’d use the placeholders and perform proper statement binding, but for brevity you can skip it here.

Next, add the following method to the playground:

func update() {
  var updateStatement: COpaquePointer = nil
  if sqlite3_prepare_v2(db, updateStatementString, -1, &updateStatement, nil) == SQLITE_OK {
    if sqlite3_step(updateStatement) == SQLITE_DONE {
      print("Successfully updated row.")
    } else {
      print("Could not update row.")
    }
  } else {
    print("UPDATE statement could not be prepared")
  }
  sqlite3_finalize(updateStatement)
}

This is a similar flow to what you’ve seen before: prepare, step, finalize! Now execute this method, followed by your query() method from before, so you can see the results:

update()
query()

You should see the following output in your console:

Successfully updated row.
Query Result:
1 | Chris

Congratulations on updating your first row! How easy was that? :]

Deleting Contacts

The final step on the path to becoming an SQLite ninja is to delete the row you created. Again, you’ll use the familiar pattern of prepare, step, and finalize.

Add the following to the playground:

let deleteStatementStirng = "DELETE FROM Contact WHERE Id = 1;"

Now add the following method to execute the statement:

func delete() {
  var deleteStatement: COpaquePointer = nil
  if sqlite3_prepare_v2(db, deleteStatementStirng, -1, &deleteStatement, nil) == SQLITE_OK {
    if sqlite3_step(deleteStatement) == SQLITE_DONE {
      print("Successfully deleted row.")
    } else {
      print("Could not delete row.")
    }
  } else {
    print("DELETE statement could not be prepared")
  }
 
  sqlite3_finalize(deleteStatement)
}

Are you feeling it now? Prepare, step, and finalize! :]

Execute this new method, followed a call to query(), like so:

delete()
query()

Now run your playground and you should see the following output in your console:

Successfully deleted row.
Query returned no results
Note: If you completed the Multiple Inserts challenge above, it’s likely the output will look a little different to that above due to rows still being present in the table.

Handling Errors

Hopefully, you’ve managed to avoid SQLite errors up to this point. But the time will come when you make a call that doesn’t make sense, or simply cannot be compiled.

Handling the error message when these things happen can save you a lot of development time; it also gives you the opportunity to present meaningful error messages to your users.

Add the following statement – which is intentionally malformed – to your playground:

let malformedQueryString = "SELECT Stuff from Things WHERE Whatever;"

Now add a method to execute this malformed statement:

func prepareMalformedQuery() {
  var malformedStatement: COpaquePointer = nil
  // 1
  if sqlite3_prepare_v2(db, malformedQueryString, -1, &malformedStatement, nil) == SQLITE_OK {
    print("This should not have happened.")
  } else {
    // 2
    let errorMessage = String.fromCString(sqlite3_errmsg(db))!
    print("Query could not be prepared! \(errorMessage)")
  }
 
  // 3
  sqlite3_finalize(malformedStatement)
}

Here’s how you’re going to force an error:

  1. Prepare the statement, which will fail and should NOT return SQLITE_OK;
  2. Get the error message from the database using sqlite3_errmsg(). This function returns a textual description of the most recent error. You then print the error to the console;
  3. As always, finalize.

Call the method to see the error message:

prepareMalformedQuery()

Run your playground; you should see the following output in your console:

Query could not be prepared! no such table: Things

Well, that’s actually helpful — you obviously cannot run a SELECT statement on a table that doesn’t exist!

Closing the Database Connection

When you’re done with a database connection, you’re responsible for closing it. But beware — there are a number of things you must have performed before closing your database will succeed, as described in the SQLite documentation.

Call the close function as shown below:

sqlite3_close(db)

Run your playground; you should see a status code of 0 in the right side results view of the playground; this represents SQLITE_OK, which means your close call succeeded.

You’ve successfully created a database, added a table, added rows to the table, queried and updated those rows, and even deleted a row — all using the SQLite C APIs from Swift. Great job!

In the next section, you’ll take what you’ve learned and see how to wrap some of these calls in Swift.

Wrapping the C API in Swift

As a Swift developer, you’re probably feeling a little uneasy about what happened in the first part of this SQLite tutorial. That C API is a bit painful, but the good news is you can take the power of Swift and wrap those C routines to make things easier for yourself.

sqlite tutorial

For this part of the SQLite tutorial, click the Making it Swift link at the bottom of the playground to open the playground for this section:

sqlite tutorial

Wrapping Errors

Getting at errors from the C API is a bit awkward as a Swift developer. Checking a result code and then calling another method just doesn’t make sense in this brave new world. It would make more sense if methods that can fail throw an error.

Add the following to your playground:

enum SQLiteError: ErrorType {
  case OpenDatabase(message: String)
  case Prepare(message: String)
  case Step(message: String)
  case Bind(message: String)
}

This is a custom ErrorType enum that covers four of the main operations you are using that can fail. Note how each case has an associated value that will hold the error message.

Wrapping the Database Connection

Another not-so-Swifty aspect is the use of those blasted COpaquePointer types.

Wrap up the database connection pointer in its own class, as shown below:

class SQLiteDatabase {
  private let dbPointer: COpaquePointer
 
  private init(dbPointer: COpaquePointer) {
    self.dbPointer = dbPointer
  }
 
  deinit {
    sqlite3_close(dbPointer)
  }
}

This looks much better. When you need a database connection, you can create a reference to a more meaningful type of SQLiteDatabase rather than COpaquePointer.

You’ll notice the initializer is private; that’s because you don’t want your Swift developers passing in that COpaquePointer. Instead, you let them instantiate this class with a path to the database file.

Add the following static method to SQLiteDatabase as follows:

static func open(path: String) throws -> SQLiteDatabase {
  var db: COpaquePointer = nil
  // 1
  if sqlite3_open(path, &db) == SQLITE_OK {
    // 2
    return SQLiteDatabase(dbPointer: db)
  } else {
    // 3
    defer {
      if db != nil {
        sqlite3_close(db)
      }
    }
 
    if let message = String.fromCString(sqlite3_errmsg(db)) {
      throw SQLiteError.OpenDatabase(message: message)
    } else {
      throw SQLiteError.OpenDatabase(message: "No error message provided from sqlite.")
    }
  }
}

Here’s what happening:

  1. Attempt to open the database at the provided path;
  2. If successful, return a new instance of SQLiteDatabase;
  3. Otherwise, defer closing the database if the status code is anything but SQLITE_OK and throw an error.

Now you can create and open a database connection using much cleaner syntax.

Add the following to your playground:

let db: SQLiteDatabase
do {
  db = try SQLiteDatabase.open(part2DbPath)
  print("Successfully opened connection to database.")
} catch SQLiteError.OpenDatabase(let message) {
  print("Unable to open database. Verify that you created the directory described in the Getting Started section.")
  XCPlaygroundPage.currentPage.finishExecution()
}

Ah, much more Swift like. Here, the attempt to open the database is wrapped in a do-try-catch block, and the error message from SQLite is passed to the catch block thanks to that custom enum you added earlier.

Run your playground and watch the console output; you’ll see something like the following:

Successfully opened connection to database.

Now you can use and inspect the db instance as a proper and meaningful type.

Before moving on to writing methods that execute statements, it would be nice if SQLiteDatabase let you easily access SQLite error messages.

Add the following computed property to SQLiteDatabase:

private var errorMessage: String {
  if let errorMessage = String.fromCString(sqlite3_errmsg(dbPointer)) {
    return errorMessage
  } else {
    return "No error message provided from sqlite."
  }
}

Here you’ve added a computed property that simply returns the most recent error SQLite knows about. If there is no error, it just returns a generic message stating as much.

Wrapping the Prepare Call

Since you do this so often, it makes sense to wrap it like the other methods. As you move forward and add functionality to the SQLiteDatabase class, you’ll make use class extensions.

Add the following extension, which will be used by your future methods, to invoke sqlite3_prepare_v2() on SQL statements:

extension SQLiteDatabase {
  func prepareStatement(sql: String) throws -> COpaquePointer {
    var statement: COpaquePointer = nil
    guard sqlite3_prepare_v2(dbPointer, sql, -1, &statement, nil) == SQLITE_OK else {
      throw SQLiteError.Prepare(message: errorMessage)
    }
 
    return statement
  }
}

Here you declare that prepareStatement(_:) can throw an error, and then use guard to throw that error should sqlite3_prepare_v2() fail. Just like before, you pass the error message from SQLite to the relevant case of your custom enum.

Creating a Contact Struct

In these examples, you’ll use the same Contact table as before, so it makes sense to define a proper struct to represent a contact. I’ve already defined the following one for you in this Playground, so you don’t need to add it:

struct Contact {
  let id: Int32
  let name: String
}

Wrapping the Table Creation

You’ll knock out the same database tasks as before, but this time you’ll use a “Swifter” approach.

To create a table, you need a CREATE TABLE SQL statement. It makes sense for Contact to define its own CREATE TABLE statement.

Create the following protocol for just that purpose:

protocol SQLTable {
  static var createStatement: String { get }
}

Now, extend Contact to provide conformance to this new protocol:

extension Contact: SQLTable {
  static var createStatement: String {
    return "CREATE TABLE Contact(" +
      "Id INT PRIMARY KEY NOT NULL," +
      "Name CHAR(255)" +
    ");"
  }
}

Now you’re able to write the following method that accepts types that conform to SQLTable to create a table:

extension SQLiteDatabase {
  func createTable(table: SQLTable.Type) throws {
    // 1
    let createTableStatement = try prepareStatement(table.createStatement)
    // 2
    defer {
      sqlite3_finalize(createTableStatement)
    }
    // 3
    guard sqlite3_step(createTableStatement) == SQLITE_DONE else {
      throw SQLiteError.Step(message: errorMessage)
    }
    print("\(table) table created.")
  }
}

Here’s a breakdown of what’s happening:

  1. prepareStatement() throws, so you must use try. You’re not doing this in a do-try-catch block because this method itself throws, so any error from prepareStatement() will simply be thrown to the caller of createTable();
  2. With the power of defer, you can ensure that your statements are always finalized, regardless of how this method exits its scope;
  3. guard lets you write a more expressive check for the SQLite status codes.

Give your new method a try, and add the following to your playground:

do {
  try db.createTable(Contact)
} catch {
  print(db.errorMessage)
}

Here you simply attempt to create the Contact, and catch the error if there is one.

Run your playground; you should see the following appear in your console:

Contact table created.

Fantastic! Isn’t that a much cleaner API to work with?

Wrapping Insertions

Moving right along, it’s time to insert a row into the Contact table. Add the following method:

extension SQLiteDatabase {
  func insertContact(contact: Contact) throws {
    let insertSql = "INSERT INTO Contact (Id, Name) VALUES (?, ?);"
    let insertStatement = try prepareStatement(insertSql)
    defer {
      sqlite3_finalize(insertStatement)
    }
 
    let name: NSString = contact.name
    guard sqlite3_bind_int(insertStatement, 1, contact.id) == SQLITE_OK  &&
      sqlite3_bind_text(insertStatement, 2, name.UTF8String, -1, nil) == SQLITE_OK else {
        throw SQLiteError.Bind(message: errorMessage)
    }
 
    guard sqlite3_step(insertStatement) == SQLITE_DONE else {
      throw SQLiteError.Step(message: errorMessage)
    }
 
    print("Successfully inserted row.")
  }
}

Now that you’ve got your SQLegs – see what I did there? :] – this code shouldn’t be too surprising. Given a Contact instance, you prepare a statement, bind the values, execute and finalize. Again, using a potent mix of defer, guard and throw allows you to take advantage of modern Swift language features.

Write the code to call this new method as shown below:

do {
  try db.insertContact(Contact(id: 1, name: "Ray"))
} catch {
  print(db.errorMessage)
}

Run your playground; you should see the following in your console:

Successfully inserted row.

Wrapping Reads

Wrapping up (sorry, I couldn’t resist!) the section on creating the Swift wrapper is querying the database.

Add the following method to query the database for a contact:

extension SQLiteDatabase {
  func contact(id: Int32) -> Contact? {
    let querySql = "SELECT * FROM Contact WHERE Id = ?;"
    guard let queryStatement = try? prepareStatement(querySql) else {
      return nil
    }
 
    defer {
      sqlite3_finalize(queryStatement)
    }
 
    guard sqlite3_bind_int(queryStatement, 1, id) == SQLITE_OK else {
      return nil
    }
 
    guard sqlite3_step(queryStatement) == SQLITE_ROW else {
      return nil
    }
 
    let id = sqlite3_column_int(queryStatement, 0)
 
    let queryResultCol1 = sqlite3_column_text(queryStatement, 1)
    let name = String.fromCString(UnsafePointer<CChar>(queryResultCol1))!
 
    return Contact(id: id, name: name)
  }
}

This method simply takes the id of a contact and either returns that contact, or nil if there isn’t a contact with that id. Again, these statements should feel somewhat familiar by now.

Write the code to query the first contact:

let first = db.contact(1)
print("\(first)")

Run your playground; you should see the following output in the console:

Optional(1 | Ray)

By now, you’ve probably identified some calls you could create in a generic fashion and apply them to entirely different tables. The point of the above exercise is to show how you can use Swift to wrap low-level C APIs. This is no simple task for SQLite; there are a ton of intricacies to SQLite that were not covered here.

You might be thinking “Hasn’t someone already created a wrapper for this?” – let me answer that for you right now!

Introducing SQLite.swift

Stephen Celis has graciously written a fully-featured Swift wrapper for SQLite named SQLite.swift. I highly recommend that you check it out if you decide that SQLite fits the bill for data storage in your app.

SQLite.swift provides an expressive way to represent tables and lets you get started with SQLite — without worrying about many of the underlying details and idiosyncrasies of SQLite. You may even consider wrapping SQLite.swift itself to create a high-level API for your app’s domain model.

Check out the well-written README.md for SQLite.swift and decide for yourself if it has a place in your personal code toolbox.

Where to Go From Here?

What about those other common tasks that were skipped over in the Swift section? You can download the completed project for this SQLite tutorial to see how we implemented updates, deletes, and multiple row handling. There simply wasn’t enough space to outline them all here.

One thing I haven’t covered is debugging. In many cases, you’ll need some kind of database browser to see what’s going on under the hood. There are a number of different apps out there that range from free and open source, to paid closed source with commercial support. Here are a couple to take a look at, but a quick Google search will reveal many more:

You can also access your SQLite databases directly from your Terminal by typing sqlite3 file.db. From there you can use the .help command to see a list of commands, or you can simply start executing SQL statements directly at the prompt. More information on the command-line SQLite client can be found on the main SQLite site.

I hope you enjoyed this whirlwind introduction to working with SQLite from Swift! If you have any questions or comments, please join the discussion below!

The post SQLite Tutorial: Getting Started appeared first on Ray Wenderlich.

Video Tutorial: iOS App Extensions Part 8: Today Extensions: Updating

Video Tutorial: iOS App Extensions Part 9: Today Extensions: OpenURL

Video Tutorial: Beginning watchOS: Series Introduction

Video Tutorial: Beginning watchOS Part 1: Layout I


Video Tutorial: Beginning watchOS Part 2: Layout II

Getting to Know Enums, Structs and Classes in Swift

$
0
0

enums-structs-classes-feature

Back in the days when there was only Objective-C, encapsulation was limited to working with classes. However, in modern iOS and Mac programming there are three choices: enums, structs and classes in Swift.

Combined with protocols, these types make it possible to create amazing things. While they share many common abilities, these types also have important differences.

The objective of this tutorial is to:

  • Give you some experience using enums, structs and classes.
  • Gain some intuition about when to use them.
  • Give you an understanding of how each works.

In terms of prerequisites, this tutorial assumes that you have at least a little Swift and object-oriented programming experience.

It’s All About Those Types

Three big selling points of Swift are its safety, speed and simplicity.

Safety implies that it’s difficult to accidentally write code that runs amok, corrupting memory and producing hard-to-find bugs. Swift makes your work safer because it tries to make it obvious when you have a bug by showing you problems at compile time, rather than hanging you out to dry at runtime.

Moreover, because Swift lets you clearly express your intent, the optimizer can go to town to help your code run lightning fast.

The Swift language core is simple and highly-regularized, thanks to being built upon a surprisingly small number of concepts. Despite its relatively simple rules, you can do amazing things.

The key to making this happen is the Swift type system:

Diagram showing the six types in Swift

Swift types are powerful, despite there being only six of them. That’s right, unlike many other languages that have literally dozens of built-in types, Swift only has six.

These consist of four named types: protocol, enum, struct, class). There are two compound types as well: tuple, function.

There are those other things you might think of as basic types—like Bool, Int, UInt, Float, Double, Character, String, Array, Set, Dictionary, Optional, etc. However, these are actually built up from the named types and delivered as part of the Swift Standard Library.

This tutorial focuses on the so-called named model types which consist of enum, struct and class.

Shapes with Scalable Vector Graphics (SVG)

As a working example, you’ll build a safe, speedy and simple SVG shape (scalable vector graphics) rendering framework.

SVG is an XML-based vector image format for 2D graphics. This specification has been an open standard developed by the W3C since 1999. (https://developer.mozilla.org/en-US/docs/Web/SVG)

Getting Started

Create a new playground in Xcode to follow along by selecting File\New\Playground… and name it Shapes and set the platform as OS X. Click Next to choose a location to save it, then Create to save the file. Clear the file completely and then enter the following:

import Foundation

Your goal will be able to render something like this:

<!DOCTYPE html><html><body><svg width='250' height='250'><rect x='110.0' y='10.0' width='100.0' height='130.0' stroke='Teal' fill='Aqua' stroke-width='5' /><circle cx='80.0' cy='160.0' r='60.0' stroke='Red' fill='Yellow' stroke-width='5'  /></svg></body></html>

It looks better when rendered by a browser or in a WebKit view, trust me. :]

You’ll need a representation for colors. SVG uses the CSS3 color type that can be specified as a name, RGB or HSL. The full specification is here: http://www.w3.org/TR/css3-color/.

To use a color in SVG, you specify it as an attribute of part of your drawing. For example, fill = 'Gray'. An easy approach to represent this in Swift this would be just to use a String as in, let fill = "Gray".

String for your Color type might not be such a great idea.

While using String is easy and does the job, there are some major downsides.

  1. It’s error prone. Any strings that are not part of the color spec will compile fine but not show up correctly at runtime. For example, “Grey” spelled with an “e” doesn’t work.
  2. Autocomplete won’t help you find valid color names.
  3. When you pass around a color as a parameter, it might not always be obvious that the string is a color.

Enum to the Rescue

Using a custom type solves these problems. If you’re coming from Cocoa Touch, you might think to implement an encapsulated class like UIColor. While using a class design could work, Swift gives you more choices for how to define your model.

Without typing anything in just yet, let’s have a think about how you might implement the colors as an enum.

You might think to implement it like so:

enum ColorName {
  case Black
  case Silver
  case Gray
  case White
  case Maroon
  case Red
  // ... and so on ... 
}

The above works very similarly to a set of C-style enums. However, unlike C-style enums, Swift gives you the option to specify a type to represent each case.

Enumerations that explicitly specify a backing store type are referred to as RawRepresentable, because they automatically adopt the RawRepresentable protocol.

So, you can specify the type of ColorName as String, and assign a value to each case, like so:

enum ColorName : String {
  case Black  = "Black"
  case Silver = "Silver"
  case Gray   = "Gray"
  case White  = "White"
  case Maroon = "Maroon"
  case Red    = "Red"
  // ... and so on ... 
}

However, Swift does something special for enums with a String representation. If you don’t specify what the case is equal to, the compiler automatically makes the String the same as the name of the case. That means you only need to write the case name:

enum ColorName : String {
  case Black
  case Silver
  case Gray
  case White
  case Maroon
  case Red
  // ... and so on ... 
}

You can further reduce your typing by separating the cases with commas using the keyword case just once.

Add the following code to the end of your playground:

enum ColorName : String {
  case Black, Silver, Gray, White, Maroon, Red, Purple, Fuchsia, Green, Lime, Olive, Yellow, Navy, Blue, Teal, Aqua
}

Now you have a first class custom type and all the goodness that comes with that. For example,

let fill = ColorName.Grey   // ERROR: Misspelled color names won't compile. Good!
let fill = ColorName.Gray   // Correct names autocomplete and compile. Yay!

Associated Values

ColorName is good for named colors, but you might recall that CSS colors have several representations: named, RGB, HSL and more. How do you model those?

Enums in Swift are great for modeling things that have one of a number of representations, such as CSS color, and each enum case can be paired with its own data. These data are called associated values.

Define the CSSColor using an enum by adding this to your playground:

enum CSSColor {
  case Named(ColorName)
  case RGB(UInt8, UInt8, UInt8)
}

With this definition, you give the CSSColor model one of two states.

  1. It can be Named, in which case the associated data is a ColorName value
  2. It can be RGB, in which case the associated data is three UInt8 (0-255) numbers for red, green, and blue.

Note that this example leaves out RGBA, HSL and HSLA cases for brevity.

Protocols and Methods with an Enum

Any model type in Swift can adopt a protocol

You want to be able to print out multiple instances of CSSColor.

In Swift, enums, just like the other named types, can adopt protocols. In particular, your type can magically work with the print statement by adopting the CustomStringConvertible protocol.

The key to inter-operating with the Swift Standard Library is to adopt standard library protocols.

Add the following extension for CSSColor to your playground:

extension CSSColor : CustomStringConvertible {
  var description: String {
    switch self {
    case .Named(let colorName):
      return colorName.rawValue
    case .RGB(let red, let green, let blue):
      return String(format: "#%02X%02X%02X", red,green,blue)
    }
  }
}

This makes CSSColor conform to CustomStringConvertible. This is what tells Swift that our type, CSSColor, can be converted to a string. We tell it how by implementing the description computed property.

In this implementation, self is switched upon to determine if the underlying model is a named or RGB type. In each case you convert the color to the required string format for that case. The named case just returns the string name whereas the RGB case returns the red, green and blue values in the required format.

Add the following to your playground:

let color1 = CSSColor.Named(.Red)
let color2 = CSSColor.RGB(0xAA, 0xAA, 0xAA)
print("color1 = \(color1), color2 = \(color2)") // prints color1 = Red, color2 = #AAAAAA

Everything is type checked and proven correct at compile time, unlike how it goes when you use only String values to represent colors.

Note: While you could go back to your previous definition of CSSColor and modify it, you don’t have to. You’ve used an extension to re-open the color type and adopt a new protocol.

The extension style is nice because it makes what you define in order to conform to a given protocol fully explicit. In the case of CustomStringConvertible, you’re required to implement a getter for a description string property.

Initializers with an Enum

Just like classes and structs in Swift, you can also add custom initializers to enum. For example, you can make a custom initializer for grayscale values.

Add this extension to your playground:

extension CSSColor {
  init(gray: UInt8) {
    self = .RGB(gray, gray, gray)
  }
}

Add the following to your playground:

let color3 = CSSColor(gray: 0xaa)
print(color3)  //  prints #AAAAAA

You can now conveniently create grayscale colors!

Namespaces with Enum

Named types can act as a namespace to keep things organized and minimize complexity. You created ColorName and CSSColor, and yet ColorName is only ever used in the context of a CSSColor.

Wouldn’t it be nice if you could hide ColorName within a CSSColor model?

Well, you can! Remove ColorName from your playground and replace it with the following code:

extension CSSColor {
    enum ColorName : String {
        case Black, Silver, Gray, White, Maroon, Red, Purple, Fuchsia, Green, Lime, Olive, Yellow, Navy, Blue, Teal, Aqua
    }
}

This moves ColorName into an extension on CSSColor. Now ColorName is tucked away, and the inner type is defined on CSSColor.

Note: One of the great features of Swift is that the order in which you declare things usually doesn’t matter. The compiler scans the file multiple times and figures it out without needing to forward declare things as it does when working with C/C++/Objective-C.

However, if you receive an error in your playground about ColorName being an undeclared type, move the above extension to just below your enum definition of CSSColor to clear the playground error.

Sometimes playgrounds are sensitive to the ordering of definitions, even when it doesn’t really matter. :]

Enums can be set up as pure namespaces that users can’t accidentally instantiate. For example, you’ll soon need the math constant pi to perform some computations. While you could use Foundation’s M_PI macro, you’ll define your own to keep things as portable as possible. (Arduino micro-controller, here we come!)

Add the following code to the end of your playground:

enum Math {
  static let pi = 3.1415926535897932384626433832795028841971694
}

Since the Math enum contains no cases, and it’s illegal to add new cases in an extension, it can never be instantiated. You’ll never be able to accidentally misuse Math as a variable or parameter.

By declaring pi as a static constant, you don’t need to instantiate one. Whenever you need the value of pi, you can simply use Math.pi rather than remembering all those digits!

Taking Stock of Enums

Enums are much more powerful in Swift than they are in other languages, such as C or Objective-C. As you’ve seen, you can extend them, create custom initializer methods, provide namespaces and encapsulate related operations.

So far you’ve used enum to model CSS colors. This works well because CSS colors are a well understood, fixed W3C specification.

Enumerations are great for picking items from a list of well-known things, such as days of the week, faces of a coin or states in a state machine. It’s no surprise that Swift optionals are implemented in terms of an enum with a state of .None or .Some with an associated value.

On the other hand, if you wanted CSSColor to be user extensible to other color space models that are not defined in the W3C specification, an enumeration is not be the preferred abstraction.

Which, by the way, brings you to the next Swift named model type, Structures. :]

Using Structs

Because you want your users to be able to define their own custom shapes within the SVG, using an enum is not a good choice for defining shape types.

New enum cases cannot be added later in an extension. That leaves either a class or a struct.

The Swift Standard Library team suggests that when you create a new model, you should first design the interface using a protocol. You want your shapes to be drawable, so add this to your playground:

protocol Drawable {
  func draw(context: DrawingContext)
}

The protocol defines what it means to be Drawable. It has a draw method that draws to something called a DrawingContext.

Speaking of DrawingContext, it’s just another protocol. Add it to your playground as follows:

protocol DrawingContext {
  func draw(circle: Circle)
  // more primitives will go here ...
}

A DrawingContext knows how to draw pure geometric types: Circle, Rectangle and other primitives. Take note of something here: the actual drawing technology is not specified, but you could implement it in terms of anything — SVG, HTML5 Canvas, Core Graphics, OpenGL, Metal, etc.

You’re ready to define a circle that adopts the Drawable protocol. Add this to your playground:

struct Circle : Drawable {
  var strokeWidth = 5
  var strokeColor = CSSColor.Named(.Red)
  var fillColor = CSSColor.Named(.Yellow)
  var center = (x: 80.0, y: 160.0)
  var radius = 60.0
 
  // Adopting the Drawable protocol.
 
  func draw(context: DrawingContext) {
    context.draw(self)
  }
}

In a struct, you group together stored properties. Here you have implemented the following properties:

  • strokeWidth: The width of the line.
  • strokeColor: The color of the line.
  • fillColor: The color to fill the circle with.
  • center: The center point of the circle.
  • radius: The radius of the circle.

Structs work a lot like classes with a couple of key differences. Perhaps the biggest difference is that structs are value types and classes are reference types.

Value vs. Reference Types

value_type

Value types work as separate and distinct entities.

The quintessential value type is an integer because it works that way in most programming languages. If you want to know how a value type acts, ask the question, “What would Int do?” For example:

For Int:

var a = 10
var b = a
a = 30     // b still has the value of 10.
a == b     // false

For Circle (defined using struct):

var a = Circle()
a.radius = 60.0
var b = a
a.radius = 1000.0  // b.radius still has the value 60.0

reference_type

If you had made your circle from a class type, it would have been given reference semantics. That means that it references an underlying shared object.

For Circle (defined using class):

var a = Circle()  // a class based circle
a.radius = 60.0
var b = a
a.radius = 1000.0  // b.radius also becomes 1000.0

When creating new objects using value types, copies are made; when using reference types, the new variable refers to the same object. This dissimiliarity in behavior is a critical difference between class and struct.

Rectangle Model

Add this to your playground to continue making your drawing library by creating a rectangle type:

struct Rectangle : Drawable {
  var strokeWidth = 5
  var strokeColor = CSSColor.Named(.Teal)
  var fillColor = CSSColor.Named(.Aqua)
  var origin = (x: 110.0, y: 10.0)
  var size = (width: 100.0, height: 130.0)
 
  func draw(context: DrawingContext) {
    context.draw(self)
  }
}

You also need to update the DrawingContext protocol so that it knows how to draw a rectangle. Update DrawingContext in your playground so it reads:

protocol DrawingContext {
  func draw(circle: Circle)
  func draw(rectangle: Rectangle)
  // more primitives would go here ...
}

Circle and Rectangle adopt the drawable protocol. They defer the actual work to something that conforms to the DrawingContext protocol.

Now it’s time to make a concrete model that does drawing SVG style. Add this to your playground:

final class SVGContext : DrawingContext {
 
  private var commands: [String] = []
 
  var width = 250
  var height = 250
 
  // 1
  func draw(circle: Circle) {
    commands.append("<circle cx='\(circle.center.x)' cy='\(circle.center.y)\' r='\(circle.radius)' stroke='\(circle.strokeColor)' fill='\(circle.fillColor)' stroke-width='\(circle.strokeWidth)'  />")
  }
 
  // 2
  func draw(rectangle: Rectangle) {
    commands.append("<rect x='\(rectangle.origin.x)' y='\(rectangle.origin.y)' width='\(rectangle.size.width)' height='\(rectangle.size.height)' stroke='\(rectangle.strokeColor)' fill='\(rectangle.fillColor)' stroke-width='\(rectangle.strokeWidth)' />")
  }
 
  var SVGString: String {
    var output = "<svg width='\(width)' height='\(height)'>"
    for command in commands {
      output += command
    }
    output += "</svg>"
    return output
  }
 
  var HTMLString: String {
    return "<!DOCTYPE html><html><body>" + SVGString + "</body></html>"
  }
}

SVGContextis a class that wraps a private array of command strings. In sections 1 and 2, you conform to the DrawingContext protocol, and the draw methods just append a string with the correct XML for rendering the shape.

Finally, you need a document type that can contain many Drawable objects, so add this to your playground:

struct SVGDocument {
  var drawables: [Drawable] = []
 
  var HTMLString: String {
    let context = SVGContext()
    for drawable in drawables {
      drawable.draw(context)
    }
    return context.HTMLString
  }
 
  mutating func append(drawable: Drawable) {
    drawables.append(drawable)
  }
}

Here, HTMLString is a computed property on SVGDocument that creates an SVGContext and returns the HTMLString from the context.

Show Me Some SVG

How about we finally draw an SVG? Add this to your playground:

var document = SVGDocument()
 
let rectangle = Rectangle()
document.append(rectangle)
 
let circle = Circle()
document.append(circle)
 
let HTMLString = document.HTMLString
print(HTMLString)

This creates a default circle and rectangle and puts them into a document, and then it prints the XML.

Let’s now visualize the SVG. Add the following to the end of the playground:

import WebKit
import XCPlayground
let view = WKWebView(frame: CGRect(x: 0, y: 0, width: 250, height: 250))
view.loadHTMLString(HTMLString, baseURL: nil)
XCPlaygroundPage.currentPage.liveView = view

This does some Playground trickery and sets up a web view to view the SVG. Press Command-Option-Return to show this web view in the assistant editor.

Using Classes

So far, you used a combination of structs (value types) and protocols to implement drawable models.

Now it’s time to play with classes too. They let you define base classes and derived classes. The more traditional object-oriented approach to the shapes problem is to make a Shape base class with a draw() method.

Even though you won’t use it now, it’s helpful to know how this approach would work. It would look something like this:

hierarchy

And in code, it would look like the following block — this is just for reference, so don’t add it to your playground:

class Shape {
  var strokeWidth = 1
  var strokeColor = CSSColor.Named(.Black)
  var fillColor = CSSColor.Named(.Black)
  var origin = (x: 0.0, y: 0.0)
  func draw(context: DrawingContext) { fatalError("not implemented") }
}
 
class Circle : Shape {
  override init() {
    super.init()
    strokeWidth = 5
    strokeColor = CSSColor.Named(.Red)
    fillColor = CSSColor.Named(.Yellow)
    origin = (x: 80.0, y: 80.0)
  }
 
  var radius = 60.0
  override func draw(context: DrawingContext) {
    context.draw(self)
  }
}
 
class Rectangle : Shape {
  override init() {
    super.init()
    strokeWidth = 5
    strokeColor = CSSColor.Named(.Teal)
    fillColor = CSSColor.Named(.Aqua)
    origin = (x: 110.0, y: 10.0)
  }
 
  var size = (width: 100.0, height: 130.0)
  override func draw(context: DrawingContext) {
    context.draw(self)
  }
}

In order to make object oriented programming safer, Swift introduced the override keyword. It requires that you, the programmer, acknowledge when you’re overriding something.

It prevents accidentally shadowing existing methods or not properly overriding what you thought you were. It can be a lifesaver when consuming a new version of a library and understanding how things have changed.

line

Nevertheless, there are some drawbacks to this object oriented approach.

The first problem you’ll notice is in the base-class implementation of draw. Shape wants to avoid being misused, so it calls fatalError() to alert derived classes that they need to override this method.

Unfortunately, this check happens at runtime time and not compile time.

Secondly, the Circle and Rectangle classes have to deal with the initialization of the base class data. While this is a relatively easy scenario, class initialization can become a somewhat involved process in order to guarantee correctness.

Thirdly, it can be tricky to future proof a base-class.

For example, suppose you wanted to add a drawable Line type. In order to work with your existing system, it would have to derive from Shape, which is a little bit of a misnomer.

Moreover, your Line class needs to initialize the base class’s fillColor property, and that doesn’t really make sense for a line.

Based on this, you could refactor your hierarchy and it would work better. In practice, however, it might not be possible to modify your base class without breaking many existing clients, and it’s usually impossible to get it right the first time.

Finally, classes have the reference (shared) semantics that were discussed earlier. While Automatic Reference Counting (ARC) takes care of things most of the time, you need to be careful not to introduce reference cycles, or you’ll end up with memory leaks.

If you add the same shape to an array of shapes, it might be surprising when you modify the color of one shape to red and another one also seems to randomly change.

Why Even Use a Class?

Given the above downsides, you might be wondering why you would ever want to use a class.

For starters, they allow you to adopt mature and battle-tested frameworks like Cocoa and Cocoa Touch.

Additionally, classes do have more important uses. For example, a large memory-hogging, expensive-to-copy object is a good candidate for wrapping in a class.

See where I’m going? They’re helpful anytime reference vs. value semantics come into play.

Check out this two-part tutorial on the subject: Reference vs. Value Types in Swift.

Computed Properties

All named model types let you create custom setters and getters that don’t necessarily correspond to a stored property.

Suppose you want to add a diameter getter and setter to your Circle model. It’s easy to implement it in terms of the existing radius property.

Add the following code to the end of your playground:

extension Circle {
  var diameter: Double {
    get {
      return radius * 2
    }
    set {
      radius = newValue / 2
    }
  }
}

This implements a new computed property which is purely based on the radius. When you get the diameter, it returns the radius doubled. When you set the diameter, it sets the radius to the value divided by 2. Simple!

More often than not, you only want to implement a special getter. In this case, you don’t have to include the get {} keyword block and can just specify the body. Perimeter and area are good use cases for this.

Add the following to the circle extension you just added:

// Example of getter-only computed properties
var area: Double {
  return radius * radius * Math.pi
}
var perimeter: Double {
  return 2 * radius * Math.pi
}

Unlike classes, struct methods are not allowed to modify — aka mutate — stored properties by default, but they can if you declare them as mutating.

For example, add the following to the Circle extension:

func shift(x: Double, y: Double) {
  center.x += x
  center.y += y
}

This tries to define a shift() method on circle which moves the circle in space. i.e. it changes the center point.

But this throws the following error on the two lines which increment the center.x and center.y properties.

// ERROR: Left side of mutating operator has immutable type ‘Double'

This can be fixed by adding the mutating keyword, like so:

mutating func shift(x: Double, y: Double) {
  center.x += x
  center.y += y
}

This tells Swift that it’s OK that your function mutates the struct.

Retroactive Modeling and Type Constraining

One of the great features of Swift is retroactive modeling. It lets you extend behavior of a model type even if you don’t have the source code for it.

Here’s a use case: Suppose you’re a user of the SVG code and you want to add an area and perimeter property to Rectangle just like Circle.

To see what this all means, add this to your playground:

extension Rectangle {
  var area: Double {
    return size.width * size.height
  }
  var perimeter: Double {
    return 2 * (size.width + size.height)
  }
}

Previously, you used extension to add methods to an existing model, and now, you’ll formalize these methods into a new protocol.

Add this to your playground:

protocol ClosedShapeType {
  var area: Double { get }
  var perimeter: Double { get }
}

That gives you an official protocol.

Next, you’ll tell the circle and rectangle to adopt this protocol retroactively by adding the following to your playground:

extension Circle: ClosedShapeType {}
extension Rectangle: ClosedShapeType {}

You can also define a function that, for example, computes the total perimeter of an array of models (any mix of structs, enums, classes) that adopt the ClosedShapeType protocol.

Add the following to the end of the playground:

func totalPerimeter(shapes: [ClosedShapeType]) -> Double {
  return shapes.reduce(0) { $0 + $1.perimeter }
}
totalPerimeter([circle, rectangle])

This uses reduce to calculate the sum of perimeters. You can learn more about how it works in An Introduction to Functional Programming.

Where To Go From Here?

The completed playground can be found here.

In this tutorial, you learned about enum, struct and class — the named model types of Swift.

All three have key similarities: they provide encapsulation, can have initializer methods, can have computed properties, can adopt protocols, and they can be modeled retroactively.

However, they also have important differences.

Enums are value types that have a set of cases, where each case can have different associated values. Each value of an enum type represents a single case as defined by the enum. They can’t have any stored properties.

Structs, like enums, are value types but can also have stored properties.

Classes, like structs, can have stored properties, and they can be built into class hierarchies that override properties and methods. Because of this, explicit initialization of base classes is a requirement.

But unlike structs and enums, classes use reference, aka sharing, semantics.

For much more information on this, see the two-part series mentioned earlier, Reference vs. Value Types in Swift.

I hope you have enjoyed this whirlwind tour of the named model types in Swift. If you’re looking for a challenge, consider building a more complete version of the SVG rendering library. You’re off to a good start. :]

As always, if you have questions or insights you would like to share, please use the forums below!

The post Getting to Know Enums, Structs and Classes in Swift appeared first on Ray Wenderlich.

Video Tutorial: Beginning watchOS Part 3: Tables

Video Tutorial: Beginning watchOS Part 4: Table Rows

iOS Conferences, and Community Facing Content

$
0
0
ios conferences

Which iOS conferences should you be attending? Find out in this episode!

Join Mic, Jake, and Marin as they discuss Marin’s 2015 conference marathon, and his pick of the bunch with his three favorite iOS conferences. The three hosts then move on to talk about community facing content, the motivation behind getting involved, and how there are many rewards, not just financial.

[Subscribe in iTunes] [RSS Feed]

Our Sponsors

This episode was brought to you by the incredibly kind folks over at Hired and Couchbase.

Hired

Hired is the platform for the best iOS developer jobs.

Candidates registered with Hired receive an average of 5 offers on the platform, all from a single application. Companies looking to hire include Facebook, Uber and Stripe.

With Hired, you get job offers and salary and/or equity before you interview, so you don’t have to waste your time interviewing for jobs you might not end up wanting, and it’s totally free to use!

Plus you, our loyal audience, will receive a $2000 bonus from Hired if you find a job through the platform, just for signing up using the show’s exclusive link: hired.com/ray

Couchbase

Couchbase are running a hands-on lab at RWDevCon, designed to get you up and running with Couchbase Mobile, their NoSQL database for mobile applications.

If you’re attending RWDevCon, be sure to join Wayne Carter at 11:30am on Saturday 12th as he explains how to use Couchbase Mobile to create a consistent user experience, regardless of whether the user is on-, or offline. Wayne will touch on such topics as local persistence, sync, security, and taking your data cross-platform.

Make sure to get there early, as places are limited!

Interested in sponsoring a podcast episode? We sell ads via Syndicate Ads, check it out!

Show Notes

Contact Us

Where To Go From Here?

We hope you enjoyed this episode of our podcast. Be sure to subscribe in iTunes to get notified when the next episode comes out.

We’d love to hear what you think about the podcast, and any suggestions on what you’d like to hear in future episodes. Feel free to drop a comment here, or email us anytime at podcast@raywenderlich.com.

The post iOS Conferences, and Community Facing Content appeared first on Ray Wenderlich.

Viewing all 4370 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>