Learn when to use Core Graphics rather than the other drawing APIs.
The post Video Tutorial: Intermediate Core Graphics Part 6: Conclusion appeared first on Ray Wenderlich.
Learn when to use Core Graphics rather than the other drawing APIs.
The post Video Tutorial: Intermediate Core Graphics Part 6: Conclusion appeared first on Ray Wenderlich.
View next video: NSURLSession And Configuration
The post Video Tutorial: Networking With NSURLSession: Series Introduction appeared first on Ray Wenderlich.
Your challenge is to customize the cache settings for the session created in the demo. See the Challenge PDF in the resources link below for full details.
View next video: NSURL, NSURLRequest, and NSURLResponse
View previous video: Series Introduction
The post Video Tutorial: Networking With NSURLSession Part 1: NSURLSession And Configuration appeared first on Ray Wenderlich.
Cocoa bindings have a simple goal: write less code. You’ll discover as you work through this Cocoa Bindings on OS X tutorial that they do indeed live up to this objective.
Cocoa bindings, aka bindings, fulfill a lot of responsibilities. Most importantly, they free you up from having to spend hours writing glue code — i.e. creating links between the model and the view in the controller when using the Model-View-Controller (MVC) pattern.
If you’ve spent time in Cocoa or Cocoa Touch, you’ve no doubt written countless lines of boilerplate code to handle the passing of data between your model and UI layers. You’ve got your delegates, notifications and observers to let you know when a control has been altered, in addition to code that helps with the task of validating and transforming data.
You may have wondered if there’s a better way.
The great news is that there is. Cocoa bindings comprise a set of technologies that makes a lot of the code you’ve previously written, frankly, unnecessary.
In this Cocoa Bindings on OS X tutorial, you’ll learn about how to use Cocoa bindings to:
Once the relationship is set up within Interface Builder, any user-generated changes to your UI are automatically pushed to your data model, and any changes made to the data model are automatically updated in the UI.
Although you won’t have to spend the next several of your hours coding, there’s still a fair amount of work ahead in Interface Builder using Auto Layout, so familiarity with both of these tools is a prerequisite.
In this tutorial, you’ll create an app that displays search results from the App Store via the iTunes API.
First, download the starter project here.
Build and run the project. You’ll see that there’s already a nice interface – but no data.
You’ll also see there are a couple of files to help you along. iTunesRequestManager.swift contains a struct with two static methods. The first sends a query to the iTunes API and downloads a JSON payload that contains iOS apps results for a provided search string, while the second is a helper method to download an image asynchronously.
The second file, iTunesResults.swift, defines a data model class that matches the data downloaded by the iTunes search method.
Note: All variables in the Result
class are defined as dynamic. This is because bindings rely on key-value coding, and hence require the Objective-C runtime. Adding the dynamic
keyword guarantees that access to that property is always dynamically dispatched using the Objective-C runtime.
Hence, you must remember that bindings rely on key-value coding and need to use the Objective-C runtime in order to work.
The class inherits from NSObject; this is also a requirement for bindings. You’ll discover why a little later, when you add a variable to your view controller class.
First, you’re going to retrieve search results via the iTunes API and add it to an NSArrayController.
Open the storyboard and look at the objects in the View Controller Scene. Note that objects on which you’ll set bindings all have the labels ‘(Bind)’.
NSArrayController
is an object that manages the content of an NSTableView
. This content often takes the form of an array of model objects.
Note: NSArrayController
offers much more than a simple array – including managing object selection, sorting and filtering. Cocoa Bindings make heavy use of this functionality.
Find an NSArrayController
object in the Object Library. Drag it into the list of objects under the View Controller Scene grouping in the Document Outline:
Next, open the Assistant Editor and make sure ViewController.swift is the file being edited. Control-drag from the Array Controller object in the Storyboard to the ViewController.swift source to add an outlet to it, and name it searchResultsController:
Now you’re ready to use the search box and button to get a list of search results and add them to the searchResultsController
object.
Control-drag from the search button in the Storyboard to the ViewController.swift source. Select to create an IBAction
, call it searchClicked
, and then add the following code to the method:
@IBAction func searchClicked(sender: AnyObject!) { //1 if (searchTextField.stringValue == "") { return } //2 if let resultsNumber = Int(numberResultsComboBox.stringValue) { //3 iTunesRequestManager.getSearchResults(searchTextField.stringValue, results: resultsNumber, langString: "en_us") { (results, error) -> Void in //4 let itunesResults = results.flatMap { $0 as? NSDictionary } .map { return Result(dictionary: $0) } //Deal with rank here later //5 dispatch_async(dispatch_get_main_queue()) { //6 self.searchResultsController.content = itunesResults print(self.searchResultsController.content) } } } } //7 override func controlTextDidEndEditing(obj: NSNotification) { //enter pressed searchClicked(searchTextField) } |
Taking each line in turn:
getSearchResults(query:, results:, language:)
. This passes in the number of results from the combo box and the query string you typed into the text field. It returns, via a completion handler, an array of NSDictionary
result objects or an NSError
object if there’s a problem completing the query. Note that the method already handles parsing the JSON.Result
object from it. When that is done, the itunesResults
variable contains an array of Result
objects.searchResultsController
, you need to make sure you’re on the main thread, therefore you use dispatch_async
to get to the main queue. You haven’t set up any bindings, but once you have, altering the content property on the searchResultsController
will update the NSTableView
(and potentially other UI elements) on the current thread. Updating UI on a background thread is always a no-no.NSArrayController
. The array controller has a number of different methods to add or remove objects that it manages, but each time you run a search, you want to clear out whatever is there and start over with just the results of the latest query. For now, print the content of searchResultsController
to the console to verify that everything is working.searchClicked()
method when the user presses enter in addition to clicking the button. This just makes it easier to run a quick search.Build and run now. Type flappy into the search bar. You will see something like this show up in the console:
It’s time to get to the meat of this tutorial!
The first step is to bind the array controller to the table view.
Open up Main.storyboard and select the table view titled Search Results Table View (Bind). Open the Bindings Inspector — it’s the second to last icon in the right pane, just before the View Effects Inspector.
Like this:
Build and run now. You’ll see at most five results unless you changed the number in the dropdown. However, they all say ‘Table View Cell’.
You’re getting a bunch of duplicate hits because the text fields in the cells have no idea which properties on the data model they should read.
Expand the objects in the table view until you find the text field named Title TextField (Bind). Select this object and open the Bindings Inspector.
objectValue
is a property on the table cell view that gets set by the NSTableView
on each cell view object from its binding to the table.
In other words, objectValue
is, in this case, equal to the Result
model object for that row.
Repeat this process for Publisher TextField (Bind) by binding the value of this element to objectValue.artistName.
Build and run now. Look at that – both the title and publisher show themselves.
How about that missing rank column? Rank isn’t set on the data model object you get from iTunes. However, the order of the results from iTunes does tell you the order in which they display on a device when searching iTunes.
So, with a little more work you can set the rank value.
Add the following code in ViewController
under this comment: //Deal with rank here later
.
.enumerate() .map({ (index, element) -> Result in element.rank = index + 1 return element }) |
This code calls enumerate()
in order to get the index and the object at the index. Then it calls .map
to set the rank value for each object and return an array with that result.
Finally, go back to the Storyboard, select Rank TextField (Bind)
, open the Bindings Inspector and do the following:
Table Cell View
objectValue.rank
Build and run now.
Now it’s time to bind the Result
object in the table that the user selects to the rest of the UI. Binding to a selection in a table involves two steps:
NSArrayController
to the table selection selection
object in the Select the Search Results Table View (Bind) and open the Bindings Inspector to do the following steps:
selectionIndexes
property that contains set of indexes that the user has selected in the table. Note that in this case, I’ve set the table view to only allow a single selection, but you could work with more than one selection if needed — think about the finder window and how you can select multiple files at a time.The NSArrayController
object has a selection
property that returns an array of objects. When you bind the selectionIndexes
property from the table view to the array controller, the selection
property will be populated with the objects in the array controller that correspond to the indexes selected in the table.
The next step is to bind the labels and other UI elements to the selected object.
Find and select the App Name Label (Bind).
Build and run.
Now you know how easy it is to get data from your model into your UI, but what if the data needs to be formatted in some way, such as currency or a date?
Luckily, there’s a built-in set of objects that make it easy to change the way a specific piece of data is displayed in a label.
Find the label titled Price Label (Bind), setting it up like this:
Price
label. Like this:
Build and run.
Note: Number formatters are very powerful – in addition to currencies, you can also control how many digits follow a decimal point, percentages, or have the number spelled out in words.
There are also a bunch of other kinds of formatters. There are formatter objects for dates, for byte counts and several other less common ones.
You’ll be using a Byte Count Formatter next.
Find File Size Label (Bind) and set it up like so:
Like this:
Build and run now.
You now know everything you need to know to bind the remaining labels, so here’s a short list of the keys you need to bind:
All these labels should be bound to the SearchResultsController and the selection controller key.
For more precision in your UI, you can also bind the Description Text View (Bind), the Attributed String binding to the itemDescription Model Key Path. Make sure you bind the NSTextField
, which is several levels down in the hierarchy, not the NSScrollView
which is at the top.
Build and run. You should see now that most of the UI is populated.
The next step is to bind the image for the icon to the Icon Image View. This is a little trickier because what you get from the JSON payload is not the image, but a URL location for the image. Result
includes a method to download the image file and make it available as an NSImage
on the artworkImage
property.
You don’t want to download all the icons at once — just the one for the current selection in the table. You therefore need to invoke the method whenever the selection changes.
Add the following code to ViewController:
//1 func tableViewSelectionDidChange(notification: NSNotification) { //2 if let result = searchResultsController.selectedObjects.first as? Result { //3 result.loadIcon() } } |
tableViewSelectionDidChange()
gets fired every time the user selects a different row in the tableselectedObjects
. It returns an array that contains all the objects for the indexes of the rows selected in the table. In your case, the table will only allow a single selection, so this array always contains a single object. You store the object in the result
object.loadIcon()
. This method downloads the image on a background thread and then updates the Result
objects artworkImage
property when the image is downloaded on the main thread.Now that your code is in place, you’re ready to bind the image view. Head back to Main.storyboard, select the Icon Image View (Bind) object and open the Bindings Inspector and set things up:
You may notice that there is a Value Path and a Value URL section. Both of these bindings are intended to be used only with local resources. It is possible to connect them to a network resource, but if you do, the UI thread will be blocked until the resource is downloaded.
Build and run, search for fruit and then select a row. You’ll see the icon image appear once it has downloaded:
The collection view beneath the description text view is currently looking a little bare — time to populate that with some screenshots. First you’ll bind the collection view to the screenShots
property before ensuring that the screenShots
array is correctly populated.
Select the Screen Shot Collection View (Bind). Open the Bindings Inspector and expand the Content binding in the Content group. Set it up thusly:
The screenShots
array starts out empty. There’s a method named loadScreenShots()
that is similar to the method that loads the icon. It’ll download the image files and populate the screenShots
array with NSImage
objects.
Add this line in ViewController.swift
, in tableViewSelectionDidChange()
right after the result.loadIcon()
:
result.loadScreenShots() |
This will populate the screenshot images and create the right number of views. The next thing you need to do is set the right collection view item prototype.
Normally when you drag a collection view into a storyboard, you automatically create a collection view item and a segue. However, this feature is buggy in the latest Xcode and at the time of writing, it’s not working.
Although the collection view item scene is present in the storyboard, it’s not connected to the collection view. Therefore you’ll have to create this connection in code.
Add the following code to the end of viewDidLoad
in ViewController.swift:
let itemPrototype = self.storyboard?.instantiateControllerWithIdentifier("collectionViewItem") as! NSCollectionViewItem collectionView.itemPrototype = itemPrototype |
Now that the collection view knows how to create each item (via the prototype) you need to provide the content for each item, via a binding.
Open Main.storyboard and select Screen Shot Image View (Bind) inside the Collection View Item Scene. You’ll find this floating next to the main view controller. Here are the settings for this one:
The representedObject
property represents the object in the collection view array for that item; in this case, it’s an NSImage
object.
Build and run now.
You can now see the screenshots appearing below the description text — great work! Just a few more features of Cocoa Bindings to cover before wrapping up.
Thus far you’ve seen how you can bind model objects to labels and images for display to the user. However, you can also bind attributes such as fonts, colors, text styles and visibility to data in your model. This allows you to easily control the appearance of your UI directly through the model layer.
Users don’t like to stare at static screens when something is loading — they tend to think the worst if there’s nothing to tell them something’s happening behind the scenes.
Instead of leaving a static screen, you can show a spinner to the user, indicating that the app is busy working. An easy way to do this is to bind a progress spinner to a new property in the ViewController
, so add the following property to ViewController
:
dynamic var loading = false |
Loading requires two things in order to work correctly. The dynamic
keyword and that the parent class is a subclass of NSObject
. Bindings relies on KVO (Key Value Observing). A swift class that doesn’t inherit from NSObject wouldn’t be able to use KVO.
Add the following line of code in the function searchClicked()
right before the line that executes the call to getSearchResults()
.
loading = true |
Locate the line that sets the content
property on searchResultsController
(self.searchResultsController.content = itunesResults
) and add the following immediately before it:
self.loading = false |
Next, select Search Progress Indicator (Bind) in Main.storyboard. You’re going to bind two properties of the progress spinner: hidden
and animate
.
First, expand the Hidden group, and set it up like so:
In this case you need to do one more thing, when loading is true, you actually want hidden
to be false and vice versa. Luckily, there’s an easy way to do that — using NSValueTransformer
to flip the value of the boolean.
Choose NSNegateBoolean from the Value Transformer dropdown list.
NSValueTransformer
is a class that helps you convert the form or value of data when moving between UI and data model.
You can subclass this object in order to do much more complex conversions, you can learn more about NSValueTransformers in this tutorial: How to Use Cocoa Bindings and Core Data in a Mac App.
Next, bind to the Animate value like this:
This boolean doesn’t need to be negated.
Build and run now. You might want to use a larger number of results so that there’s time to watch the spinner do its spin thing while results are retrieved.
Color is the spice of design, and right now things are looking a little drab. You won’t be surprised to learn that you can set color with Cocoa bindings!
In this scenario, you’re dealing with apps that have a larger number of reviews, making them rank higher in the search results. More reviews tends to be a good sign, and users enjoy having a visual indicator of such a thing when they have to scroll through a long list and make split-second decisions.
So, you’ll build out that visual cue.
First, you need to add a method that calculates the color of each result based on the number of reviews.
Add this code to ViewController
inside ViewController.swift:
func setColorsOnData() { //1 let allResults = searchResultsController.arrangedObjects //2 let sortDescriptor = NSSortDescriptor(key: "userRatingCount", ascending: false) let sortedResults = allResults.sortedArrayUsingDescriptors([sortDescriptor]) as NSArray //3 for index in 0..<sortedResults.count { //4 let red = CGFloat(Float(index) / Float(sortedResults.count)) let green = CGFloat(1.0 - (Float(index) / Float(sortedResults.count))) let color = NSColor(calibratedRed: red, green: green, blue: 0.0, alpha: 1.0) //5 if let result = sortedResults.objectAtIndex(index) as? Result { result.cellColor = color } } } |
Here’s what you’re cooking up in there:
sortedResults
array that contains the sorted listcellColor
Next, you need to call that new method. Add this line to searchClicked()
in ViewController.swift
right after this line self.arrayController.content = itunesResults
:
self.setColorsOnData() |
Now, bind the font color of the rank column to that value.
Select the Rank TextField (Bind) object and set it up like this:
Build and run.
You can now see that the rank numbers are color-coded, according to the number of reviews each app has.
That’s the gist of Cocoa Bindings, and you can see just how much easier it makes life when you need to connect data and UI. You learned:
You can download the final project here. Hopefully, you can see how much time and code you can save by adopting this technology.
Each binding has a lot of little settings and options, many of which we didn’t explore. One specific thing to take a look at is this resource provided by Apple. It will cover a lot of the details about what the options in the bindings windows do.
I hope you enjoyed this Cocoa Bindings on OS X tutorial and picked up some new techniques to use to accelerate your development process. You’ve just opened up a whole new universe! Let’s talk about it in the forums — I look forward to your questions, comments and findings.
The post Cocoa Bindings on OS X Tutorial appeared first on Ray Wenderlich.
Learn about NSURL, NSURLRequest, and NSURLResponse and how these classes are used in the process of a network request.
The post Video Tutorial: Networking With NSURLSession Part 2: NSURL, NSURLRequest, and NSURLResponse appeared first on Ray Wenderlich.
I recently got back from the fourth annual NSNorth, a popular Canadian mobile development conference.
This year the event was held at the the St James Cathedral Centre in Toronto, and organizers Philippe Casgrain and Dan Byers were joined by Adrienne Marshall in presenting another successful conference for designers and developers.
There were 160 attendees registered for the conference, with companion tickets bringing the attendance to over 200. It felt like just the right size for connecting with past acquaintances and making new life long friends.
In this article, I’ll share some of the highlights of the event so you can get a taste of what the event was like, and see if it’s something you might want to attend next year. Let’s dive in!
Author and podcaster Daniel Steinberg kicked off the conference with a day long workshop geared to towards intermediate developers looking to level up their Swift skills.
Daniel walked students though intermediate level Swift concepts, assuming that the basics were covered. For example, he explained how the Swift compiler will treat objects and types, how errors are handled in Swift 2, and how we now have the ability to ask for the “first” element in a collection.
One thing Daniel said in his talk really stood out to me:
Consider these examples:
Daniel’s mix of clear explanations, humor and industry know-how was a great help for budding and experienced developers looking to enhance their understanding of Swift.
The keynote for NSNorth was presented on Thursday night. It was followed by a reception sponsored by Shopify.
May-Li Khoe, formerly with Apple, Microsoft and Leapfrog and now with Khan Academy, led off the conference with a talk about reshaping the future. She prompted us to consider the putting the user first when designing our apps, where are they when using the apps, and how they feel about the technology.
She illustrated her arguments with the story of Antanas Mockus, the mayor of Bogata who shook things up by firing the corrupt police department. He hired mimes to mock litterers and jay walkers. He also gamed the system by instituting white and red cards popular in sports. Like offensive soccer players, bad citizens would get presented red cards by fellow citizens. Good and kind people would get a white card.
She also gave great examples people who successfully shaped the future:
She left us with an insightful question: “What do you want the future to be?”
Indie developer Gwen Weston gave an interesting talk on type erasure.
She began by asking us to consider what is a “type”. She then went on to explain the differences between concrete and abstract types, the former representing data and the latter representing behavior. With the use of Generics, we use types represented by T or U, we can use type reification to make abstract type concrete.
Protocols present a exception, where we cannot directly instantiate abstract types. In this case we can wrap an abstract type in a concrete type, also know as type erasure.
Gwen took a topic that could have been dry and made it fun by injecting humor: all of her examples were Pokemon based. A great talk all around!
The delightful speaker Ayaka Nonaka is looking forward to iOS 10, however she wanted to look back at some new additions to iOS 9 that we may not have implemented yet.
Stating that she preferred to work in code, she likes the new layout tools that empower clean layout:
If you ever get a chance to see Ayaka Nonaka speak, you won’t be disappointed!
Liz Marley likes to play. She’s a heavy duty character in World of Warcraft, taking on all foes while sending instructions to her companions. Putting a twist on the gamer put-down “Learn to Play”, she renamed her clan “Play to Learn”. This positive attitude extends to her work in App Camp For Girls.
Empowering young girls to become developers is the mandate of App Camp For Girls. It provides a safe environment presented by other women, whom the girls can identify with. Praise is not given for appearance or for being smart, but rather for working hard.
Relating her talk to the audience, Liz argued that Apple reset the clock with Swift. All developers started off fresh on the same footing, and they even gave us Playgrounds making it easy to get started and experiment.
Liz wrapped her talk up by saying we are invited to play – so go pick a topic and play!
One of the cool features of NSNorth are lightning talks. These are short 15 minute presentations given by attendees, selected from proposals ahead of the conference. They are a great way for new speakers to get experience and for those who want to impart a bite size bit of knowledge.
As an example, one talk I really liked was by Zev Eisenberg, discussing his open source library BonMot, which allows you to take the pain out of attributed strings.
In essence, it allows you to layout type like a typographer. He developed the library out of necessity for some projects he was working on.
BonMot allows for the creation of attributed strings through the use of BonChain arrays, where effects can be applied and the sent to BonText. The resulting output is an attributed string with the format added to each individual BonChain item.
Very slick and worth checking out for your typography needs!
Another fascinating talk was given by watchmaker and iOS developer Jon Edwards.
Building on Charles Perry’s talk at NSNorth 2014 on finding your niche in the App Store, Jon started out by reminding us that only 0.01% of app developers are successful and happy with their App Store results.
By analogy, Jon also used the example of the surfing mecca Mavericks, where some of the biggest waves exist. In the movie Chasing Mavericks, the protagonist learns that careful observation can lead you to find the best waves. Rather than fighting things head on, a keen observation of the laws of nature offers better results.
Steve Jobs suggested that one should zoom out and see what is really going on. Jon said that in the world of watchmaking, the ratio of watches to watchmakers is 5000:1. Currently, 50% of watchmakers are of retirement age or close to death. Last year, just around 50 watchmakers graduated from colleges. With that insight, it seems to be no wonder why watchmaking is a lucrative business!
Jon went on to discuss the hedgehog concept, where unlike a fox that knows many things, a hedgehog knows one big thing. The key is to discover your sweet spot. As Jim Collins explains in his book Good to Great, it’s critical to determine what you passionate about.
The takeaway is to find out what you can be the best in the world at, and also find out what can drive your economic engine. The intersection of these is the sweet spot.
Jonathan Rhyne began his talk with a definition of story: an accounting of incidents or events. He explained that one of his favorite films, Forrest Gump is an example of great storytelling. It’s about destiny versus coincidence, and overcoming obstacles.
Jonathan argued that we are all storytellers. We form our identities and understand life through stories. Most of us have vivid memories, and memories are often attached to emotions.
We can remember where we were when significant events happened, but sometimes we remember the emotions at the expense of details. For example during the events on 911 the first plane crash wasn’t broadcast until the next day. Many of us can remember that as if we experienced it live. We have changed our memories with emotion.
We as developers are also in the people and emotion business. He suggested that you don’t just give a feature list: instead, ask many whys. Why can’t I do that, and why does my app do this?
Here are some examples of focusing on the why’s:
Get to know your target audience and ask how your product feels. Make people the center of your story and make your app have a supporting role. The take away is to ask yourself: why it is that you do what you do?
Michael Gorbath talk invited the audience to consider where we place our values in the platforms we choose to work with.
Beginning with conference name, NSNorth, he reminded us that the name and many Apple frameworks came from NextStep. Founded by Steve Jobs after he was ousted from Apple 30 years ago, NeXT and values that the company contained still matter today.
He argued that values should be a top priority. NeXT valued well designed UI, ease of use, and power. Values are about the choices we make and many of the NeXT’s values are still with us, especially given that NeXT was the seed that led to OS X and iOS.
Michael worked at Apple for a time and recalled attending C4, an early developer conference. A speaker from Appcelerator gave a talk on using Java instead of Objective-C. Following the talk, the questions from the audience were very negative – Michael being among the naysayers! The C4 conference organizers were very upset because of the attendees xenophobic behavior. The takeaway was that we shouldn’t criticize someone just because they use a different stack.
The reaction was caused by a conflict of values:
In this talk, Michael invited us to become “xenophilic” – to be more open to ideas and new platforms.
For example, recently Micheal was asked to work on Xamarin project, that is built using C#. He found that working with C# had certain advantages over the tools he was familiar with.
Even exploring Android development opened his eyes to some interesting features; such as a built in annotation system, collections of components, different ways to manage resources and animations with built-in tweeting to name a few.
In conclusion, he suggests that we all should become platform tourists and be inspired to explore other mobile stacks.
Rob Segal of Get Set Games, makers of the Mega Jump series of games, was the first game developer to speak at any NSNorth conference.
Get Set is a small company, initially just 2 designers and 2 developers. Mega Jump benefited from early App Store success, often featured by Apple and in the early days was able to sell characters by In App Purchases. They also had come success working with Pixar and Disney with re-skinned versions of their games.
With the assistance of the Canadian Trade Commission, they were able to find more success selling their apps in Asian markets. They were introduced to companies that would take their code and adapt their apps to burgeoning markets, such as India, who are the latest target having just jumped into smart phones.
Working with social networks; Linc, Kakao, WeChat and others also provided larger audiences. In China, working with Tenyu, Yoda1 and Takweb Games they were quite successful. Notably one of their games managed to get 100 million downloads in one day.
The takeaway here is to reach out to other development companies – they can hep you access markets you might not be able to otherwise.
One of the most entertaining talks took place during Keynote Karaoke. Organizer Phillipe Casgrain wrote an algorithm that would play 5 slides in random order. Participants were invited onto the stage and given 3 minutes to present their talk on the fly.
Many of the conference speakers took part and some attendees volunteered to be in the spotlight. Once on stage they realized that they had got more than they bargained for!
Notable Karaoke talks were given by Janie Clayton, Paddy O’Brian, Jonathan Rhyne and one of the most entertaining was by Joe Cieplinski of the Release Notes podcast.
Aside from poutine and beaver tails, what would make a Canadian conference more complete that a winter related activity!
In 2015, we were able to experience Curling at rink at the Chateaux Montebello, where the conference was hosted. This year, we had a private night at the Hockey Hall of Fame, just around the corner from St. James Cathedral.
We were able to see exhibits of all the stars of the game, from around the world. We even tried our hand at the interactive exhibits; shoot out and goaltending. Of course we all got to hang out with the Stanley Cup, awarded to the top team in the National Hockey League.
NSNorth has offered companion tickets for designers and developers who wanted to bring their families to attend the events.
This year they took it up a notch and had two tech workshops for kids on Saturday. Toronto’s Ladies Learning Code presented a gaming workshop, and Daniel Steinberg ran an afternoon workshop on for kids on making iOS games with Swift.
NSNorth is great conference and one of my favorites. I would definitely suggest that you try to attend it in the spring of 2017, where hopefully it will be held in Toronto again.
There are some other great iOS conferences you should consider too:
As a proud Canadian on the raywenderlich.com Team, I hope to see you next year at NSNorth and keep your stick on the ice!
The post NSNorth 2016 Conference Highlights appeared first on Ray Wenderlich.
Learn how NSURLSessionTask has several subclasses that do the work of the network requests.
The post Video Tutorial: Networking With NSURLSession Part 3: NSURLSessionTask appeared first on Ray Wenderlich.
Not so long ago, before the advent of graphical user interfaces, command-line programs were the primary method for interacting with computers. Despite the prevalence of GUIs, command-line programs still have an important role in today’s computing world. Command-line programs such as ImageMagick or ffmpeg are important in the server world. In fact, the majority of the servers that form the Internet run only command-line programs.
Even Xcode uses command-line programs! When Xcode builds your project, it calls xcodebuild, which does the actual building. If the building process was baked-in to the Xcode product, continuous integration solutions would be hard to achieve — if not impossible!
In this command line programs on OS X tutorial you will write a command-line utilty named Panagram. Depending on the options passed in, it will detect if a given input is a palindrome or anagram. It can be started with arguments or run in interactive mode without arguments.
Swift seems like an odd choice for creating a command-line program, as languages like C, Perl, Ruby or Java are a more traditional choice. But there are some great reasons to choose Swift for your command-line needs:
In this command line programs for OS X tutorial, you’ll create a classic compiled project.
Open Xcode and go to File\New\Project. Find the OS X group, select Application\Command Line Tool and click Next:
For Product Name, enter Panagram. Make sure that Language is set to Swift, then click Next.
Choose a location on your disk to save your project and click Create.
Many C-like languages have a main
function that serves as the entry point — i.e. the code that the operating system will call when the program is executed. This means the program execution starts with the first line of this function. Swift doesn’t have a main
function; instead, it has a main file.
When you run your project, the first line inside that file that isn’t a method or class declaration is the first one to execute. It’s a good idea to keep your main.swift file as clean as possible and put all your classes and structs in their own files. This keeps things streamlined and helps you to understand the main execution path.
Press Cmd + N to create a new file. Under OS X, select Source\Swift File and press Next:
Save the file as ConsoleIO.swift and open it. You’ll wrap all the input and output elements in a small, handy class.
Add the following code to ConsoleIO.swift:
class ConsoleIO { class func printUsage() { let executableName = (Process.arguments[0] as NSString).lastPathComponent print("usage:") print("\(executableName) -a string1 string2") print("or") print("\(executableName) -p string") print("or") print("\(executableName) -h to show usage information") print("Type \(executableName) without an option to enter interactive mode.") } } |
This code creates a class ConsoleIO
and a class method that prints usage information to the console. Every time you run a program, the path to the executable is implicitly passed as argument [0] and accessible through the global Process
enum. Process
is a small wrapper around the argc
and argv
arguments you may know from C-like languages.
Create another new Swift file named Panagram.swift and add the following code to it:
class Panagram { func staticMode() { ConsoleIO.printUsage() } } |
This creates a class Panagram
that has one method. The class will handle the program logic, with staticMode()
representing non-interactive mode — i.e. when you provide all data through command line arguments. For now, it simply prints the usage information.
Now open main.swift and replace the print
statement with the following code:
let panagram = Panagram() panagram.staticMode() |
Build and run your project; you’ll see the following output in Xcode’s console:
usage: Panagram -a string1 string2 or Panagram -p string or Panagram -h to show usage information Type Panagram without an option to enter interactive mode. Program ended with exit code: 0 |
So far, you’ve learned what a command-line tool is, where the execution starts and how you can split your code into logical units to keep main.swift organized.
In the next section, you’ll handle command-line arguments and complete the static mode of Panagram.
When you start a command-line program, everything you type after the name is passed as an argument to the program. Arguments can be separated with whitespace characters. Usually, you’ll run into two kind of arguments: options and strings.
Options start with a dash followed by a character, or two dashes followed by a word. For example, many programs have the option -h
or --help
, the first being simply a shortcut for the second. To keep things simple, Panagram will only support the short version of options.
Open ConsoleIO.swift and add the following enum above the ConsoleIO
class:
enum OptionType: String { case Palindrome = "p" case Anagram = "a" case Help = "h" case Unknown init(value: String) { switch value { case "a": self = .Anagram case "p": self = .Palindrome case "h": self = .Help default: self = .Unknown } } } |
This creates an enum
with String
as its base type so you can pass the command-line arguments directly to init(_:)
. Panagram has three options: -p
to detect palindromes, -a
for anagrams and -h
to show the usage information. Everything else will be handled as an error.
Next, add the following method to the ConsoleIO
class:
func getOption(option: String) -> (option:OptionType, value: String) { return (OptionType(value: option), option) } |
The above method accepts a String
as its argument and returns a tuple of OptionType
and String
.
Open Panagram.swift and add the following property to the class:
let consoleIO = ConsoleIO() |
Then replace the content of staticMode()
with the following:
//1 let argCount = Process.argc //2 let argument = Process.arguments[1] //3 let (option, value) = consoleIO.getOption(argument.substringFromIndex(argument.startIndex.advancedBy(1))) //4 print("Argument count: \(argCount) Option: \(option) value: \(value)") |
Here’s what’s going on in the code above:
arguments
array.OptionType
.In main.swift, replace the line panagram.staticMode()
with the following:
if Process.argc < 2 { //Handle interactive mode } else { panagram.staticMode() } |
If your program is invoked with fewer than 2 arguments, then you’re going to start interactive mode. Otherwise you use the non-interactive static mode.
You now need to figure out how to pass arguments to your command-line tool from within Xcode. To do this, click on the Scheme named Panagram in the Toolbar:
Select Edit Scheme… in the popover that appears:
Ensure Run is selected, click the Arguments tab, then click the + sign under Arguments Passed On Launch. Add -p as argument and click Close:
Now run your project, and you’ll see the following output in the console:
Argument count: 2 Option: Palindrome value: p Program ended with exit code: 0 |
So far, you’ve added a basic option system to your tool, learned how to handle command-line arguments and how to pass arguments from within Xcode.
Next up, you’ll build up the main functionality of Panagram.
Before you can write any code to detect palindromes or anagrams, you should be clear on what they are!
Palindromes are words or sentences that read the same backwards and forwards. Here are some examples:
As you can see, capitalization and punctuation are often ignored.
Anagrams are words or sentences that are built using the characters of other words or sentences. Some examples are:
You’ll encapsulate the detection logic inside a small extension to String
.
Create a new file StringExtension.swift and add the following code to it:
extension String { } |
Time for a bit of design work. First, how to detect an anagram:
Add the following method to the String extension:
func isAnagramOfString(s: String) -> Bool { //1 let lowerSelf = self.lowercaseString.stringByReplacingOccurrencesOfString(" ", withString: "") let lowerOther = s.lowercaseString.stringByReplacingOccurrencesOfString(" ", withString: "") //2 return lowerSelf.characters.sort() == lowerOther.characters.sort() } |
Taking a closer look at the algorithm above:
Detecting palindromes is simple as well:
Add the following method to detect palindromes:
func isPalindrome() -> Bool { //1 let f = self.lowercaseString.stringByReplacingOccurrencesOfString(" ", withString: "") //2 let s = String(f.characters.reverse()) //3 return f == s } |
The logic here is quite straightforward:
Time to pull this all together and help Panagram do its job.
Open Panagram.swift and replace the print(_:)
statement inside staticMode()
with the following:
//1 switch option { case .Anagram: //2 if argCount != 4 { if argCount > 4 { print("Too many arguments for option \(option.rawValue)") } else { print("Too few arguments for option \(option.rawValue)") } ConsoleIO.printUsage() } else { //3 let first = Process.arguments[2] let second = Process.arguments[3] if first.isAnagramOfString(second) { print("\(second) is an anagram of \(first)") } else { print("\(second) is not an anagram of \(first)") } } case .Palindrome: //4 if argCount != 3 { if argCount > 3 { print("Too many arguments for option \(option.rawValue)") } else { print("Too few arguments for option \(option.rawValue)") } } else { //5 let s = Process.arguments[2] let isPalindrome = s.isPalindrome() print("\(s) is \(isPalindrome ? "" : "not ")a palindrome") } //6 case .Help: ConsoleIO.printUsage() case .Unknown: //7 print("Unknown option \(value)") ConsoleIO.printUsage() } |
Going through this step-by-step:
Run your project with some modified arguments inside the Scheme. For example, you could use the -p option as shown below:
You have a basic version of Panagram working, but you can make it even more useful by tying in to the input and output streams.
In most command-line programs, you’d like to print some messages for the user. For example, a program that converts video files into different formats could print the current progess or some error messages if something goes wrong.
Unix-based systems such as OS X define two different output streams:
stderr can be used to log error messages, the internal program state, or any other information the user doesn’t need to see. This can make debugging of a shipped application much easier.
Your next task is to change Panagram to use these different output streams.
First, open ConsoleIO.swift and add the following enum to the top of the file, outside the scope of the Panagram class:
enum OutputType { case Error case Standard } |
This defines the output method to use when writing messages.
Next add the following function to the ConsoleIO
class:
func writeMessage(message: String, to: OutputType = .Standard) { switch to { case .Standard: print("\u{001B}[;m\(message)") case .Error: fputs("\u{001B}[0;31m\(message)\n", stderr) } } |
This function has two parameters; the first is the actual message to print, and the second is where to write it. This defaults to .Standard
.
The code for the .Standard
option uses print
, which by default writes to stdout. The .Error
case uses the C function puts
to write to stderr, which is a global variable and points to the standard error stream.
What are those cryptic strings, though? These are control characters that cause Terminal to change the color of the following string. In this case you’ll print error messages in red (\u{001B}[0;31m
). The sequence \u{001B}[;m
used in the standard case resets the terminal color back to the default.
To use this new function, open Panagram.swift and change the print
lines in staticMode()
to use the new writeMessage(_:to:)
method.
The switch
statement should now look like the following:
case .Anagram: if argCount != 4 { if argCount > 4 { consoleIO.writeMessage("Too many arguments for option \(option.rawValue)", to: .Error) } else { consoleIO.writeMessage("too few arguments for option \(option.rawValue)", to: .Error) } ConsoleIO.printUsage() } else { let first = Process.arguments[2] let second = Process.arguments[3] if first.isAnagramOfString(second) { consoleIO.writeMessage("\(second) is an anagram of \(first)") } else { consoleIO.writeMessage("\(second) is not an anagram of \(first)") } } case .Palindrome: if argCount != 3 { if argCount > 3 { consoleIO.writeMessage("Too many arguments for option \(option.rawValue)", to: .Error) } else { consoleIO.writeMessage("too few arguments for option \(option.rawValue)", to: .Error) } } else { let s = Process.arguments[2] let isPalindrome = s.isPalindrome() consoleIO.writeMessage("\(s) is \(isPalindrome ? "" : "not ")a palindrome") } case .Help: ConsoleIO.printUsage() case .Unknown: consoleIO.writeMessage("Unkonwn option \(value)", to: .Error) ConsoleIO.printUsage() } |
As you see, only error messages need the to: parameter. That’s one of the benefits of Swift’s default values for parameters.
Run your project; you should see something similar to this in the Xcode console. For example, using the arguments a, listen and silent you’ll see the following:
[;mlisten is an anagram of silent |
The [;m
at the beginning of the output looks a bit awkward. That’s because the Xcode console doesn’t support using control characters to colorize the output. To see this in action, you’ll have to launch Panagram in Terminal:
There are different ways to launch your program from inside Terminal. You could find the build product using the Finder and start it directly via Terminal, or you could be lazy and tell Xcode to do this for you. In this section you’ll discover the lazy way.
First, edit your current Scheme and uncheck Debug executable. Now click on the Executable drop down and select Other:
In the window that appears, go to Applications/Utilities, select Terminal.app, then click Choose:
Now select the Arguments tab, remove all entries under Arguments Passed On Launch, then add one new entry in that section:
${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}
Finally, click Close.
This instructs Xcode to open Terminal when you run your project and pass through the path to your program. Terminal will then launch your program as you’d expect.
stdin
is attached to the keyboard and is therefore a way for you to collect input from users interactively. When Panagram is started without arguments, it will open in interactive mode and prompt the user for the options it would otherwise have collected from its arguments.
First, you need a way to get input from the keyboard.
Open ConsoleIO.swift and add the following method to the ConsoleIO
class:
func getInput() -> String { // 1 let keyboard = NSFileHandle.fileHandleWithStandardInput() // 2 let inputData = keyboard.availableData // 3 let strData = NSString(data: inputData, encoding: NSUTF8StringEncoding)! // 4 return strData.stringByTrimmingCharactersInSet(NSCharacterSet.newlineCharacterSet()) } |
Taking each numbered section in turn:
stdin
.Next, open Panagram.swift and create a function interactiveMode()
as follows:
func interactiveMode() { //1 consoleIO.writeMessage("Welcome to Panagram. This program checks if an input string is an anagram or palindrome.") //2 var shouldQuit = false while !shouldQuit { //3 consoleIO.writeMessage("Type 'a' to check for anagrams or 'p' for palindromes type 'q' to quit.") let (option, value) = consoleIO.getOption(consoleIO.getInput()) switch option { case .Anagram: //4 consoleIO.writeMessage("Type the first string:") let first = consoleIO.getInput() consoleIO.writeMessage("Type the second string:") let second = consoleIO.getInput() //5 if first.isAnagramOfString(second) { consoleIO.writeMessage("\(second) is an anagram of \(first)") } else { consoleIO.writeMessage("\(second) is not an anagram of \(first)") } case .Palindrome: consoleIO.writeMessage("Type a word or sentence:") let s = consoleIO.getInput() let isPalindrome = s.isPalindrome() consoleIO.writeMessage("\(s) is \(isPalindrome ? "" : "not ")a palindrome") default: //6 consoleIO.writeMessage("Unknown option \(value)", to: .Error) } } } |
Taking a look at what’s going on above:
shouldQuit
breaks the infinite loop that is started in the next line.At the moment, you have no way to interrupt the while
loop. To do this, open ConsoleIO.swift again and add the following line to OptionType
:
case Quit = "q" |
Next, add the following line to to init(_:)
:
case "q": self = .Quit |
Now go back to Panagram.swift and add a .Quit
case to the switch
statement inside interactiveMode()
:
case .Quit: shouldQuit = true |
Then change the .Unknown
case definition inside staticMode()
as follows:
case .Unknown, .Quit: |
Finally, open main.swift and replace the comment //Handle interactive mode
with the following:
panagram.interactiveMode() |
Run your project and enjoy your finished command-line program!
You can download the final project for this command line programs on OS X tutorial
here.
If you want to write more command-line programs in the future, take a look at how to redirect stderr to a log file and also look at ncurses, which is a C library for writing “GUI-style” programs for the terminal.
You can also check out this great article on scripting with Swift.
I hope you enjoyed this command line programs on OS X tutorial; if you have any questions or comments, feel free to join the forum discussion below!
The post Command Line Programs on OS X Tutorial appeared first on Ray Wenderlich.
Learn how the NSURLSession system uses either delegate methods or closures to communicate progress and completion.
The post Video Tutorial: Networking With NSURLSession Part 4: Delegate vs. Closures appeared first on Ray Wenderlich.
Update note: This In App Purchases tutorial on consumables was updated for iOS 9 and Swift 2.2 by Nicholas Waynik. The original tutorial was written by site editor-in-chief Ray Wenderlich.
Unlike other types of IAPs, Consumables are things that are only supposed to be used once. Think of extra lives in games, or stickers in a messaging app. Because of the disposable nature of these IAPs you have to consider some new functionality in your app: like keeping count of how many IAPs have been purchased and possibly limitting the number a person can have.
This In App Purchases tutorial picks up where things left things off in the previous In-App Purchases tutorial, so you’ll have to follow that tutorial first before starting this one. As a reminder, in that tutorial an app called “Rage” was created. It allowed customers to purchase rage face comics as non-consumable In-App purchases.
In this tutorial, you will extend the app to add a new consumable In-App Purchase – after all, those are often way more lucrative than non-consumables, since customers can purchase them more than once!
Note: This tutorial (and the previous) are focused on the “simplest and easiest” way to do things, not the most “robust and flexible” way of doing things. For more in-depth coverage, check out In-App Purchase Video Tutorial Series.
So without further ado, let’s dive into learning more about In-App Purchases – you’ll see it’s pretty easy, and there’s no need to rage about it! :]
Start by downloading the starter project for this tutorial.
Note that the starter project is not the same as where we left things off in the last tutorial – a few extra things were added for you. So, open the project in Xcode and have a look around:
You will have to make a few changes to this project for it to work with your own Apple developer account:
Select Rage in Project Navigator and then select the Rage target. Select the General tab and change the Bundle identifier from “com.razeware.Rage” to the one you used for the previous IAP tutorial.
Open RageProducts.swift and search for “com.razeware.rage” – replace that with your Bundle identifier as well. If you used a different product identifier for GirlfriendOfDrummerRage, then go ahead and change that in RageProducts.swift as well.
Once you’re done, build and run to try out the app on your device. Purchase a comic to make sure the purchase succeeds, and that you can view the comic after you buy it.
You have an sneaky plan to make money – instead of allowing the user to see cool random rage faces as often as they’d like, instead you’ll add an arbitrary limit to it, and charge users to purchase more, mwuhahaha!
This way, there will be no limit to how much money users can spend on your app. Hopefully the bucks will keep rolling in!
Note: This is just the beginning of ways you can use consumable In-App Purchases to (arguably sneakily) increase your app’s revenue. To learn more, check out the many blogs and talks about freemium game design, gamer psychology, or any games by Zynga ;]
Just like you did with consumable In-App Purchases, the first step to make this all happen is to create a new In-App Purchase entry in iTunes Connect.
So log onto iTunes Connect, and click My Apps. Click your entry for Rage, then click Features, In-App Purchases and +.
Underneath the Consumable option, click Select.
Fill out the screen that appears as follows (but replace the bundle ID with your own):
Finally, scroll down to the Language section and click Add Language. Fill in the dialog that appears as follows:
Click Save, then Save again, and you’re done! Time to try this out in your app.
To begin, open RageProducts.swift and add a new static variable for the new product identifier you just created. Then modify the `productIdentifiers` set to also include the new variable. It should look similar to the following:
public static let RandomRageFace = Prefix + "RandomRageFace" private static let productIdentifiers: Set<ProductIdentifier> = [RageProducts.GirlfriendOfDrummerRage, RageProducts.RandomRageFace] |
Next, open IAPHelper.swift and replace deliverPurchaseNotificationForIdentifier(_:)
with the following:
private func deliverPurchaseNotificationForIdentifier(identifier: String?) { guard let identifier = identifier else { return } purchasedProductIdentifiers.insert(identifier) if identifier == RageProducts.RandomRageFace { let defaults = NSUserDefaults.standardUserDefaults() var currentValue = defaults.integerForKey(RageProducts.RandomRageFace) currentValue += 5 defaults.setInteger(currentValue, forKey: RageProducts.RandomRageFace) } else { NSUserDefaults.standardUserDefaults().setBool(true, forKey: identifier) } NSUserDefaults.standardUserDefaults().synchronize() NSNotificationCenter.defaultCenter().postNotificationName(IAPHelper.IAPHelperPurchaseNotification, object: identifier) } |
Here you add a special case behavior for the consumable In-App Purchase. When a customer purchases one, instead of simply setting a flag indicating whether it’s purchased or not, you increment a value that keeps track of how many times the user can see a random rage face.
Note: This works but isn’t the ideal way of doing things, because now your IAPHelper class has hard-coded logic for a particular In-App Purchase. This doesn’t make it so reusable. For a more reusable way of doing things, check out In-App Purchase Video Tutorial Series.
Next open MasterViewController.swift and replace tableView(_:didSelectRowAtIndexPath:)
with the following:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { let product = products[indexPath.row] if (product.productIdentifier == RageProducts.RandomRageFace) { self.performSegueWithIdentifier(showRandomFaceSegueIdentifier, sender: self) } else { self.performSegueWithIdentifier(showDetailSegueIdentifier, sender: self) } } |
Here you added logic to determine if the selected product is the RandomRageFace
IAP. If it is then you will show the new RandomFaceViewController
, otherwise you’ll perform the segue with the identifier value of showDetail
and show the details of a specific rage face.
Go ahead and build and run. The new Random Rage Face consumable In-App purchase is listed in the table view.
Now tap on Random Rage Face.
You’ll see that the app displays the the view for RandomFaceViewController. Currently, tapping on the Random Rage Face! button does nothing. Quit the simulator so you can fix this.
Open RandomFaceViewController.swift and replace buttonPressed(_:)
with the following:
@IBAction func buttonPressed(sender: UIButton) { let defaults = NSUserDefaults.standardUserDefaults() var currentValue = defaults.integerForKey(RageProducts.RandomRageFace) if currentValue <= 0 { return } else { currentValue -= 1 defaults.setInteger(currentValue, forKey: RageProducts.RandomRageFace) defaults.synchronize() refresh() let randomIdx = (arc4random() % 4) + 1 let randomName = "random\(randomIdx).png" imageView.image = UIImage(named: randomName) } } |
This is basic logic to determine if the user has any random rage faces available. If they do, then you will display one of the random four images included in the starter project. There is one problem though: how does the user know if they have any available faces? To fix that, add the following two methods just above buttonPressed(_:)
:
override func viewWillAppear(animated: Bool) { super.viewWillAppear(animated) refresh() } func refresh() { let defaults = NSUserDefaults.standardUserDefaults() let currentValue = defaults.integerForKey(RageProducts.RandomRageFace) label.text = "Times Remaining: \(currentValue)" } |
When RandomFaceViewController
is first presented, you update the label with the current rage face count by calling refresh()
. The refresh()
method simply retrieves the number of rage faces left to be viewed from NSUserDefaults
. Finally, you display that number in a label at the bottom of the view controller.
And that’s it! Build and Run the app and purchase a few more consumables. Then test out your random rage face button and make sure it works as expected!
Here is the final sample project from the In App Purchases tutorial series.
Congrats – you now have implemented both non-consumable and consumable In-App Purchases, and added the ability for users to restore transactions!
This In App Purchases tutorial may provide more than enough functionality for simple apps. But if you want to take things even further and learn how develop a robust and extensible app, check out In-App Purchase Video Tutorial Series!
I hope you enjoyed this In App Purchases tutorial, and wish you best of luck with your consumable In-App Purchases! Just don’t be too sneaky or evil, one Zynga is enough ;]
The post In App Purchases Tutorial: Consumables appeared first on Ray Wenderlich.
Learn how NSURLSession handles threading and how to control it if necessary.
The post Video Tutorial: Networking With NSURLSession Part 5: Threading And Operation Queues appeared first on Ray Wenderlich.
Review what you learned in our Networking with NSURLSession video tutorial series and find out where to go from here.
The post Video Tutorial: Networking With NSURLSession Part 6: Conclusion appeared first on Ray Wenderlich.
The post Video Tutorial: Collection Views: Introduction appeared first on Ray Wenderlich.
In this video we look at the basics of Collection Views. We build a simple collection view displaying the index of each cell.
The post Video Tutorial: Collection Views Part 1: Getting Started appeared first on Ray Wenderlich.
Your challenge is to add a label to the custom cell which displays the paper’s caption, and add a gradient background behind the label so the caption can be read even on lighter wallpapers. See the Challenge PDF in the resources link below for full details.
View previous video: Getting Started
The post Video Tutorial: Collection Views Part 2: Custom Cells appeared first on Ray Wenderlich.
Blowing stuff up is fun. Blowing stuff up with friends is even funner. Blowing your friends up? We have a winner!
Unfortunately, it’s a little difficult to secure C4 explosives along with some willing buddies willing to explore the afterlife. Thankfully, there are some alternatives.
Enter Bomberman. Bomberman is a game where four players battle it out by strategically placing bombs across the battlefield with the goal being to blow each other up.
Each bomb has a few seconds of delay before it explodes and spews out an inferno in four directions. For additional excitement, explosions can trigger impressive chain reactions.
The original Bomberman came out in the early 80s and spinoffs have been published ever since. It’s a timeless game formula that’s still a lot of fun to play and build.
The original title was 2D, but you’re going to create a basic 3D version inside of Unity.
In this tutorial, you’ll learn the following:
Loosen up your wrists and get ready to shout “fire in the hole”. Things are about to get really explody inside of Unity. :]
Download the bomberman how-to starter project and extract it to a location of your choosing.
Open up the Starter Project in Unity. The assets are sorted inside several folders:
If it’s not opened yet, open up the Game scene and give it a run.
Both players can walk around the map using either the WASD keys and the arrow keys.
Normally, when player 1 (the red one) presses Space he should place a bomb at his feet, player 2 should be able to do the same thing by pressing Enter/Return.
However, that doesn’t work yet. You need to implement the code for placing bombs first, so open the Player.cs script in your favorite code editor.
This script handles all player movement and animation logic. It also includes a method named DropBomb that simply checks if the bombPrefab GameObject is attached:
private void DropBomb() { if (bombPrefab) { //Check if bomb prefab is assigned first } } |
To make a bomb drop beneath the player, add the following line inside the if
statement:
Instantiate(bombPrefab, myTransform.position, bombPrefab.transform.rotation); |
This will make a bomb spawn at the player’s feet. Give your scene a run to try it out:
It’s working great!
There’s a small problem with the way the bombs get dropped though, you can drop them wherever you want and this will create some problems when you need to calculate where the explosions should spawn.
You’ll learn the specifics when this tutorial covers how to make the explosions.
The next task it to make sure the bombs snap into position when dropped so they align nicely with the grid on the floor. Each tile on this grid is 1×1, so it’s fairly easy to make this change.
In Player.cs, edit Instantiate()
like so:
Instantiate(bombPrefab, new Vector3(Mathf.RoundToInt(myTransform.position.x), bombPrefab.transform.position.y, Mathf.RoundToInt(myTransform.position.z)), bombPrefab.transform.rotation); |
Mathf.RoundToInt
calls for the x and z values of the player position, rounds off any float to an int value, which then snaps the bombs to the tile positions:
Play the scene and run around while dropping some bombs. The bombs will now snap into place:
Although dropping bombs on the map is pretty fun, you know it’s really all about the explosions! Time to add some firepower to this thing. :]
To start off, you’re going to need a new script:
Now attach the Bomb script to the Bomb prefab:
Finally, open the Bomb script in your code editor. Inside of Start(), add the following line of code:
Invoke("Explode", 3f); |
Invoke()
takes 2 parameters, firstly the name of the method you want to be called and secondly, the delay before it gets called. In this case, you want to make the bomb explode in three seconds, so you call Explode()
— you’ll add it next.
Add the following under Update()
:
void Explode() { } |
Before you can spawn any Explosion GameObjects
, you’ll need a public variable of the type GameObject
so you can assign an Explosion
prefab in the Editor. Add the following right above Start()
:
public GameObject explosionPrefab; |
Save your file and return to the Editor. Select the Bomb prefab in the Prefabs folder and drag the Explosion prefab to the Explosion Prefab slot:
Once you’ve done this, return to the code editor. You finally get to write the code that makes things go boom!
Inside Explode()
, add the following lines:
Instantiate(explosionPrefab, transform.position, Quaternion.identity); //1 GetComponent<MeshRenderer>().enabled = false; //2 transform.FindChild("Collider").gameObject.SetActive(false); //3 Destroy(gameObject, .3f); //4 |
This piece of code does the following:
GameObject
is destroyed.
Save your Bomb script and return to the editor and give your game a play. Put down down some bombs and bask in the fiery goodness as they explode!
The next step is to add the iconic touch of expanding rows of explosions. To do that, you’ll need to create a coroutine.
People often confuse coroutines with multi-threading. They are not the same: Coroutines run in the same thread and they resume at intermediate points in time.
To learn more about coroutines and how to define them, check out the Unity documentation.
Return to your code editor and edit the Bomb script. Under Explode()
, add a new IEnumerator
named CreateExplosions
:
private IEnumerator CreateExplosions(Vector3 direction) { return null // placeholder for now } |
Add the following four lines of code between the Instantiate
call and the disabling of the MeshRenderer
in Explode()
:
StartCoroutine(CreateExplosions(Vector3.forward)); StartCoroutine(CreateExplosions(Vector3.right)); StartCoroutine(CreateExplosions(Vector3.back)); StartCoroutine(CreateExplosions(Vector3.left)); |
The StartCoroutine
calls will start up the CreateExplosions IEnumerator
once for every direction.
Now comes the interesting part. Inside of CreateExplosions()
, add this piece of code:
//1 for (int i = 1; i < 3; i++) { //2 RaycastHit hit; //3 Physics.Raycast(transform.position + new Vector3(0,.5f,0), direction, out hit, i, levelMask); //4 if (!hit.collider) { Instantiate(explosionPrefab, transform.position + (i * direction), //5 explosionPrefab.transform.rotation); //6 } else { //7 break; } //8 yield return new WaitForSeconds(.05f); } |
This looks like quite a complicated code snippet, but it’s actually fairly straightforward. Here’s a section-by-section explanation:
for loop
for every unit of distance you want the explosions to cover. In this case, the explosion will reach two meters.
RaycastHit
object holds all the information about what and at which position the Raycast
hits — or doesn’t hit.StartCoroutine
call. It then outputs the result to the RaycastHit object. The i
parameter dictates the distance the ray should travel. Finally, it uses a LayerMask named levelMask to make sure the ray only checks for blocks in the level and ignores the player and other colliders.for loop
. This ensures the explosion can’t jump over walls.for loop
. This makes the explosion more convincing by making it look like it’s expanding outwards.Here’s how it looks in action:
The red line is the raycast. It checks the tiles around the bomb for a free space, and if it finds one then it spawns an explosion. When it hits a block, it doesn’t spawn anything and it stops checking in that direction.
Now you can see the reason why bombs need to be snapped to the center of the tiles. If the bombs could go anywhere, then in some edge cases the raycast will hit a block and not spawn any explosions because it is not aligned properly with the level:
There’s still an error in the Bomb code — the LayerMask doesn’t exist yet. Right under the variable declaration of explosionPrefab
, add an extra line to it so it looks like this:
public GameObject explosionPrefab; public LayerMask levelMask; |
A LayerMask selectively filters out certain layers and commonly used with raycasts. In this case, you need to filter out only the blocks so the ray doesn’t hit anything else.
Save your bomb script and return to the Unity Editor. Click the Layers button at the top right and select Edit Layers…
Click the text field next to User Layer 8 and type in “Blocks“. This defines a new layer you can use.
Inside the hierarchy view, select the Blocks GameObject.
Change the layer to your newly created Blocks layer:
When the Change Layer dialog comes up, click the “Yes, change children” button, to apply to all of the yellow blocks scattered across the map.
Finally, select the Bomb prefab in the Prefabs folder in the project view, and change the Level Mask to Blocks.
Run the scene again and drop some bombs. Watch your explosions spread out nicely and go around the blocks:
Congratulations, you’ve just made it through the hardest part of this tutorial!
Go ahead and reward yourself with a refreshing drink or a delicious snack, think about what you just did, and then come back to play around with reactions to explosions!
When an explosion from one bomb touches another, the next bomb should explode — this feature makes for a more strategic, exciting and firey game.
Luckily this is quite easy to implement.
Open up the Bomb.cs script in your code editor. Add a new method named OnTriggerEnter
below CreateExplosions()
:
public void OnTriggerEnter(Collider other) { } |
OnTriggerEnter
is a pre-defined method in a MonoBehaviour
that gets called upon collision of a trigger collider and a rigidbody. The Collider
parameter, named other
, is the collider of the GameObject that entered the trigger.
In this case, you need to check the colliding object and make the bomb explode when it is an explosion.
First, you need know if the bomb has exploded. The exploded variable will need to be declared first, so add the following right under the levelMask
variable declaration:
private bool exploded = false; |
Inside OnTriggerEnter()
, add this snippet:
if (!exploded && other.CompareTag("Explosion")) { // 1 & 2 CancelInvoke("Explode"); // 2 Explode(); // 3 } |
This snippet does three things:
Explosion
tag assigned.
Explode
invocation by dropping the bomb — if you don’t do this the bomb might explode twice.
Now you have a variable, but it hasn’t been changed anywhere yet. The most logical place to set this is inside Explode()
, right after you disable the MeshRenderer
component:
... GetComponent<MeshRenderer>().enabled = false; exploded = true; ... |
Now everything is set up, so save your file and run the scene again. Drop some bombs near each other and watch what happens:
Now you’ve got some seriously destructive firepower going on. One little explosion can set your little game world on fire by triggering other bombs, allowing for these cool chain reactions!
The last thing to do is to handle players’ reactions to explosions (Hint: they’re not good!) and how the game translates the reaction into a win or draw state.
Open the Player.cs script in your code editor.
Right now, there’s no variable to indicate if the player is dead or alive, so add a boolean variable at the top of the script, right under the canMove
variable:
public bool dead = false; |
This variable is used to keep track if the player died to an explosion.
Next, add this above all other variable declarations:
public GlobalStateManager GlobalManager; |
This is a reference to the GlobalStateManager
, a script that is notified of all player deaths and determines which player won.
Inside OnTriggerEnter()
, there’s already a check to see if the player was hit by an explosion, but all it does right now is log it in the console window.
Add this snippet under the Debug.Log
call:
dead = true; // 1 GlobalManager.PlayerDied(playerNumber); // 2 Destroy(gameObject); // 3 |
This piece of code does the following things:
Save this file and return to the Unity editor. You’ll need to link the GlobalStateManager
to both players:
Run the scene again and make sure one of the players is obliterated by an explosion.
Every player that gets in the way of an explosion dies instantly.
The game doesn’t know who won though because the GlobalStateManager doesn’t use the information it received yet. Time to change that.
Open up GlobalStateManager.cs in your code editor.
For the GlobalStateManager
to keep track of what player(s) died, you need two variables. Add these at the top of the script above PlayerDied()
:
private int deadPlayers = 0; private int deadPlayerNumber = -1; |
First off, deadPlayers
will hold the amount of players that died. The deadPlayerNumber
is set once the first player dies, and it indicates which one it was.
Now that you have this set up, you can add the actual logic. In PlayerDied()
, add this piece of code:
deadPlayers++; // 1 if (deadPlayers == 1) { // 2 deadPlayerNumber = playerNumber; // 3 Invoke("CheckPlayersDeath", .3f); // 4 } |
This snippet does the following:
That last delay is crucial for allowing a draw check. If you checked right away, you might not see that everybody died. 0.3 seconds is sufficient to determine if everybody died.
You’re made it to the very last section! Here you create the logic behind choosing between a win or a draw!
Make a new method named CheckPlayersDeath
in the GlobalStateManager script:
void CheckPlayersDeath() { // 1 if (deadPlayers == 1) { // 2 if (deadPlayerNumber == 1) { Debug.Log("Player 2 is the winner!"); // 3 } else { Debug.Log("Player 1 is the winner!"); } // 4 } else { Debug.Log("The game ended in a draw!"); } } |
This is the logic behind the different if-statements in this method:
Save your code, then give the game a final run and test if the console window reads out what player won or if it ended up as a draw:
And that concludes this tutorial! Now go ask a friend if they want to share in the fun and blow them up when you get the chance. :]
Download the final project here.
Now you know how to make a basic Bomberman-like game by using Unity.
This tutorial used some particle systems for the bomb and the explosion, if you want to learn more about particle systems, check out my Introduction To Unity: Particle Systems Tutorial.
I highly encourage you to keep working on this game — make it your own by adding new features! Here are some suggestions:
Be sure to share your creations here, I’d love to see what you guys can come up with! As always, I hope you enjoyed this tutorial!
If you have any remarks or questions, you can do so in the Comments section.
The post How to Make a Game Like Bomberman appeared first on Ray Wenderlich.
In this video we break the collection view into multiple sections with each displaying a title.
The post Video Tutorial: Collection Views Part 3: Multiple Sections appeared first on Ray Wenderlich.
In this video we look at adding new cells to the collection view.
The post Video Tutorial: Collection Views Part 4: Inserting Cells appeared first on Ray Wenderlich.
In this video we look at subclassing the layout in the collection view, so that we can animate the addition of the cells.
The post Video Tutorial: Collection Views Part 5: Subclassing Layout appeared first on Ray Wenderlich.
Creating the visual elements of a game is only half of the work. Once you have your monsters in place and you have primed all your catapults to fire, a colossal battle may appear underwhelming when the greatest of explosions fail to produce even the tiniest of a whisper.
But when you add sounds to your game – even terrible ones at that, you may be shocked to discover the depth that they provide. Throw in some awesome sounds, and you’ll may discover an entirely new game.
Adding sound via code isn’t difficult, but Unity, which has an easy-to-use visual editor and works with a wide range of audio file formats, makes it even simpler. This tutorial will show you how to add sounds to the game Barn Blaster by using the Unity editor and by adding code, so if you are looking to add sounds to your next game, this tutorial is a great starting point!
In this tutorial, you’ll:
This is a beginner level tutorial, but you should be familiar with Unity’s interface. If you are new to Unity or need a refresher on the basic concepts, check out our Introduction to Unity tutorial.
First, download the source project: . Open the project in Unity and hit play.
You’ll see a bunch of tractors driving back and forth in front of a red barn. When you hit the space bar, a farm animal launches into the air. The goal of the game is to land the animal in the barn without getting hit by a tractor. If the animal gets hit by a tractor it dies; if it makes it into the barn, it’s a goal!
Right now, of course, it’s totally silent—not a moo to be heard! You’ll bring the game to life with sound.
The game is set up to launch a random animal: a cow, pig or sheep. Each one will play a different sound, so your first task is add the sound effect of the animal being launched.
The project has already been set up with the prefabs (object templates) for each animal. In the Project tab, click on the Assets/Prefabs folder and select the cow prefab.
The first thing this prefab needs is an AudioSource component to play sound. Click the Add Component button and type in AudioSource, then select the only option that appears.
The cow prefab can now play audio, but it needs an AudioClip to play. Currently, the AudioClip on the component you added is empty.
Some of you may be wondering: what exactly is an AudioSource? How does it differ from an AudioClip? You can assume the functions by their names, but assuming can be a dangerous thing—especially with flying livestock on the line!—so let’s cover some basics.
To play sound in Unity, you use an AudioSource and an AudioClip.
An AudioSource is what will actually play the sound in 2D or 3D space. In 3D space, the sound’s volume can vary based on how far the AudioSource is from the object listening to it (the AudioListener, which in this game is on the camera).
You can set an AudioSource to play sound in 2D space, which means it will play at a consistent volume regardless of the distance from the AudioListener.
The AudioClip is the actual audio file the AudioSource will play.
One important thing to note is that the AudioSource is a component. That means it’s an object that inherits from Unity’s MonoBehaviour
class and can be attached directly to any Unity GameObject
.
The AudioClip is a member variable that is found on the AudioSource (i.e. each AudioSource will have one AudioClip). You can attach components through the Unity editor and through code, though this tutorial only uses the editor.
A key part of playing sounds is setting up triggers for AudioSources to play. A trigger is just that: a condition which causes the AudioSource to play.
In this tutorial you will be editing code which has been pre-configured to only need you to code in the audio-playing portions, but behind the scenes is code that uses Unity’s physics engine.
Click on the Assets/Sounds folder in the Project view and find the moo sound file. With the cow prefab still highlighted in the Inspector, drag the moo sound file onto the AudioClip.
Make sure there is a check mark in the the Play On Awake box.
This means the sound file will play as soon as the object is created, which is exactly what you want. When the animal is launched toward the barn, it will let out an animal roar—or moo, in this case!
As a challenge, do the same thing for the Sheep and Pig prefabs.
Need help? Just open the spoiler to find out how.
Solution Inside | SelectShow> |
---|---|
|
At this point, all three animal prefabs have their voices added. To test it out, hit play and press the space bar to launch an animal. You should hear each animal playing its respective sound as it flies towards the barn.
Oinks and moos and baas—oh my!
The AudioSource can play a wide variety of file formats, including the most common mp3 and wav formats. If you ever find that your sound file is not playing, first check here to see if the file format is supported.
In some cases, sound files will be encoded into formats such as mp3 to take advantage of certain hardware decoding. In cases where mp3 is used, those mp3 files will be re-encoded, resulting in additional quality loss.
Since this tutorial was prepared ahead of time, the file formats should be fine, so if the sounds aren’t playing check the following:
The game is coming along great so far—all the animals are making their sounds as they fly towards the barn. But a few things are still missing:
Adding these sounds will give this game this game some real polish.
To add a buzzing sound to the tractors as they move back and forth, first hold Control on Windows and Command on Mac and click on all three tractors in the Hierarchy. Batch-add an AudioSource, then add the tractor sound clip just like you did with the animal sounds. Make sure Play On Awake is checked.
With all the tractors hooked up with sound, hit the play button.
Hmmm … it’s great the tractors have sound, but with all three playing at the same time it’s hard to distinguish between them. Plus it’s really loud.
As mentioned earlier, 3D sounds can play with a decrease in volume the further the AudioListener (in this game it’s on the camera) is from the AudioSource. Adding a falloff effect (so that the further the tractors are from the camera, the quieter they are) will make things sound a lot better.
Click on tractor in the Hierarchy; in the Inspector, look at the AudioSource component. There will be a drop down area called 3D Sound Settings. Here you can set the Doppler Level, the Rolloff and the Distance variables.
The Doppler Level is exactly what it sounds like: sound intensity varies to mimic the Doppler effect. The Rolloff Level is how much the volume quiets down the further it is from the AudioListener.
This is the closest tractor to the player, so its sound falloff should be more dramatic than the back two. Set the Volume Rolloff to Linear Rolloff, which will make the effects more pronounced, and set the Min Distance to 1 and the Max Distance to 9. Set the Doppler Level to 0.68.
This will make the front tractor sound loud as it approaches the middle of the screen (as it moves closer to the listener on the camera) and quieter as it moves off screen. Hit play to see this for yourself.
For the back two tractors, their sounds should be more like background noise; only the front tractor should have the exaggerated sounds.
To turn down the intensity of the back tractors, start by selecting tractor2 in the Hierarchy. Set the Volume Rolloff to Linear Rolloff, then set the Min Distance to 1 and the Max Distance to 30. Set the Doppler Level to 0.68. Next, select tractor3 in the Hierarchy and set the Volume Rolloff to Linear Rolloff. Set the Min Distance to 1 and the Max Distance to 50. Set the Doppler Level to 0.68.
Hit play and listen to the different sound levels of the tractors as they move back and forth.
The tractors are way too loud, especially with three of them playing at once. Set the Volume slider on their AudioSource to 0.1.
If you play the game for more than 40 seconds, you’ll notice the tractor sounds cut out. That’s because their AudioSource hasn’t been set to loop. To change this, click the Loop box for each tractor’s AudioComponent.
When the animals hit a tractor, they unfortunately get clobbered by it. What’s even more unfortunate is that there is currently no sound when that happens! As mentioned earlier, the tractors are using the Unity physics engine and listening for collisions with the animals. When an animal collides with a tractor, it tells the animal to die—that’s when the sound needs to play.
First, you will need to attach an AudioClip of the death sound to the Tractor component. To do this, hold Control on Windows or Command on Mac and click on the three tractors in the Hierarchy. Click on the Sounds folder in Assets and drag the death file to the Death Sound field of the Tractor component:
To code in the animal death sound, start by double-clicking on the Tractor C# script to open it in your editor. Before the closing brace of the if statement
, add the following code:
audioSource.PlayOneShot(deathSound); |
The final result should look like this:
void OnCollisionEnter(Collision col) { if (col.gameObject.GetComponent<Animal>() && !col.gameObject.GetComponent<Animal>().isDead) { Destroy(col.gameObject); audioSource.PlayOneShot(deathSound); } } |
Hit Control-S on Windows or Command-S on Mac to save the script.
PlayOneShot()
plays the sound once. You are passing in the sound you added to the tractor and then playing it once from the tractor. The reason the tractor (rather than the animal) should play the sound is that when the animal is hit by the tractor, the literal GameObject
that was the animal is deleted. Since it no longer exists, the animal can’t play a sound. You could turn the mesh off and play the sound from the animal that way, but that is more complicated.
The benefit of using PlayOneShot()
is that the sound will play to completion even if PlayOneShot()
is called again. If this were not the case, the animal sounds would cut each other off, sounding jerky to user.
Hit play and exercise your darker side by intentionally launching animals into the tractors instead of aiming for the safety of the barn. You should hear a “squish” sound as they collide with the tractor.
The only missing sound at this point is the success sound when an animal makes it to the barn.
To add that, start by clicking on the barn object in the Hierarchy. In the Inspector, add an AudioSource component to it, then drag the win sound from Assets/Sounds to the AudioClip field. This time, make sure Play On Awake is turned off. This sound will only be played if an animal makes to the barn.
Double-click on the Barn script in Assets/Scripts. Underneath the opening brace of the if statement
, add the following:
if(col.gameObject.GetComponent<Animal>()) |
It should look like this:
void OnCollisionEnter(Collision col){ if(col.gameObject.GetComponent<Animal>()){ GetComponent<AudioSource>().Play(); Destroy(col.gameObject); } } |
This tells the barn that when an animal collides with it, it should get the AudioSource component and play it. Save your changes, then hit play and launch animals into the barn. A success sound will now play when the animal makes it to the barn.
Success!
There’s one last bit of polish you can add for very little effort. Hearing the exact same sound over and over is annoying. To keep sounds fresher and less irritating, code in some variance to the pitch.
Open the Animal in the Scripts folder. Add the following just under public bool isDead = false;
void Start(){ AudioSource audioSource = GetComponent<AudioSource>(); audioSource.pitch = Random.Range(0.8f, 1.5f); audioSource.Play(); } |
This code fetches the AudioSource component and sets the pitch variable to a random value between 0.8 and 1.5. Now hit play and launch the animals. Their animal sounds will vary each time. Pretty cool, right?
Great job adding your first sound effects to a Unity game! Now your animals can happily moo, oink and baa their way into the barn—unless they get hit by a tractor, of course.
If you ran into any issues, download the completed project: Barn Blaster – Complete Project
For more fun, try adding different pitches to each of the tractors, to the success sound that plays when an animal makes it to the barn and to the death sounds. You can also try adding different animal sounds and a unique death sound for each animal (although that will require a little more coding, along with finding more audio files).
To learn more about Unity’s sound engine, check out Unity’s Live Training on Adding Sound Effects to Your Game. Also, check out the AudioSource and AudioClip Unity documentation.
Stay tuned for future Unity tutorials! Feel free to leave comments below, or join the conversation in our forums.
The post Introduction to Unity Sound appeared first on Ray Wenderlich.