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

Screencast: Localization

$
0
0

Translating your app for a specific language or region is known as Localization. Let's learn to localize an app that already has Internationalization support.

The post Screencast: Localization appeared first on Ray Wenderlich.


Readers’ App Reviews – January 2018

$
0
0

Happy New Years to the raywenderlich.com readers! We have received some awesome apps from you this month. Its the perfect start to the year, let’s check them out.

I’m honored you are taking a quick break to see what the community has been building. Every month, readers like you release great apps built with a little help from our tutorials, books, and videos. I want to highlight a few today to give just a peek at what our fantastic readers are creating.

This month we have:

  • An app to help you with planning
  • A calculator for your investments
  • A game using chess pieces
  • And of course, much more!

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

Due Life


If you have trouble scheduling your weeks or forgetting plans, then Due Life is here to help you out!

Due Life is a combination of a checklist app and a calender app. It allows you to make tasks with a title, due date, due time, and notfication option. You can also add extra notes to eack task if you need to be a bit more precise in the task description.

Then, you can add the task to different lists so that you are able to keep them all organized. Once you have composed your tasks for the week, you can tap and drag them to the calender at the top of the screen to mark them in the app. The app will notify you of when the task needs to be done!

Due Life is a much needed app for people who want to be more organized. If you are one of those people, give it a download.

Dividend Calc


If you are an investor and like to buy and sell stocks, then the Dividend Calc will soon become one of your favorite apps.

The Dividend Calc allows you to input the amount of shares you have for each stock and it will provide you will how much annual dividend returns you are expected to recieve from all of your stocks. It also show other dividend information such as quarterly returns, number of shares, targeted amount of shares, etc.

The app shows extra information about the stock itself so that you can view everything about that stock without leaving the app. Finally, you can set your target annual dividend amount and watch as you get closer to achieving your goals.

The Dividend Calc is an awesome app, you should download it and try it out!

Pocket Money


Do you give you kids an allowance but cannot seem to remember what you have given them for the past week? Well, Pocket Money has got your back!

Pocket Money is a simple but useful app that allows you to track your children’s allowances. Add up to four children and input their name, when they should recieve their allowance, and how much they should be given.

Then, Pocket Money keeps up with how much your kids have been given and when they last recieved their allowance. Each child’s profile can be customized differently so that their funds can be accounted for accordingly.

Pocket Money is great for keeping up with your kid’s allowances. Download it and give it a try!

Knights


Knights is an interesting puzzle game that will challenge you for hours.

The object of the puzzle is to move four knight pieces from one side of the board to the other, but all of the spaces on the board are occupied by other pieces except for one.

You must move the other pieces out of the way by using their classic Chess movement restrictions in order to make room for the knights to move across the board to the other side. Knights is a great example of using pre-exsisting mechanics to create an entirely new and fun game!

If you like Chess or puzzle games, then you will love Knights. Click or tap on the app store link below to download it.

FBSearch


If you are searching for demographic reasons, looking for new friends, or need to do bulk searches for any reason, this app will be helpful to you.

FBSearch is an app that lets you perform bulk searches on Facebook. You can tailor your searches through many different parameters such as Gender, Relationship Status, Location, Company, etc. It will display a list of people that match your search parameters and you will be able to view their profiles.

You can also add people to your favorites so that you will not forget to contact them in the future! The app is free but has some limitations on search parameters, which you can remove for just 99 cents!

FBSearch is an awesome app for anyone that has recently moved to a new place. Download it if you need some help finding friends on Facebook!

Face-Off


Many people love posting images of them online to share what they are doing with their friends and family, but there are strangers that might also be able to find your pictures. Thankfully, Face-Off is here to remedy this issue.

Face-Off is an app that allows you to select a picture to edit. The app will scan the photo for any faces and put a box around them. You can then tap on each face that you want to blur and adjust the blur slider to an amount that you prefer.

This feature is great because it allows you to customize which faces you want hidden and which ones you want to be normal. After you are finished editing the photo, you can share it to any social media website with added privacy that can be achieved in just a few seconds.

If you are worried about you or your loved one’s faces being shown on the internet, Face-Off is a very simple and easy way to secure your privacy. Download it and try it out!

FanBook


If you are a big sports fan and love to share different strategies that your favorite teams use to crush their opponents, then FanBook is here to help.

FanBook allows you to create your own playbook and share them with your friends in a simple way. First, create and name your team. You can choose from a team of 5, 7, or 11 players. Second, enter your line-up of players including their name, age, height, weight, etc.

Lastly, you can position your players anywhere on the field and draw arrows, as well as other markings, to plan out your strategy. After you are finished creating your Position Diagram, you can share it with your friends in any way you wish.

FanBook is a must have for those sports fans who love discussing and sharing team strategies with their friends. Download it today and give it a try!

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 you 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 – January 2018 appeared first on Ray Wenderlich.

Video Tutorial: Beginning App Asset Design Part 1: Composing Shapes

Swift Algorithm Club: Hash Tables

$
0
0

Swift Algorithm Club: Hash Tables

The Swift Algorithm Club is an open source project to implement popular algorithms and data structures in Swift.

Every month, the SAC team will feature a cool data structure or algorithm from the club in a tutorial on this site. If your want to learn more about algorithms and data structures, follow along with us!

In this tutorial, you’ll learn how to implement a Swift hash table. This data structure was first implemented by Matthijs Hollemans, and is now refactored for tutorial format.

Getting Started

As a Swift developer, you’re familiar with the Dictionary structure. If you’re also a Kotlin developer, you would be familiar with the HashMap class. The underlying data structure that powers both of these constructs is the hash table data structure.

The Swift dictionary is a collection of key-value pairs. Storing an value in a dictionary requires you to pass in a value with a key:

var dictionary: [String: String] = [:]

// add key-value pair
dictionary["firstName"] = "Steve"

// retrieve value for a key
dictionary["firstName"] // outputs "Steve"

Underneath the hood, the dictionary will pass the key-value pair to a hash table for storage. In this tutorial, you’ll learn about a basic implementation of the hash table and learn about its performance.

Hash Tables

A hash table is nothing more than an array. Initially, this array is empty. When you put a value into the hash table under a certain key, it uses that key to calculate an index in the array. Here is an example:

In this example, the key "firstName" is maps to array index 1.

Adding a value under a different key puts it at another array index:

The trick is how the hash table calculates those array indices. That is where the hashing comes in. When you write the following statement,

hashTable["firstName"] = "Steve"

the hash table takes the key “firstName” and asks it for its hashValue property. Hence, keys must conform to the Hashable protocol.

Hash Functions

When you write "firstName".hashValue, it returns a big integer: -8378883973431208045. Likewise, "hobbies".hashValue has the hash value 477845223140190530.

Hash values are calculated by a hash function, which takes some input and returns an integer:

To achieve a better understanding of how hash functions work, you’ll implement two simple hash functions of your own. Open up a playground and write the following in the playground page:

func naiveHash(_ string: String) -> Int {
  let unicodeScalars = string.unicodeScalars.map { Int($0.value) }
  return unicodeScalars.reduce(0, +)
}

This above hash function uses the unicode scalar representation of each character and sums it up. Write the following into the playground page:

naiveHash("abc") // outputs 294

While this hash function does map a string to an integer value, it’s not very good. See why by writing the following:

naiveHash("bca") // also outputs 294

Since naiveHash only sums up the unicode scalar representation of each character, any permutation of a specific string will yield the same result.

A single lock is being opened by many keys! This isn’t good. A significantly improved hash function can be obtained with just a bit more effort. Write the following in the playground page:

// sourced from https://gist.github.com/kharrison/2355182ac03b481921073c5cf6d77a73#file-country-swift-L31
func djb2Hash(_ string: String) -> Int {
  let unicodeScalars = string.unicodeScalars.map { $0.value }
  return unicodeScalars.reduce(5381) {
    ($0 << 5) &+ $0 &+ Int($1)
  }
}

djb2Hash("abc") // outputs 193485963
djb2Hash("bca") // outputs 193487083

This time, the two permutations have different hash values. The hash function implementation in the Swift Standard Library for String is far more complicated, and uses the SipHash algorithm. That's beyond the scope of this tutorial.

Note:
  • If you're interested in how the strings compute the hash value, you can check out the source code here.
  • Swift uses the SipHash hash function to handle many of the hash value calculations. The API to this implementation is private, but a public implementation has been done here.

Keeping Arrays Small

"firstName" has a hash value of -8378883973431208045. Not only is this number large, it's also negative. So how do you fit it into an array?

A common way to make these big numbers suitable is to first make the hash positive and then take the modulo with the array size.

In the example earlier, the array had a size of five. The index for the "firstName" key becomes abs(-8378883973431208045) % 3 = 1. You can calculate the array index for "hobbies" is 2.

Using hashes in this manner is what makes the dictionary efficient; To find an element in the hash table, you must hash the key to get an array index and then look up the element in the underlying array. All these operations take a constant amount of time, so inserting, retrieving, and removing are all O(1).

Note: It is difficult to predict where in the array your objects end up. Hence, dictionaries do not guarantee any particular order of the elements in the hash table.

Avoiding Collisions

There is one problem. Taking the modulo of the hash value with a number can lead to a same value. Here's one such example:

djb2Hash("firstName") % 2 // outputs 1
djb2Hash("lastName") % 2 // outputs 1

This example is a little contrived, but serves the purpose of highlighting the possibility of a hash mapping to the same index. This is known as a collision. A common way to handle collisions is to use chaining. The array looks as follows:

With chaining, keys and their values are not stored directly in the array. Instead, each array element is a list of zero or more key-value pairs. The array elements are usually called buckets, and the lists are called the chains. Here we have 3 buckets, and the bucket at index 2 has a chain. The other buckets are empty.

Retrieving Items

Here's an example of retrieving an item from the hash table:

let x = hashTable["lastName"]

The hash table first hashes the key "lastName" to calculate the array index, which is 2. Since bucket 2 has a chain, you step through the list to find the value with the key "lastName". This is done by comparing the keys using a string comparison. The hash table checks that the key belongs to the last item in the chain and returns the corresponding value, "Jobs".

Common ways to implement this chaining mechanism are to use a linked list or another array. Chains should not become long because looking up items in the hash table would become a slow process. Ideally, you would have no chains at all, but in practice it is impossible to avoid collisions. You can improve the odds by giving the hash table enough buckets and usin high-quality hash functions.

Note: An alternative to chaining is "open addressing". The idea is this: if an array index is already taken, we put the element in the next unused bucket. This approach has its own upsides and downsides.

Implementation

In the Sources directory, create a new Swift file and name it HashTable.swift. Delete any text in the file and write the following:

public struct HashTable<Key: Hashable, Value> {
  private typealias Element = (key: Key, value: Value)
  private typealias Bucket = [Element]
  private var buckets: [Bucket]

  private(set) public var count = 0
  public var isEmpty: Bool {
    return count == 0
  }

  public init(capacity: Int) {
    assert(capacity > 0)
    buckets = Array<Bucket>(repeating: [], count: capacity)
  }
}

Although you created a hash function based on the djb2 hash algorithm, it's better to leverage Apple's version. Through the constraining the Key as Hashable, your dictionary enforces that all keys have a hash value, so your dictionary doesn't need to worry about calculating the actual hash.

The main array is named buckets It has a fixed size provided by the init(capacity) method. You also keep track of how many items have been added to the hash table using the count variable.

Operations

Now that the scaffolding for your hash table is complete, you'll want to define the mutating operations for this structure. There are four common things you will do with a hash table:

  • insert a new elements
  • look up an element
  • update an existing element
  • remove an element

You'll want the syntax to look like this:

hashTable["firstName"] = "Steve" // insert
let x = hashTable["firstName"] // lookup
hashTable["firstName"] = "Tim" // update
hashTable["firstName"] = nil // delete

Start by defining the following helper method in your HashTable structure:

private func index(for key: Key) -> Int {
  return abs(key.hashValue) % buckets.count
}

This method will help ensure the key maps to an index within the bounds of the storage array. Next, add the following just below index(for:):

Value Retrieval

Write the following inside the HashTable structure:

// 1
public subscript(key: Key) -> Value? {
  get {
    return value(for: key)
  }
}

// 2
public func value(for key: Key) -> Value? {
  let index = self.index(for: key)
  return buckets[index].first { $0.key == key }?.value
}
  1. The subscript method takes a key and returns a value. The actual logic will reside in the value(for:) method.
  2. value(for:) first calls index(for:) to convert the key into an array index. That returns the bucket number, but this bucket may be used by more than one key if there were collisions. Thus, you use the first method that takes a closure, where you compare the key of each element with the key you want to match it with.

    If a match is found, you use optional chaining to extract the value. Otherwise, first will return nil, signifying that the key doesn't map to a value in the hash table.

Inserting Values

The subscript method can also work as a setter. Add the following code at the bottom of subscript:

set {
  if let value = newValue {
    update(value: value, for: key)
  }
}

This adds a setter to the subscript operation. newValue is a invisible reference to the value that is being assigned to the subscript. Once again, you'll be defining actual logic in a helper method.

Add the following below value(for:):

@discardableResult
public mutating func update(value: Value, for key: Key) -> Value? {
  let index = self.index(for: key)

  // 1
  if let (i, element) = buckets[index].enumerated().first(where: { $0.1.key == key }) {
    let oldValue = element.value
    buckets[index][i].value = value
    return oldValue
  }

  // 2
  buckets[index].append((key: key, value: value))
  count += 1
  return nil
}

Here's the play-by-play:

  1. You first check to see if the value is already inside a bucket. If it is, you update the value at the index i.
  2. If execution comes to this point, it means the key doesn't map to a particular value inside the hash table. You then add the new key-value pair at the end of the bucket.

With that, you're finally able to try your hash table out. Navigate back to the playground page and write the following at the bottom of the playground:

var hashTable = HashTable<String, String>(capacity: 5)
hashTable["firstName"] = "Steve"

if let firstName = hashTable["firstName"] {
  print(firstName)
}

if let lastName = hashTable["lastName"] {
  print(lastName)
} else {
  print("lastName key not in hash table")
}

You should see the following output in the console:

Steve
lastName key not in hash table

Removing Items

The final operation you'll implement is the one that removes the key. Update the subscript method to the following:

public subscript(key: Key) -> Value? {
  get {
    return value(for: key)
  }

  set {
    if let value = newValue {
      update(value: value, for: key)
    } else {
      removeValue(for: key)
    }
  }
}

Next, add the remove(value:for:) method at the bottom of the HashTable structure:

@discardableResult
public mutating func removeValue(for key: Key) -> Value? {
  let index = self.index(for: key)

  // 1
  if let (i, element) = buckets[index].enumerated().first(where: { $0.1.key == key }) {
    buckets[index].remove(at: i)
    count -= 1
    return element.value
  }

  // 2
  return nil
}

This is fairly similar to the update method. You first check to see if the value is in the bucket. If it is, you remove the key in the chain, decrement the count, and return the value. Otherwise, you return nil, since you couldn't find the key-value pair to remove.

Navigate back to the playground page and write the following:

hashTable["firstName"] = nil

if let firstName = hashTable["firstName"] {
  print(firstName)
} else {
  print("firstName key is not in the hash table")
}

You should see the following in the console:

Steve
lastName key not in hash table
firstName key is not in the hash table

Resizing the Hash Table

This version of the hash table always uses an array of fixed size or capacity. If you have many items to store in the hash table, choose a prime number greater than the maximum number of items.

The load factor of a hash table is the percentage of the capacity that is currently used. If there are 3 items in a hash table with 5 buckets, then the load factor is 3/5 = 60%.

If the hash table is small, and the chains are long, the load factor can become greater than 1, which is a sign of bad performance. One way to avoid this is to resize the hash table. Adding the code for this condition is left as an exercise for the reader. Keep in mind that making the buckets array larger will change the array indices that the keys map to! This requires you to insert all the elements again after resizing the array.

Where to Go From Here?

I hope you enjoyed this tutorial on implementing a Swift hash table!

Here is a playground with the above code. You can also find the original implementation here.

This was just one of the many algorithms in the Swift Algorithm Club repository. If you're interested in more, check out the repo.

It's in your best interest to know about algorithms and data structures - they're solutions to many real-world problems, and are frequently asked as interview questions. Plus it's fun!

So stay tuned for many more tutorials from the Swift Algorithm club in the future. In the meantime, if you have any questions on implementing trees in Swift, please join the forum discussion below.

Note: The Swift Algorithm Club is always looking for more contributors. If you've got an interesting data structure, algorithm, or even an interview question to share, don't hesitate to contribute! To learn more about the contribution process, check out our Join the Swift Algorithm Club article.

The post Swift Algorithm Club: Hash Tables appeared first on Ray Wenderlich.

Video Tutorial: Beginning App Asset Design Part 1: Challenge – Boolean Operations

Video Tutorial: Beginning App Asset Design Part 1: Bezier Curves

Open-Source Collaboration Using Git and GitHub

$
0
0
Note: This tutorial assumes the following:
  • You already have a GitHub account. If you don’t, sign up for a free one here.
  • Git is installed on your system. You can check this by opening up Terminal and typing which git. If there’s a result — typically /usr/bin/git — then you’re good to go. If not, you can install Xcode or download an installer from the Git website here.

Open-Source Collaboration Using Git and GitHub

You’ve come across a project on GitHub you want to contribute to. Great! That seems easy enough. But working on a global, open-source project can be quite intimidating for first-timers.

In this tutorial, you’ll learn the ins and outs of contributing to open-source by moving through the entire workflow of open-source contributions, from retrieving the code, to creating issues, to pushing your new contributions. And you’ll get a good laugh along the way as you dive into the tutorial’s sample project!

Getting Started

Open-source development is a huge part of the software development industry. Many tools and libraries you use everyday have been shaped by millions of humans all around the globe. Dependency managers such as CocoaPods and Carthage that iOS developers use daily are driven by public contributions. Even the Swift language itself is open-source.

There are many reasons to contribute to open-source projects:

  • It’s a great way to build a highly accessible portfolio. Your GitHub profile can be a treasure trove of your technical expertise for inquiring minds.
  • Open-source contributions rely on collaboration between fellow developers. Your participation and contributions to project discussions are an excellent indication of your abilities as a team player.
  • Current and future employers, along with your peers in the industry, will take note of your work in the community.
  • It’s a great way to learn and expand your development skills!

Contributing to open-source starts by choosing the project you want to contribute to. One way to find a project that is relevant to your interests is to check out the topics section in GitHub. Here’s the Swift topic list:

List of Swift Category Projects on Github

Checking out the trending category is a good way to find popular projects as well.

If you know exactly which repo you want to contribute to, you can also visit the project page directly. Last year, Ray Wenderlich unloaded many programming dad jokes at RWDevCon, leaving the audience gasping for air.

In an effort to bring more humor to the programming industry, you’ll be contributing your very own programming dad jokes to our first open-source joke repository.

Navigate to the URL for the repository for this tutorial — https://github.com/raywenderlich/DadJokes and you should see the DadJokes project on GitHub.

You should see something like this:

RayWenderlich Dad Jokes Repository on Github

Keep this page handy, you’ll be visiting it often.

A Bit of Terminology

Before you begin piling on the puns, you’ll need to know some common terminology behind open-source-projects.

Repo

Short for repository, a repo is a project on GitHub. DadJokes can therefore be classified as a repo. You’ll use and hear this word fairly often in your forays into open-source.

Maintainers

“Maintainers” refers to the users who have permission to make changes to the repo. The owner of the repo has power to grant different level of privileges to certain users. The ability to set these access levels is important to prevent malicious users from altering the code – or in this case, blunting the puns.

README

The README file usually refers to the Markdown file that summarizes what the project is about.

Raising an issue

A good first step in the open-source process is to look at an issue. An issue is a way to create a discussion in the community, whether it’s to bring up a question, provide feedback, or contacting the maintainers.

Navigate to the DadJokes repo and click on the Issues tab:

Github Issues tab image

This tab contains a list of issues raised by community members. You’ll begin your adventure by creating an issue.

Click the green New Issue button, and you should see the following:

Github New Issue Page

If contributing guidelines are available for a repo, you’ll see a warning dialog. Since you’re a good citizen, click on the highlighted contributing text and check out the rules.

After being humored by the contributing guidelines, head back to the issue creation page. The first order of business is to create a title. Write Joke as your title.

Next is the body of the issue. You should see some pre-filled text. If the maintainer added an ISSUE_TEMPLATE.md file to their repository, GitHub will render the contents of the file as a template for every new issue.

For this particular issue, write the following into the issue body:

Issue created in response to #1

### Question
What did the Swift String hash function say to the others?

### Answer
I Sip Hash Are You?

All GitHub issues are paired with a number. This number can be referenced within the repository, allowing you to “deep link” an issue from various discussions. In this particular issue, you’ve referenced issue #1 as part the body. Click the Preview tab to check out the issue:

Preview of the issue to submit on Github

Click on Submit new issue to create your first issue.

Note: I’m terrible at making dad jokes. SipHash is the hashing algorithm for Swift strings. You can check out the source code for that here.

Downloading a Repo

After writing an issue, you’ll probably wait for feedback to decide how to proceed. While you wait for that, you’ll explore the project in depth. The first step is to actually get the project code onto your machine.

Forking

Before downloading someone else’s repo, you’ll need to create a fork, which is a personal copy of someone else’s project. Forks act as a bridge between the original repository and your personal copy.

Create a fork by clicking on the Fork button located at the top-right corner of the repo:

Github showing the Fork button for a repository

Note: If you belong to multiple organizations, you’ll be prompted to choose where the fork should reside in. Choose your personal account.

In a few moments, GitHub should complete forking the repository. You’ll find yourself in a familiar page:

Forked Github repository page

This is your personal replica of the original repo. You’re free to make any changes with this copy, and it won’t affect the original one. Now that you have your fork, it’s time to clone it onto your computer.

Cloning

In your fork of the DadJokes repo, click on Clone or download, and you should be presented with a popover dialog:

Github clone / download popover dialog

Make sure you’re cloning with HTTPS, and copy the link. Next, open Terminal and execute the following:

cd ~/Desktop
git clone <your copied HTTPS url here>

This will clone the repository in your Desktop directory.

Exploring the Project

After cloning the repository, you should see a new folder named DadJokes on your desktop. Navigate into the project folder and open DadJokes.xcodeproj in Xcode. Build and run the app on an iPhone simulator, and you should see the following:

DadJokes application initial joke list

Depending on when you read this article, there may be a few new jokes added by other contributors. The more the merrier, I say!

Making Contributions

Bring up Terminal again. Execute the following commands in Terminal:

cd ~/Desktop/DadJokes
git checkout -b feature/my-new-joke

This creates a new branch for the new modifications you’ll be making to the source code. Next, open JokeStore.swift and find the following line:

private var storage: [Joke] = [
  // ...
]

storage is a hard-coded array of Joke structures. The table view controller from earlier lists all the jokes contained in this array. To contribute to this project, you’ll need to add a joke (or a few) in this array.

Add a new Joke at the front of storage:

private var storage: [Joke] = [
  // add new joke here (feel free to add your own)
  Joke(description: "You should be careful with functions that return a value...",
    punchline: "In fact, I would just a void them."),

  // ... other jokes
]

Build and run. You should see the new joke at the top of the table view:

Dadjokes application displaying your new joke

Pushing to Your Remote

A remote refers to the location of the repository on GitHub. Now you’ve made some changes to your personal copy project, it’s time to push the changes to your remote. Type the following in Terminal:

git add .
git commit -m "Added new joke"
git push --set-upstream origin feature/my-new-joke

You may have to enter your GitHub login and password upon pushing. Once you’ve done that, your changes will have been pushed back up to GitHub. Your personal copy is now updated with the new joke, but the original repo won’t be able to see the changes. To make them visible, you’ll have to submit a pull request.

Pull Requests

A pull request is proposed change to a project in a GitHub repository. The community can view this pull request to discuss the change and any potential modifications.

Head back to the original DadJoke repository and click on New pull request:

Original DadJokes repository highlighting the New Pull Request button

This brings you to the pull request creation page:

Create Pull Request Github page

Your new joke is in your personal fork of the repo, so you’ll need to click on compare across forks. This brings up the following UI:

Github compare across forks UI

The left options represent the base fork and branch. Since you want to create a pull request for the original repository and the master branch, you’ll leave those two options alone. You need to modify the two options on the right side. Update them to match your own fork and your new branch. Here’s an example of what it would look like:

Modifying the forked repository option on Github

Modifying the faked repository branch with the changes on Github

With that, you’re presented with a similar UI to the issue creations page:

Pull Request creation page Github

This is the final step before publicly announcing your proposal to the community. The bottom section of the page shows a summary of the changes you’ve proposed for this pull request.

Change the title of the pull request to <your name>’s Joke (substituting your own name into the angle brackets), and add the following for the body:

This addresses issue #1. Adds a dad joke.

#1 creates a reference to the issue or pull request with that number. In this case, #1 refers to the issue asking for more jokes. When you create a PR, strive to be concise and reference related discussions. This gives more context to your PR and makes it easier for maintainers to review and give feedback.

Click on Create pull request to publish it to the public.

Reviewing a PR

GitHub has a great tool for streamlining the review process. This tool can be accessed by clicking on the Files changed tab of a particular pull request:

Viewing a pull requests files changed tab on Github

The “Files changed” tab lists all the changes being proposed by a particular pull request. Additions are highlighted as green, while removals are highlighted as red.

Hover over the green line where you added your joke. You should see a blue “+” button to the left of the line. Click on it:

Writing a comment for a specific change within your pull request Github

When doing reviews, you’ll be going through each change and giving comments if necessary. Write LOL, my sides :+1: in the text view and click Start a review. Comments created this way will be batched until you submit the review, so don’t be afraid to take a break for bigger PRs.

Since this one’s fairly small, you’ll have to be content with just that one comment. Click Finish your review and leave a summary of your findings:

Submit review screen Github

Normally you wouldn’t review your own contribution, but for the sake of this tutorial, you’ve done just that. Head over to the other PRs and apply the same procedure to give your opinions!

Where to Go From Here?

I hope you’ve enjoyed this tutorial on open-source contributions. There are lots of projects out there, and you’re now equipped to contribute to them. There are related tutorials of interest if you want to know more:

  • The Swift Algorithm Club is one of the most popular Swift repositories on GitHub. Check out the introductory article to learn more about contributing to it.
  • The beginning git video course is a great way to learn more about git version control. If you want to be an open-source contributor, having a thorough knowledge of git is highly beneficial.

If you have any questions or comments, please join the discussion below!

The post Open-Source Collaboration Using Git and GitHub appeared first on Ray Wenderlich.

Video Tutorial: Beginning App Asset Design Part 1: Challenge – Tracing Complex Shapes


Video Tutorial: Beginning App Asset Design Part 1: Text & Typography

Video Tutorial: Beginning App Asset Design Part 1: Conclusion

Debugging and Historical Nerd Off – Podcast S07 E09

$
0
0

In this episode Mark Dalrymple returns to talk with Dru and Janie about Debugging techniques and then Dru and Mark lead Janie on a Nerdtastic journey into Ye Olde Days of programming on Apple Platforms.

[Subscribe in iTunes] [RSS Feed]

This episode was sponsored by Rollbar.

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

Episode Links

Debugging

Nerd Off

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 Debugging and Historical Nerd Off – Podcast S07 E09 appeared first on Ray Wenderlich.

Video Tutorial: Beginning App Asset Design Part 2: Introduction

Video Tutorial: Beginning App Asset Design Part 2: Raster Basics

Google Maps iOS SDK Tutorial: Getting Started

$
0
0
Update note: This tutorial has been updated to Xcode 9.2, iOS 11.2, Swift 4 and Google Maps SDK 2.5.0 by Ron Kliffer. The original tutorial was written by Ron Kliffer.

Google Maps iOS SDK Tutorial: Getting Started

Up to iOS 5, Google Maps was an integral part of iOS and was the mapping engine used by all iOS devices. With the release of iOS 6 in 2012, Apple made a dramatic change and replaced Google Maps with an in-house mapping engine: MapKit.

Just a few months later, Google released its own standalone Google Maps app for iOS, along with the Google Maps iOS SDK for developers.

There are benefits and drawbacks to both MapKit and the Google Maps iOS SDK, but this tutorial will walk you through implementing Google Maps into your apps to see for yourself how well it can work in your geolocating apps.

In this tutorial, you’ll build an app called Feed Me, which gets the user’s current location and searches for nearby places to eat, drink, or even go grocery shopping. The results will be presented in-app using the Google Maps iOS SDK.

This tutorial assumes some familiarity with Swift and iOS programming. If you’re new to Swift, or to iOS programming altogether, you might want to check out some of our other tutorials before continuing.

This tutorial also requires familiarity with CocoaPods. You must have CocoaPods installed in order to follow this tutorial. To learn more about CocoaPods, check out this tutorial by Joshua Greene, published right here on the site.

This tutorial uses Xcode 9.2 and iOS 11.2, and requires knowledge of Auto Layout and Swift of course.

Getting Started

Download the Feed Me Starter Project This project already uses CocoaPods, so open it using the Feed Me.xcworkspace file.

Take a look around to get familiar with the project. The important elements to notice are:

  • MapViewController.swift: This is the main view controller of this project, and you’ll only be working with this controller in this tutorial.
  • GoogleDataProvider.swift: This is a wrapper class for making Google API calls. You’ll review the methods it contains later in the tutorial.
  • GooglePlace.swift: This is a model for place results returned from Google.
  • MarkerInfoView.swift: This is a subclass of UIView that displays details of places. It comes with a matching xib file.

Before you start coding it’s a good idea to see how the app works. Build and run your app; you’ll see the following screen appear:

Right now all you’ll see is a blank screen with a pin in the middle. Press the action button on the right side of the navigation bar to see the TypesTableViewController screen like so:

That’s all there is to see in the app at the moment — it’s up to you to add some magic!

Creating API Keys

The first thing you’ll need are some API keys for the Google Maps SDK and the Google APIs you’ll be using. If you don’t already have a Google account, create one (they’re free!) and log in to the Google Developers Console.

Click on Create Project, name your project Feed Me, and click Create:

If your project doesn’t appear straight away, refresh the page until it does. Select the newly created project to access its settings. Select APIs & SERVICES and then Library from the left pane menu:

Search and enable these APIs:

  • Google Maps SDK for iOS
  • Google Places API Web Service

Select Credentials under APIs & services in the left pane menu. Click Create credentials, and then click API key to create the key:

Copy the key and click Close:

You’ll use the key in a moment, but first you’ll add the actual Google Maps iOS SDK.

Adding the SDK

Open Podfile (in the Pods project) and add the following, right above end:

pod 'GoogleMaps'

Next, Open Terminal and navigate to the directory that contains your Feed Me project by using the cd command:

cd ~/Path/To/Folder/Containing/Feed Me

Enter the following command to install the Google Maps iOS SDK:

pod install

You should see output similar to the following:

Downloading dependencies
Installing GoogleMaps (2.5.0)
Using SwiftyJSON (4.0.0)
Generating Pods project
Integrating client project

You now have GoogleMaps in your project. Doesn’t CocoaPods make life a whole lot easier? :]

Open AppDelegate.swift and replace it’s contents with the following:

import UIKit
import GoogleMaps

// 1
let googleApiKey = "ENTER_KEY_HERE"

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

  var window: UIWindow?

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

    //2
    GMSServices.provideAPIKey(googleApiKey)
    return true
  }
}

There are two new elements here:

  1. A constant to hold your Google API key. Replace ENTER_KEY_HERE with the Google API key you created earlier.
  2. Your app will instantiate Google Maps services with the API Key using the GMSServices class method provideAPIKey().

Next, open Main.storyboard to bring up Interface Builder. Bring up the Object Library by selecting the third tab in the view toolbar — Utilities — and then select the third tab in the library toolbar — Object Library — as shown in the screenshot below:

Locate the MapViewController scene and drag a simple UIView from the Object Library to the approximate center of the MapViewController’s view. Change the view’s background color to light gray. Next, open the Document Outline using Editor\Show Document Outline and re-order the view hierarchy so that the object tree looks like this:

To turn this simple UIView into a GMSMapView, select the view you just added and open the Identity inspector by selecting the third tab from the left in the Utilities toolbar. Change the view’s Class to GMSMapView, as shown in the screenshot below:

Your MapViewController scene should now look like this:

Next, you’ll need to add some constraints to make the map fill the entire screen. Select Map View in the Document Outline and then choose the second button from the right in the bottom right of the Interface Builder window — the Pin button. Ensure that Constrain to margins is unchecked — this ensures that the map will fill all the available space on the screen — and add 0 (zero) space constraints from the top, left, bottom and right of the superview.

Your Pin editor should look like this:

Click on Add 4 Constraints to add the constraints to the map view.
Your MapViewController scene should look like the following, where the gray area represents the GMSMapView:

Before you build and run the project, add an IBOutlet for the map view. To do that, bring up the Assistant Editor by selecting the second tab in the Editor toolbar:

Select the map view in Interface Builder, hold down the Ctrl key and drag a line from the map view to MapViewController.swift. A popup will appear; set the connection type to Outlet and the name to mapView. Keep the Type as GMSMapView, and click Connect:

This will create a GMSMapView property in MapViewController.swift and automatically hook it up in Interface Builder. Before you build and run, add the following to the top of the file, after import UIKit:

import GoogleMaps

Build and run your project; you should now see a map, like so:

You’re now using the Google Maps iOS SDK in your app — but you can do more than show a basic map, right? :]

Getting the Location

Feed Me is all about finding places near the user, and you can’t do that without getting the user’s location.

First, open MapViewController.swift and add the following property:

private let locationManager = CLLocationManager()

This will add and instantiate a CLLocationManager property named locationManager.

Next, find viewDidLoad() and add these two lines to the bottom:

locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()

This will make MapViewController the delegate of locationManager and request access to the user’s location.

Next, open the Feed Me project at the top of the Project navigator, select the Feed Me target and go to the Info tab, select the first line in the Custom iOS Target Properties section and click the + icon to add a new row.

Choose Privacy – Location When In Use Usage Description as the key, choose String for the type, and enter the following text as the value:

By accessing your location, this app can find you a good place to eat.

When you’re finished, it should look something like this:

Before you can run the app, you need to make MapViewController conform to the CLLocationManagerDelegate protocol.

Add the following extension to the bottom of MapViewController.Swift:

// MARK: - CLLocationManagerDelegate
//1
extension MapViewController: CLLocationManagerDelegate {
  // 2
  func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
    // 3
    guard status == .authorizedWhenInUse else {
      return
    }
    // 4
    locationManager.startUpdatingLocation()

    //5
    mapView.isMyLocationEnabled = true
    mapView.settings.myLocationButton = true
  }

  // 6
  func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    guard let location = locations.first else {
      return
    }

    // 7
    mapView.camera = GMSCameraPosition(target: location.coordinate, zoom: 15, bearing: 0, viewingAngle: 0)

    // 8
    locationManager.stopUpdatingLocation()
  }
}

Taking each numbered comment in turn:

  1. You create a MapViewController extension that conforms to CLLocationManagerDelegate.
  2. locationManager(_:didChangeAuthorization:) is called when the user grants or revokes location permissions.
  3. Here you verify the user has granted you permission while the app is in use.
  4. Once permissions have been established, ask the location manager for updates on the user’s location.
  5. GMSMapView has two features concerning the user’s location: myLocationEnabled draws a light blue dot where the user is located, while myLocationButton, when set to true, adds a button to the map that, when tapped, centers the map on the user’s location.
  6. locationManager(_:didUpdateLocations:) executes when the location manager receives new location data.
  7. This updates the map’s camera to center around the user’s current location. The GMSCameraPosition class aggregates all camera position parameters and passes them to the map for display.
  8. Tell locationManager you’re no longer interested in updates; you don’t want to follow a user around as their initial location is enough for you to work with.

Build and run your app; once it loads you’ll be prompted with an alert, asking for location permissions. Tap on Allow:

You should now see a map centering around your location. Scroll the map and tap the Locate button and the map will center back to your location like so:

Implementing Geocoding

Now that you have the user’s location, it would be nice if you could show the street address of that location. Google Maps has an object that does exactly that: GMSGeocoder. This takes a simple coordinate and returns a readable street address.

First, you’ll need to add some UI to present the address to the user.

Open Main.storyboard and add a UILabel to the MapViewController scene. Make sure you add the label to the MapViewController view, and not the GMSMapView.

Next, open the Attributes inspector, and give the label the following attributes:

  • Set Alignment to center.
  • Set Lines to 0. Surprisingly, this lets the label take up as many lines as it needs to fit the text. Go figure! :]
  • Set Background to white with 85% opacity.

The label’s Attributes inspector and the scene’s Object Tree should look like this when done:

Attributes inspector

Finally, add to the label left, bottom and right constraints of 0 as shown below:

This pins the label to the bottom of the screen and stretches it over the entire width of the screen.

Your storyboard scene should look like the following:

Next, create an outlet for the label. Select the Assistant Editor, and ctrl+drag from the label in the Document Outline to MapViewController.swift. Set the connection type to Outlet, the name to addressLabel and click Connect.

This adds a property to your MapViewController that you can use in your code:

@IBOutlet weak var addressLabel: UILabel!

Add the method below to MapViewController:

private func reverseGeocodeCoordinate(_ coordinate: CLLocationCoordinate2D) {

  // 1
  let geocoder = GMSGeocoder()

  // 2
  geocoder.reverseGeocodeCoordinate(coordinate) { response, error in
    guard let address = response?.firstResult(), let lines = address.lines else {
      return
    }

    // 3
    self.addressLabel.text = lines.joined(separator: "\n")

    // 4
    UIView.animate(withDuration: 0.25) {
      self.view.layoutIfNeeded()
    }
  }
}

Once again, here’s what each commented section does:

  1. Creates a GMSGeocoder object to turn a latitude and longitude coordinate into a street address.
  2. Asks the geocoder to reverse geocode the coordinate passed to the method. It then verifies there is an address in the response of type GMSAddress. This is a model class for addresses returned by the GMSGeocoder.
  3. Sets the text of the addressLabel to the address returned by the geocoder.
  4. Once the address is set, animate the changes in the label’s intrinsic content size.

You’ll want to call this method every time the user changes their position on the map. To do so you’ll use GMSMapViewDelegate.

Add another extension to the bottom of MapViewController.swift as follows:

// MARK: - GMSMapViewDelegate
extension MapViewController: GMSMapViewDelegate {

}

This will declare that MapViewController conforms to the GMSMapViewDelegate protocol.

Next, add the following line of code to viewDidLoad():

mapView.delegate = self

This makes MapViewController the map view’s delegate.

Finally, add the following method to the newly added extension:

func mapView(_ mapView: GMSMapView, idleAt position: GMSCameraPosition) {
  reverseGeocodeCoordinate(position.target)
}

This method is called each time the map stops moving and settles in a new position, where you then make a call to reverse geocode the new position and update the addressLabel‘s text.

Build and run your app; you’ll see the address of your current location — real or simulated — pop up at the bottom of the screen:

Notice anything wrong with this picture?

Solution Inside SelectShow>

Fortunately, GMSMapView provides a very simple solution for this: padding. When padding is applied to the map, all of the visual elements will be placed according to that padding.

Head back to reverseGeocodeCoordinate(_:), and add these lines just before the animation block:

// 1
let labelHeight = self.addressLabel.intrinsicContentSize.height
self.mapView.padding = UIEdgeInsets(top: self.view.safeAreaInsets.top, left: 0,
                                    bottom: labelHeight, right: 0)

Now, replace the animation block with:

UIView.animate(withDuration: 0.25) {
  //2
  self.pinImageVerticalConstraint.constant = ((labelHeight - self.view.safeAreaInsets.top) * 0.5)
  self.view.layoutIfNeeded()
}

These do two things:

  1. Prior to the animation block, this adds padding to the top and bottom of the map. The top padding equals the view’s top safe area inset, while the bottom padding equals the label’s height.
  2. Updates the location pin’s position to match the map’s padding by adjusting its vertical layout constraint.

Build and run your app again; this time the Google logo and locate button will move to their new position once the label becomes visible:

Move the map around; you’ll notice that the address changes every time the map settles to a new position. Let’s add a visual effect to dampen the address changing.

Add the following method to the GMSMapViewDelegate extension:

func mapView(_ mapView: GMSMapView, willMove gesture: Bool) {
  addressLabel.lock()
}

This method is called every time the map starts to move. It receives a Bool that tells you if the movement originated from a user gesture, such as scrolling the map, or if the movement originated from code. You call the lock() on the addressLabel to give it a loading animation.

When there’s a lock(), there must also be an unlock(). Add the following to the top of reverseGeocodeCoordinate(coordinate:)‘s closure:

self.addressLabel.unlock()
Note: For the full implementation of the lock() and unlock(), check out UIViewExtensions.swift.

Build and run your app; as you scroll the map you should see a loading animation on the address label like so:

Finding Something to Eat

Now that the map is set up and you have the user’s location in hand, it’s time to get this user fed!

You’ll use the Google Places API to search for places to eat and drink around the user’s location. Google Places API is a free web service API you can use to query to find establishment, geographic locations, or other points of interest near any given point.

Google Maps iOS SDK provides you with the GMSMarker class to mark locations on a map. Each marker object holds a coordinate and an icon image and renders on the map when added.

For this app you’ll need some more info on each marker, so you’ll need to create a subclass of GMSMarker.

Create a new Cocoa Touch Class, name it PlaceMarker and make it a subclass of GMSMarker. Ensure you choose Swift as the language for this file.

Replace the contents of PlaceMarker.swift with the following:

import UIKit
import GoogleMaps

class PlaceMarker: GMSMarker {
  // 1
  let place: GooglePlace

  // 2
  init(place: GooglePlace) {
    self.place = place
    super.init()

    position = place.coordinate
    icon = UIImage(named: place.placeType+"_pin")
    groundAnchor = CGPoint(x: 0.5, y: 1)
    appearAnimation = .pop
  }
}

This is a relatively straightforward bit of code:

  1. Add a property of type GooglePlace to the PlaceMarker.
  2. Declare a new designated initializer that accepts a GooglePlace as its sole parameter and fully initializes a PlaceMarker with a position, icon image, anchor for the marker’s position and an appearance animation.

Next, add two more properties to MapViewController.swift as follows:

private let dataProvider = GoogleDataProvider()
private let searchRadius: Double = 1000

You’ll use dataProvider (defined in GoogleDataProvider.swift) to make calls to the Google Places Web API, and searchRadius to determine how far from the user’s location (in meters) to search for places.

Add the following method to MapViewController:

private func fetchNearbyPlaces(coordinate: CLLocationCoordinate2D) {
  // 1
  mapView.clear()
  // 2
  dataProvider.fetchPlacesNearCoordinate(coordinate, radius:searchRadius, types: searchedTypes) { places in
    places.forEach {
      // 3
      let marker = PlaceMarker(place: $0)
      // 4
      marker.map = self.mapView
    }
  }
}

Let’s go over what you just added:

  1. Clear the map of all markers.
  2. Use dataProvider to query Google for nearby places within the searchRadius, filtered to the user’s selected types.
  3. Iterate through the results returned in the completion closure and create a PlaceMarker for each result.
  4. Set the marker’s map. This line of code is what tells the map to render the marker.

Here’s the $64,000 question: when do you want to call this method?

First, the user can reasonably expect to see places nearby when the app launches.

Locate locationManager(_:didUpdateLocations:) and add the following line of code at the end:

fetchNearbyPlaces(coordinate: location.coordinate)

Second, the user has the ability to change the types of places to display on the map, so you’ll need to update the search results if the selected types change.

Locate typesController(_:didSelectTypes:) and add the following line of code to the end:

fetchNearbyPlaces(coordinate: mapView.camera.target)

Finally, you’ll need to give the user the option to fetch new places when their location changes.

Open Main.storyboard and drag a UIBarButtonItem from the Object Library to the left side of the MapViewController’s navigation bar. Change the button’s Identifier to Refresh, as shown below:

Select the Assistant Editor and ctrl+drag from the Refresh button to MapViewController.swift. Choose Action and name the method refreshPlaces. Insert the following code into the newly added method:

fetchNearbyPlaces(coordinate: mapView.camera.target)

Build and run your project; you’ll see location pins popping up around the map. Change the search types in the TypesTableViewController and see how the results change:

All these markers sure add some color to the map, but they’re not much use without additional info to give the user some details on the pinned location.

Add the following method to the GMSMapViewDelegate extension in MapViewController.swift:

func mapView(_ mapView: GMSMapView, markerInfoContents marker: GMSMarker) -> UIView? {
  // 1
  guard let placeMarker = marker as? PlaceMarker else {
    return nil
  }

  // 2
  guard let infoView = UIView.viewFromNibName("MarkerInfoView") as? MarkerInfoView else {
    return nil
  }

  // 3
  infoView.nameLabel.text = placeMarker.place.name

  // 4
  if let photo = placeMarker.place.photo {
    infoView.placePhoto.image = photo
  } else {
    infoView.placePhoto.image = UIImage(named: "generic")
  }

  return infoView
}

This method is called each time the user taps a marker on the map. If you return a view, then it pops up above the marker. If nil is returned, nothing happens. How does that happen?

  1. You first cast the tapped marker to a PlaceMarker.
  2. Next you create a MarkerInfoView from its nib. The MarkerInfoView class is a UIView subclass that comes with the starter project for this tutorial.
  3. Then you apply the place name to the nameLabel.
  4. Check if there’s a photo for the place. If so, add that photo to the info view. If not, add a generic photo instead.

Before you run the app, you want to make sure the location pin doesn’t cover the info window. Add the following method to the GMSMapViewDelegate extension:

func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
  mapCenterPinImage.fadeOut(0.25)
  return false
}

This method simply hides the location pin when a marker is tapped. The method returns false to indicate that you don’t want to override the default behavior — to center the map around the marker — when tapping a marker.

Obviously, the pin needs to re-appear at some point. Add the following to the end of mapView(_:willMove:):

if (gesture) {
  mapCenterPinImage.fadeIn(0.25)
  mapView.selectedMarker = nil
}

This checks if the movement originated from a user gesture; if so, it un-hides the location pin using the fadeIn(_:) method. Setting the map’s selectedMarker to nil will remove the currently presented infoView.

Finally, add the following method to the GMSMapViewDelegate extension:

func didTapMyLocationButton(for mapView: GMSMapView) -> Bool {
  mapCenterPinImage.fadeIn(0.25)
  mapView.selectedMarker = nil
  return false
}

This method runs when the user taps the Locate button; the map will then center on the user’s location. Returning false again indicates that it does not override the default behavior when tapping the button.

Build and run your app; select a marker and you’ll see the location pin fade out. Scrolling the map closes the infoView and brings the pin back:

That’s it, you’ve done it! You now have a fully functioning Google Maps app. :]

Where To Go From Here?

Here’s a link to the complete project from this tutorial. Since the Google Maps SDK is very large in size, we excluded it from the project, so make sure to run pod install before building.

Keep in mind that before you’re able to run this finished project, you will need to insert your API keys as you did at the beginning of this tutorial.

My purpose here is not to convince you that Google Maps iOS SDK is better than Apple’s own MapKit; however, here’s a few pros and cons of Google Maps:

Pros

  • Frequent Updates to the SDK by Google.
  • Uniform experience for cross platform (iOS and Android) apps.
  • Google Maps are often more detailed, especially outside the United States. For example:

Cons

  • Unlike Google Maps, MapKit is native to iOS, which means it’s always synced with iOS and works with Swift out of the box.
  • Lack of stability in comparison to MapKit.
  • MapKit has a much better integration with CoreLocation and CoreAnimation.

This tutorial only showed you the basics of what the Google Maps SDK can do. There’s much more to learn; you should definitely check out the full documentation for more cool features the SDK has to offer.

Among the other things you can do with Google Maps iOS SDK are showing directions, indoor maps, overlays, tile layers, Street View, and advanced integration with the Google Maps app. For brownie points, try to use some of these features to enhance the Feed Me app.

Thanks again to Google Developer Advocates Brett Morgan and Todd Kerpelman, both of whom worked with me to find the best way to integrate the Google Places API into this tutorial.

If you have any questions, tips, or just wanna show off your cool mapping app, feel free to post about it in the discussion below!

The post Google Maps iOS SDK Tutorial: Getting Started appeared first on Ray Wenderlich.

Video Tutorial: Beginning App Asset Design Part 2: Resolution Dependence


Android Unit Testing with Mockito

$
0
0
Unit Testing with Mockito and Kotlin

Ensuring all the features are working

The need for writing tests in software development is often underestimated and relegated to later stages of a project. Sometimes not writing any tests is considered right for mobile apps.

You may have heard several excuses, a few of which are:

  • “Mobile apps are frontend apps, the real logic is in the backend, so backend apps should be tested instead.”
  • “Mobile apps are difficult to unit test, because most of the logic is done in the UI. At most, you should only care about UI tests.”
  • “Mobile apps are “simple” or “tiny” compared to backend apps. Thus, effort should be put in the features instead of wasting time making tests.”

Mobile apps are actually becoming larger and more complex. Hence, teams are also growing in size.

Some companies even have separate teams that focus on specific features. And often, there’s another team that has to:

  • Merge all the features.
  • Upload the final build to Playstore/AppStore.

This increase in code complexity and team collaboration may jeopardize the proper functioning of your application.

Writing good tests can cover this!

In this tutorial, you’ll be refactoring a starter project to use the Model-View-Presenter presentation architecture pattern and write unit tests using Mockito.

But first of all, let’s take a look at the testing pyramid.

Testing pyramid

Tests are typically broken into three different kinds:

testing pyramid

The Testing Pyramid, showing the three categories of tests that you should include in your app’s test suite

  • UI Tests:
    These tests interact with the UI of your app, they emulate the user behavior and assert UI results. These are the slowest and most expensive tests you can write because they require a device/emulator to run. On Android, the most commonly used tools for UI testing are Espresso and UI Automator.
  • Integration Tests:
    When you need to check how your code interacts with other parts of the Android framework but without the complexity of the UI. These tests don’t require a device/emulator to run. On Android, the most common tool for integration testing is Roboelectric.
  • Unit Tests:
    The system under test (SUT) is one class and you focus only on it. All dependencies are considered to be working correctly (and ideally have their own unit tests :]), so they are mocked or stubbed.
    These tests are the fastest and least expensive tests you can write because they don’t require a device/emulator to run. On Android, the most commonly used tools for unit testing are JUnit and Mockito.

A typical rule of thumb is to have the following split among the categories:

  • UI Tests: 10%
  • Integration Tests: 20%
  • Unit Tests: 70%

Because unit tests are so important in the testing pyramid and also easy to write, this tutorial will focus on them.

Note: This tutorial assumes you have previous experience with developing for Android in Kotlin. If you are unfamiliar with the language have a look at this tutorial. If you’re beginning with Android, check out some of our Getting Started and other Android tutorials.

Getting started

Download the starter project. Extract the zip file but don’t open the project in Android Studio yet.

You’ll be working with this simple app named “IngrediSearch” that allows users to search for recipes and favorite them.

Note: For this app to work, please ensure the following:
  • Get your Food2Fork API key
  • Create a keystore.properties file with the following content (including the quotes):
    FOOD2FORK_API_KEY="YOUR API KEY"
  • Place this file in the root project.

With the keystore.properties file added, open the project in Android Studio 3.0.1 or greater.

Build and run the project to become familiar with the application features.

app welcome page app search page
app results page app recipe detail page

The project contains the following main files:

  • MainActivity.kt: Contains the main screen.
  • SearchActivity.kt: Allows the user to input ingredients.
  • SearchResultsActivity.kt: Searches for recipes using the API and shows the results. It also provides the ability to add or remove favorites.
  • RecipeActivity.kt: Shows the recipe detail.
  • FavoritesActivity.kt: Shows the list of favorites.
  • RecipeRepository.kt: Interacts with the API to search for recipes. It also stores the favorites in SharedPreferences.
  • RecipeAdapter.kt: Adapter used to show the list in SearchResultsActivity and FavoritesActivity.

Before you start unit testing, it’s best to ask one very important question…

Is this unit testable?

By checking the source code you will find:

Logic in the Activities

class SearchActivity : ChildActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
    ...
    searchButton.setOnClickListener {
      // 1
      val query = ingredients.text.toString().trim()
      // 2
      if (query.isBlank()) {
        // 3
        Snackbar.make(searchButton, getString(R.string.search_query_required), Snackbar
            .LENGTH_LONG).show()
      } else {
        // 4
        startActivity(searchResultsIntent(query))
      }
    }
  }
}

When the user clicks the search button:

  1. Trim the ingredients text string entered by the user.
  2. Check if it’s blank.
  3. When it’s blank, then show an error message.
  4. If it’s not blank, then proceed to the next screen.

Activity doing everything

class SearchResultsActivity : ChildActivity() {

  private fun search(query: String) {
    // 1
    showLoadingView()
    // 2
    repository.getRecipes(query, object : RecipeRepository.RepositoryCallback<List<Recipe>> {
      override fun onSuccess(recipes: List<Recipe>?) {
        if (recipes != null && recipes.isNotEmpty()) {
          // 3
          showRecipes(recipes)
        } else {
          // 4
          showEmptyRecipes()
        }
      }

      override fun onError() {
        // 5
        showErrorView()
      }
    })
  }

To perform a search:

  1. Because the operation is asynchronous, the activity must show a loading view.
  2. Call the repository of recipes.
  3. If there are recipes, show them!
  4. When no recipes are found, a “No recipes were found” message is shown.
  5. Show an error view if there was an error fetching the recipes.

Adapter doing too much logic

Inside this same activity, you’ll find:

    list.adapter = RecipeAdapter(recipes, object : RecipeAdapter.Listener {
      override fun onAddFavorite(item: Recipe) {
        // 1
        item.isFavorited = true
        // 2
        repository.addFavorite(item)
        // 3
        list.adapter.notifyItemChanged(recipes.indexOf(item))
      }
      ...
    })
  1. Altering the model (favorited status).
  2. Calling the repository.
  3. Updating the view to show the altered model.

Conclusion

Because these are so embedded into the Android activities/adapter, they are not efficiently unit testable. A refactor must be done!

Model-View-Presenter

You’ll refactor the project to the Model-View-Presenter structure. This will ease the creation of unit tests.

Note: If you already know about MVP you can skip to the next section where the project is already refactored to MVP and ready to write unit tests.
model view presenter


Also called just MVP

  • Model:
    All your data classes, API connectors, databases.
  • View:
    Activities, Fragments and any Android Views. It’s responsible for showing the data and propagating the user’s UI actions to the corresponding presenter methods.
  • Presenter:
    Knows about the model and the view. Publishes methods that will be called by the view. These methods usually involve fetching data, manipulating it, and deciding what to show in the view.

Refactoring to MVP

Creating your first Presenter

First, you’ll refactor the SearchActivity to MVP.

Therefore, create a new class by right-clicking on the com.raywenderlich.ingredisearch package and choosing New-Kotlin File/Class. Name the class SearchPresenter and add the following:

class SearchPresenter {
  // 1
  private var view: View? = null

  // 2
  fun attachView(view: View) {
    this.view = view
  }

  // 3
  fun detachView() {
    this.view = null
  }

  // 4
  fun search(query: String) {
    // 5
    if (query.trim().isBlank()) {
      view?.showQueryRequiredMessage()
    } else {
      view?.showSearchResults(query)
    }
  }

  // 6
  interface View {
    fun showQueryRequiredMessage()
    fun showSearchResults(query: String)
  }
}
  1. The presenter knows about the view, so it has to hold a reference to it.
  2. When the view is created, it must attach to the presenter.
  3. You must detach from the presenter when the view is destroyed.
  4. This presenter exposes the search method.
  5. If the query is blank then the view has to show a “query required” message. If it’s not blank, it’ll show the results.
  6. A View interface that your activity will have to conform to.

Implementing your first View

Now, open SearchActivity and modify it to the following:

// 1
class SearchActivity : ChildActivity(), SearchPresenter.View {

  private val presenter: SearchPresenter = SearchPresenter()

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_search)

    // 2
    presenter.attachView(this)

    searchButton.setOnClickListener {
      val query = ingredients.text.toString()
      // 3
      presenter.search(query)
    }
  }

  override fun onDestroy() {
    // 4
    presenter.detachView()
    super.onDestroy()
  }

  // 5
  override fun showQueryRequiredMessage() {
    // Hide keyboard
    val view = this.currentFocus
    if (view != null) {
      val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
      imm.hideSoftInputFromWindow(view.windowToken, 0)
    }

    Snackbar.make(searchButton, getString(R.string.search_query_required), Snackbar
        .LENGTH_LONG).show()
  }

  // 6
  override fun showSearchResults(query: String) {
    startActivity(searchResultsIntent(query))
  }
}
  1. Conform to the SearchPresenter.View interface by implementing 5 and 6.
  2. Create a new instance of the presenter and attach the view.
  3. Whenever the user clicks the search button, instead of the activity doing any logic, just call the search method of the presenter.
  4. When the view is destroyed you must tell the presenter to detach the view.
  5. Implement showQueryRequiredMessage required by the SearchPresenter.View interface.
  6. SearchPresenter.View also requires you to implement showSearchResults.

Creating the SearchResults presenter

Create a SearchResultsPresenter class.

// 1
class SearchResultsPresenter(val repository: RecipeRepository) {
  private var view: SearchResultsPresenter.View? = null
  private var recipes: List<Recipe>? = null

  // 2
  fun attachView(view: SearchResultsPresenter.View) {
    this.view = view
  }

  fun detachView() {
    this.view = null
  }

  // 3
  interface View {
    fun showLoading()
    fun showRecipes(recipes: List<Recipe>)
    fun showEmptyRecipes()
    fun showError()
    fun refreshFavoriteStatus(recipeIndex: Int)
  }
}
  1. This presenter will make the API request therefore it has RecipeRepository as dependency.
  2. You also need to attach/detach.
  3. A View interface that your activity will have to conform to.

You may have noticed that you’re repeating the attach/detach logic here, so let’s create a BasePresenter:

abstract class BasePresenter<V> {
  protected var view: V? = null

  fun attachView(view: V) {
    this.view = view
  }

  fun detachView() {
    this.view = null
  }
}

Now extend from this class, remove the view property and the attach/detach methods:

class SearchResultsPresenter(private val repository: RecipeRepository) :
    BasePresenter<SearchResultsPresenter.View>() {
  private var recipes: List<Recipe>? = null

  interface View {
    fun showLoading()
    fun showRecipes(recipes: List<Recipe>)
    fun showEmptyRecipes()
    fun showError()
    fun refreshFavoriteStatus(recipeIndex: Int)
  }
}

Add the following method:

  // 1
  fun search(query: String) {
    view?.showLoading()
    // 2
    repository.getRecipes(query, object : RecipeRepository.RepositoryCallback<List<Recipe>> {
      // 3
      override fun onSuccess(recipes: List<Recipe>?) {
        this@SearchResultsPresenter.recipes = recipes
        if (recipes != null && recipes.isNotEmpty()) {
          view?.showRecipes(recipes)
        } else {
          view?.showEmptyRecipes()
        }
      }

      // 4
      override fun onError() {
        view?.showError()
      }
    })
  }
  1. This presenter exposes the search method.
  2. Call the repository to get recipes asynchronously.
  3. If the call is successful show the recipes (or empty if there are none).
  4. Whenever there is an error with the call, show the error.

Add the following extra methods:

  // 1
  fun addFavorite(recipe: Recipe) {
    // 2
    recipe.isFavorited = true
    // 3
    repository.addFavorite(recipe)
    // 4
    val recipeIndex = recipes?.indexOf(recipe)
    if (recipeIndex != null) {
      view?.refreshFavoriteStatus(recipeIndex)
    }
  }

  // 5
  fun removeFavorite(recipe: Recipe) {
    repository.removeFavorite(recipe)
    recipe.isFavorited = false
    val recipeIndex = recipes?.indexOf(recipe)
    if (recipeIndex != null) {
      view?.refreshFavoriteStatus(recipeIndex)
    }
  }
  1. Expose the addFavorite method.
  2. Alter the state of the model.
  3. Call the repository to save the favorite.
  4. Tell the view to refresh with the favorited status.
  5. Analogously, expose the removeFavorite method.

Implementing SearchResultsPresenter.View

Now, open SearchResultsActivity and modify it to the following:

// 1
class SearchResultsActivity : ChildActivity(), SearchResultsPresenter.View {

  private val presenter: SearchResultsPresenter by lazy {SearchResultsPresenter(RecipeRepository.getRepository(this))}

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_list)

    val query = intent.getStringExtra(EXTRA_QUERY)
    supportActionBar?.subtitle = query

    // 2
    presenter.attachView(this)
    // 3
    presenter.search(query)
    retry.setOnClickListener { presenter.search(query) }
  }
}
  1. Conform to the SearchResultsPresenter.View interface.
  2. Instantiate the presenter with the repository and attach the view.
  3. Whenever the user enters this screen, instead of the activity doing any logic, just call the search method of the presenter.
  4. When the view is destroyed you must tell the presenter to detach the view.

Implement the SearchResultsPresenter.View interface:

  override fun showEmptyRecipes() {
    loadingContainer.visibility = View.GONE
    errorContainer.visibility = View.GONE
    list.visibility = View.VISIBLE
    noresultsContainer.visibility = View.VISIBLE
  }

  override fun showRecipes(recipes: List<Recipe>) {
    loadingContainer.visibility = View.GONE
    errorContainer.visibility = View.GONE
    list.visibility = View.VISIBLE
    noresultsContainer.visibility = View.GONE

    setupRecipeList(recipes)
  }

  override fun showLoading() {
    loadingContainer.visibility = View.VISIBLE
    errorContainer.visibility = View.GONE
    list.visibility = View.GONE
    noresultsContainer.visibility = View.GONE
  }

  override fun showError() {
    loadingContainer.visibility = View.GONE
    errorContainer.visibility = View.VISIBLE
    list.visibility = View.GONE
    noresultsContainer.visibility = View.GONE
  }

  override fun refreshFavoriteStatus(recipeIndex: Int) {
    list.adapter.notifyItemChanged(recipeIndex)
  }

Implement the missing method:

  private fun setupRecipeList(recipes: List<Recipe>) {
    list.layoutManager = LinearLayoutManager(this)
    list.adapter = RecipeAdapter(recipes, object : RecipeAdapter.Listener {
      override fun onClickItem(recipe: Recipe) {
        startActivity(recipeIntent(recipe.sourceUrl))
      }

      override fun onAddFavorite(recipe: Recipe) {
        // 1
        presenter.addFavorite(recipe)
      }

      override fun onRemoveFavorite(recipe: Recipe) {
        // 2
        presenter.removeFavorite(recipe)
      }
    })
  }
  1. When adding a favorite, now the adapter listener just calls the presenter’s addFavorite method.
  2. Also, when the user wants to remove a favorite, just call the presenter’s removeFavorite method.

MVP Refactor done!

Now that the refactor was done, you’ll be able to create unit tests.

Build and run the app and make sure the app behaves just as it did before the refactor.

You can also download the MVP refactored project if you want to. Remember to add the keystore.properties file in order to open the project.

Using Mockito

Setup Mockito dependencies

Open the application’s build.gradle file and add the following dependency:

dependencies {
  ...
  testImplementation 'com.nhaarman:mockito-kotlin-kt1.1:1.5.0'
  ...
}

Mockito-Kotlin is a wrapper library around Mockito.

It provides top-level functions to allow for a more idiomatic approach and also solves a few issues with using the Mockito java library in Kotlin. Check its wiki for more information.

State & Behavior verification

In state verification, you first have the system under test (SUT) configured with all the necessary dependencies (setup phase). Secondly, you perform a certain operation (exercise phase). Finally, you examine the state of the object and verify it’s the expected one (verification phase). This is sometimes called black-box testing. Usually, JUnit is used for this.

In behavior verification, instead, you specify which methods are to be invoked on the dependencies, in other words, you setup expectations, thus verifying not that the ending state is correct, but that the methods were invoked correctly. This is sometimes called white-box testing. Usually, Mockito is used for this.

Mockito main features

  • Mock:
    The SUT usually has dependencies that are necessary for the SUT to work. If you want to verify a method was called by the SUT, you mock the dependency class and then verify the mocked dependency method was called.
  • Stubbing:
    Sometimes your SUT will follow a certain path or another depending on the results of methods called on its dependencies. To force a dependency to always respond the same way, you need to stub the method.

At last, it’s time for some unit testing! :]

Search unit tests

You’ll create a unit test that verifies that the presenter calls the view’s showQueryRequiredMessage when an empty search is performed.

First delete the ExampleUnitTest:
Delete ExampleUnitTest

Add a new class called SearchTests, with the following content:

package com.raywenderlich.ingredisearch

import com.nhaarman.mockito_kotlin.mock
import com.nhaarman.mockito_kotlin.verify
import org.junit.Test

class SearchTests {
  // 1
  @Test
  fun search_withEmptyQuery_callsShowQueryRequiredMessage() {
    // 2
    val presenter = SearchPresenter()
    // 3
    val view: SearchPresenter.View = mock()
    presenter.attachView(view)

    // 4
    presenter.search("")

    // 5
    verify(view).showQueryRequiredMessage()
  }
}
  1. Every unit test must start with the @Test annotation.
  2. Instantiate the presenter.
  3. Because you don’t need a real view that conforms to the interface, you can mock it.
    Then attach this view to the presenter.
  4. Call the search method with an empty query.
  5. Verify on the mocked view that the presenter calls showQueryRequiredMessage

Now to run the test, press on the little green arrow (the arrow will have a circle after the first run of the tests) to the left of the class declaration:

Run SearchTests

Hopefully you’ll get all green! :]

Successful test results

Refactoring the unit test

Because all SearchTests will basically share the same setup, you should add a setup() function with a @Before annotation as follows:

class SearchTests {

  private lateinit var presenter : SearchPresenter
  private lateinit var view : SearchPresenter.View

  @Before
  fun setup() {
    presenter = SearchPresenter()
    view = mock()
    presenter.attachView(view)
  }
  ...

The function marked @Before is executed before any test, therefore it’s a good place to setup objects/mocks. It’s also common to see a tearDown() function marked @After in test classes, which is run when a test completes.

Modify your first test with the following:

  @Test
  fun search_withEmptyQuery_callsShowQueryRequiredMessage() {
    presenter.search("")

    verify(view).showQueryRequiredMessage()
  }

Verify a method is never called

You can also test that a function is never called by adding the following test:

  @Test
  fun search_withEmptyQuery_doesNotCallsShowSearchResults() {
    presenter.search("")

    verify(view, never()).showSearchResults(anyString())
  }
Note: Android Studio will mark never() as an unresolved reference. Make sure you import the com.nhaarman.mockito_kotlin option which is the Mockito wrapper.

Search results tests

Kotlin default final classes/methods

Before proceeding to create these tests, it’s important to mention that Kotlin classes and methods by default are final. Mockito won’t work with final classes/methods, but there are a few workarounds:

  • Add the open keyword to classes and methods that you’ll mock.
  • Create an interface and have the class implement the interface. Then, just mock the interface (interfaces are open by default).
  • Use mock-maker-inline. You’ll do this later.

Repository refactor

Because in the following tests you’ll mock the repository, we’re going to take the interface approach.

So, use Shift+F6 to rename the RecipeRepository class to RecipeRepositoryImpl and create a new RecipeRepository interface with all the public methods, you can also move the RepositoryCallback outside:

interface RecipeRepository {
  fun addFavorite(item: Recipe)
  fun removeFavorite(item: Recipe)
  fun getFavoriteRecipes(): List<Recipe>
  fun getRecipes(query: String, callback: RepositoryCallback<List<Recipe>>)
}

interface RepositoryCallback<in T> {
  fun onSuccess(t: T?)
  fun onError()
}

Open RecipeRepositoryImpl and implement RecipeRepository:

class RecipeRepositoryImpl(private val sharedPreferences: SharedPreferences) :
    RecipeRepository

Add the override keyword to the corresponding methods (also, be sure to remove RepositoryCallback from RecipeRepositoryImpl if you added it into the interface file).

Also, open SearchResultsPresenter and modify it to use the interface:

class SearchResultsPresenter(val repository: RecipeRepository) :
    BasePresenter<SearchResultsPresenter.View>()

And fix the anonymous RepositoryCallback:

repository.getRecipes(query, object : RepositoryCallback<List<Recipe>> {

Setup Search results tests

Add a new class called SearchResultsTests to the test package:

package com.raywenderlich.ingredisearch

import com.nhaarman.mockito_kotlin.mock
import org.junit.Before

class SearchResultsTests {

  private lateinit var repository: RecipeRepository
  private lateinit var presenter: SearchResultsPresenter
  private lateinit var view: SearchResultsPresenter.View

  @Before
  fun setup() {
    repository = mock()
    view = mock()
    presenter = SearchResultsPresenter(repository)
    presenter.attachView(view)
  }
}

Add the following tests:

  // 1
  @Test
  fun search_callsShowLoading() {
    presenter.search("eggs")

    verify(view).showLoading()
  }

  // 2
  @Test
  fun search_callsGetRecipes() {
    presenter.search("eggs")

    verify(repository).getRecipes(eq("eggs"), any())
  }

These tests verify:

  1. That the view is shown as “loading” whenever the presenter is required to search.
  2. If the repository is called with the corresponding parameters (“eggs”), then the eq matcher is used to verify that it’s called with the same string. The any matcher was used for the callback parameter because you don’t care about it.

Try and run these search results tests using the green arrow next to the test class name.

Stub a callback

Now, create a test that stubs the response of the recipes repository and verifies that the presenter calls showRecipes on the mocked view.

  @Test
  fun search_withRepositoryHavingRecipes_callsShowRecipes() {
    // 1
    val recipe = Recipe("id", "title", "imageUrl", "sourceUrl", false)
    val recipes = listOf<Recipe>(recipe)

    // 2
    doAnswer {
      val callback: RepositoryCallback<List<Recipe>> = it.getArgument(1)
      callback.onSuccess(recipes)
    }.whenever(repository).getRecipes(eq("eggs"), any())

    // 3
    presenter.search("eggs")

    // 4
    verify(view).showRecipes(eq(recipes))
  }
  1. Create a list of recipes.
  2. Stub the repository getRecipes method to return these recipes.
  3. Call the search method.
  4. Verify that the presenter calls showRecipes on the mocked view with the list of recipes.

Go ahead and run the new test to make sure all is good.

Verify state

The following test is just a JUnit test:

  @Test
  fun addFavorite_shouldUpdateRecipeStatus() {
    // 1
    val recipe = Recipe("id", "title", "imageUrl", "sourceUrl", false)

    // 2
    presenter.addFavorite(recipe)

    // 3
    Assert.assertTrue(recipe.isFavorited)
  }
  1. Create a recipe.
  2. Call the addFavorite method.
  3. Verify that the recipe isFavorited flag has changed.

Run the test to make sure the state of a recipe is changed correctly when marked as a favorite.

RecipeRepository tests

Before creating the tests, open RecipeRepositoryImpl and look at the following functions:

  override fun addFavorite(item: Recipe) {
    // 1
    val favorites = getFavoriteRecipes() + item
    saveFavorites(favorites)
  }

  // 2
  private fun saveFavorites(favorites: List<Recipe>) {
    val editor = sharedPreferences.edit()
    editor.putString(FAVORITES_KEY, gson.toJson(favorites))
    editor.apply()
  }
  1. The addFavorite method, first calls getFavoriteRecipes and appends an item.
  2. Then it saves to SharedPreferences using a JSON format.

You’ll create a test that verifies this behavior.

Because you’ll need to stub getFavoriteRecipes() and also you’ll need to call the real addFavorite method, a mock on the RecipeRepository interface won’t work. You need to spy on a real instance of RecipeRepositoryImpl. More on the spy feature later.

Mock maker inline

Now, recall that Kotlin by default has final classes and final methods (unless you use the open keyword).
So, instead of adding the open keyword to the RecipeRepositoryImpl class and methods, create a text file under app/src/test/resources/mockito-extensions called org.mockito.plugins.MockMaker with the following content (it may be easier to switch to the Project view in the Project pane in order to add the new directory and text file):

mock-maker-inline

mockito-extensions file

This will enable you to mock/spy on real classes without adding the open keyword.

Spy the repository implementation

Add a new class to the test package called RepositoryTests with the following content:

package com.raywenderlich.ingredisearch

import android.content.SharedPreferences
import com.nhaarman.mockito_kotlin.mock
import com.nhaarman.mockito_kotlin.spy
import com.nhaarman.mockito_kotlin.whenever
import org.junit.Before

class RepositoryTests {
  private lateinit var spyRepository: RecipeRepository
  private lateinit var sharedPreferences: SharedPreferences
  private lateinit var sharedPreferencesEditor: SharedPreferences.Editor

  @Before
  fun setup() {
    // 1
    sharedPreferences = mock()
    sharedPreferencesEditor = mock()
    whenever(sharedPreferences.edit()).thenReturn(sharedPreferencesEditor)

    // 2
    spyRepository = spy(RecipeRepositoryImpl(sharedPreferences))
  }
}
  1. You need to mock SharedPreferences and the corresponding editor.
  2. Because you’ll stub the RecipeRepository‘s getRecipes method but you also need to call the real addFavorite method on the same object, instead of a mock you need a spy.

Finally, create the test:

  @Test
  fun addFavorite_withEmptyRecipes_savesJsonRecipe() {
    // 1
    doReturn(emptyList<Recipe>()).whenever(spyRepository).getFavoriteRecipes()

    // 2
    val recipe = Recipe("id", "title", "imageUrl", "sourceUrl", false)
    spyRepository.addFavorite(recipe)

    // 3
    inOrder(sharedPreferencesEditor) {
      // 4
      val jsonString = Gson().toJson(listOf(recipe))
      verify(sharedPreferencesEditor).putString(any(), eq(jsonString))
      verify(sharedPreferencesEditor).apply()
    }
  }
  1. Stub the getFavoriteRecipes() with an empty list. Notice that when stubbing spies you need to use doReturn/whenever/method.
  2. Call the real addFavorite method with a recipe.
  3. Check that the subsequent verifications are executed in the exact order.
  4. Verify that the list is saved correctly with JSON format.

Go ahead and run the repository tests to see the spy in action!

Where To Go From Here?

Congratulations! You’ve just learned the basics of using Mockito for unit testing.

You can download the final project here. Remember to add the keystore.properties file in order to open the project.

In this tutorial, you added the unit tests after writing the code. In Test Driven Development (TDD), you write the unit tests first and only add code to pass the currently failing unit test.

I suggest reading the following:

  • Mockito reference: To delve more into this topic, please have a look at the Mockito-Kotlin and Mockito wikis.
  • Mocks aren’t stubs: You’ll commonly hear in the jargon “You should mock that”, but they aren’t always strictly referring to mocks. An article from Martin Fowler explains the difference.
  • Dependency injection: In order to make your app more testable, it’s good to have your dependencies injected somehow. This Dagger 2 tutorial will help you with that.
  • Test patterns: Because writing tests is a bit of an art form, this book from Gerard Meszaros will some great patterns to you. It’s an incredible reference.
  • Espresso codelab: If you’re wondering how UI tests are done, this codelab from Google Developers will help you get started.

I hope you enjoyed this tutorial, and if you have any questions or comments, please join the forum discussion below!

The post Android Unit Testing with Mockito appeared first on Ray Wenderlich.

Video Tutorial: Beginning App Asset Design Part 2: Challenge: Resolution

Screencast: Introduction to ReplayKit

Video Tutorial: Beginning App Asset Design Part 2: Masks and Compositing

How to make a Power-Up System in Unity

$
0
0

How to make a Power-Up System in UnityWhat would Sonic The Hedgehog be without gold rings and power sneakers; Super Mario, without mushrooms; or Pac-Man without power pellets? The games wouldn’t be nearly as much fun!

Power-ups are a critical gameplay component as they add extra layers of complexity and strategy to keep the action moving.

In this tutorial you will learn how to:

  • Design and build a reuseable power-up system.
  • Use message-based communication in your game.
  • Implement these in a top-down “dodge-em-up” game filled with your own power-ups!
Note: This tutorial assumes you are familiar with Unity and have an intermediate knowledge of C#. If you need need some refreshers, you can check out our other Unity tutorials.

You’ll need Unity 2017.1 or later to follow this tutorial, so upgrade your Unity installation if you haven’t already.

Getting Started

The game you’ll work with a 2D top-down arena dodge-em-up; it’s a little like Geometry Wars without the shooting — and without the commercial success. Your helmeted hero has to dodge the enemies to get to the exit; bumping into enemies reduces health. When all health is depleted, it’s game over.

Download the starter project for this tutorial and extract it to a location of your choosing. Open the project in Unity and take a look at the project folders:

  • Audio: Contains the sound effect files for the game.
  • Materials: The materials for the game.
  • Prefabs: Contains the Prefabs for the game, including the play area, player, enemies, particles and power-ups.
  • Scenes: The main game scene is in here.
  • Scripts: Contains the C# scripts for the game, which have been thoroughly commented. Feel free to nose around the scripts if you’d like to become more familiar with them before starting.
  • Textures: The source images used for game and splash screen.

Open up the scene named main and press the Play button.

You’ll see the game has no power-ups yet. As a result, it’s hard to complete and perhaps a little dull. Your task is to add some power-ups and liven things up. When the player collects a power-up, a quote from a famous movie series will appear on screen. See if you can guess the movie series, the answer is at the end of this tutorial!

The Power-Up Lifecycle

A power-up has a lifecycle, which consists of several distinct states:

  • The first stage is creation which can happen during gameplay or at design time when you manually place power-up GameObjects into your scene.
  • Next comes attract mode, when power-ups can animate or otherwise do something to attract attention.
  • The collection stage is the act of picking up the power-up, which can trigger sounds, particle systems or other special effects.
  • The collection leads to the issuance of the payload, which is the power-up “doing its thing”. The payload can be anything you can imagine, from a humble health bonus to giving the player some awesome superpowers. The payload step also sets up the expiry check. The power-up may be set to expire after a set amount of time has elapsed, after the player has been hurt, after a certain number of uses, or after some other gameplay condition has occurred.
  • The expiry check leads to the expiry stage proper. The expiry stage will destroy the power-up and marks the end of the cycle.

The above lifecycle contains elements you’d want to use repeatedly in every game and elements that would only pertain to the current game. For example, detecting if a player has collected a pickup is a feature you would like in every game, but a specific payload of making the player invisible might be something you only want in your current game. This is important to consider when designing the script logic.

Creating a Simple Star Power-Up

You’re likely familiar with “entry-level” power-ups, such as gold coins, stars or rings that provide a simple score or health bonus. You will now create a Star power-up in the scene that will instantly provide a health bonus to the player and give your hero a better chance of making it out alive.

Relying solely on the star is not going to be good enough to escape unscathed, but you’ve still got other power-ups to add later on in this tutorial that will definitely give your hero a competitive edge.

Create a new Sprite, name it PowerUpStar, and position it just above the player at a location of (X:6, Y:-1.3). To keep the scene tidy, make the sprite a child of the empty PowerUps “folder” GameObject in the scene:

Now define the sprite’s appearance. Set the Transform Scale to (X:0.7, Y:0.7), in the Sprite Renderer component, assign the star to the Sprite slot and set Color to a pale brown color (R:211, G:221, B:200).

Add a Box Collider 2D component, tick the Is Trigger checkbox and set the Size to (X:0.2, Y:0.2):

You’ve just created your first power-up! Play the game to see if everything looks good. The power-up appears, but nothing happens when you try to pick it up. To fix this, you will need to do some scripting.

Separating Game Logic with a Class Hierarchy

Being a conscientious developer, you want to make the best use of your time and reuse elements from previous projects. To do this with a power-up system, you need to design it with a class hierarchy. The class hierarchy separates the power-up logic into a reusable engine part and a game-specific part. If you are new to the idea of class hierarchies and inheritance we’ve got a video that explains all of this.

The diagram above shows the class PowerUp as the parent class. It contains the game-independent logic, so you can reuse this mostly as-is in other projects. The tutorial project already contains the parent class. The parent class orchestrates the power-up lifecycle, manages the different states a power-up can have and handles collisions, collection, payloads, messages and expiry.

The parent class implements a simple state machine that tracks the power-up lifecycle. What you must implement is a subclass and some inspector values for each new power-up, and you will be good to go!

Power-Up Coding Checklist

Note: To create a power-up script, you must create a subclass of the PowerUp class and observe the following checklist. This tutorial refers back to this checklist several times, so keep it handy!
  1. Implement PowerUpPayload to issue the payload.
  2. Optionally, implement PowerUpHasExpired to remove the payload from the previous step.
  3. Call PowerUpHasExpired when the power-up has expired. If the power-up expires immediately, tick the ExpiresImmediately checkbox in the inspector as there is no need to call PowerUpHasExpired.

Think about what the Star power-up does: it simply provides a small health bonus. You’ll only need a bit of scripting to make this happen.

Creating Your First Power-Up Script

Add a new script to the PowerUpStar GameObject, name it PowerUpStar and open it up in your editor.

Add the following code, replacing most of the boilerplate Unity starter code while leaving the using statements at the top as they are.

class PowerUpStar : PowerUp
{
    public int healthBonus = 20;

    protected override void PowerUpPayload()  // Checklist item 1
    {
        base.PowerUpPayload();

        // Payload is to give some health bonus
        playerBrain.SetHealthAdjustment(healthBonus);
    }
}

The code is pretty short, but this is all you need to implement your Star logic! The script addresses each of the checklist points as follows:

  1. PowerUpPayload awards some health by calling playerBrain.SetHealthAdjustment. The PowerUp parent class has already taken care of obtaining the playerBrain reference. The fact that you have a parent class means you will need to call base.PowerUpPayload to ensure all core logic executes before your code.
  2. You don’t need to implement PowerUpHasExpired because the health award is permanent.
  3. This power-up expires immediately, so again, you don’t need to code anything; simply tick the ExpiresImmediately checkbox in the inspector. This is a good time to save the method and switch back to Unity to make some inspector settings.

Creating Your First Power-Up in the Scene

After you save and switch back to Unity, the StarPowerUp GameObject will look like this in the inspector:

Populate the inspector values as follows:

  • Power Up Name: Star
  • Explanation: Recovered some health…
  • Power Up Quote: (I will become more powerful than you can possibly imagine)
  • Expires Immediately: Ticked
  • Special Effect: Drag in the prefab from project folder Prefabs/Power Ups/ParticlesCollected
  • Sound Effect: Drag in the audio clip from project folder Audio/power_up_collect_01
  • Health Bonus: 40

Once you have done this, your power-up will look like this:

Once you’re happy with your PowerUpStar GameObject settings, drag it into the project tree folder Prefabs/Power Ups to create a prefab.

Use your new prefab to add a few Stars to the right of the scene in places you find pleasing.

Run the scene and steer the hero towards the first power-up. Some audio and a glorious particle effect accompany your collection. Awesome!

Message-Based Communication

The next power-up you will create needs some background information. To get that information, you need a way for your GameObjects to communicate with each other.

For example, when you collect a power-up, the UI must know what information to display. When the player’s health changes, the health bar needs to know what the updated health level should be. There are lots of ways you can do this, but the Unity manual lists several mechanisms to accomplish this.

Each communication method has its pros and cons, and one size certainly does not fit all. What you see in this game is message based communication as outlined in the Unity manual.

You can categorize GameObjects as being message broadcasters, message listeners, or both:

On the left in the above diagram are some message broadcasters. You can think of this as the objects “shouting out” when something interesting happens. For example, the player broadcasts the message “I got hurt”. On the right in the above diagram are the message listeners. As the name suggests, these listen for messages. Listeners don’t have to listen to every message; they simply listen for those messages that they might want to react to.

Message broadcasters can also be message listeners. For example, sthe power-up broadcasts messages, but also listens for player messages. A good example of this is a power-up that will expire when a player gets hurt.

You can imagine that if there are many broadcasters and many listeners, there could be many lines criss-crossing between the left and right sides. To make life easier, Unity provides an EventSystem component that sits in between, like this:

Unity uses the extendable EventSystem component to handle input. The component also manages much of the sending and receiving event logic.

Phew! That’s a lot of theory, but the bottom line is that such a messaging system will allow power-ups to easily listen in to the gameplay and reduce hard-wiring between objects. This should make adding new power-ups quite simple, particularly later in development, because most messages will already be broadcast.

Steps to Set Up Message-Based Communication

This is the last bit of theory before you can get back to building. To broadcast a message, you need to take care of these steps:

  • Broadcasters define what message they want to broadcast as a C# Interface.
  • Broadcasters then send messages to listeners stored in a listener list.

See this video on C# Interfaces if you need a refresher.

In short, an interface defines method signatures. Any class that implements the interface promises to provide functionality for these methods.

You will see it more clearly with an example. Look at the code in the IPlayerEvents.cs file:

public interface IPlayerEvents : IEventSystemHandler
{
   void OnPlayerHurt(int newHealth); 
   void OnPlayerReachedExit(GameObject exit); 
}

This C# interface has methods for OnPlayerHurt and OnPlayerReachedExit. These are the messages that the player can send. Now look at the method SendPlayerHurtMessages in the PlayerBrain.cs file. The snippet below contains numbers referenced in the explanation that follows:

   private void SendPlayerHurtMessages()
   {
      // Send message to any listeners
      foreach (GameObject go in EventSystemListeners.main.listeners)  // 1
      {
         ExecuteEvents.Execute<IPlayerEvents>                   // 2
             (go, null,                                               // 3
              (x, y) => x.OnPlayerHurt(playerHitPoints)            // 4
             );
      }
   }

The method above handles the sending of the message OnPlayerHurt. The foreach loop iterates through every listener held in the list EventSystemListeners.main.listeners and calls ExecuteEvents.Execute against each listener, which sends the messages.

Taking each numbered comment in turn:

  1. EventSystemListeners.main.listeners is a list of GameObjects globally visible in the singleton EventSystemListeners object. Any GameObject that wants to listen to any message must be in this list. You can add GameObjects to this list by giving the GameObject a tag of Listener in the inspector, or by calling EventSystemListeners.main.AddListener.
  2. ExecuteEvents.Execute is a method provided by Unity that sends the message to a GameObject. The type in the angle brackets is the interface name that contains the message you want to send.
  3. This specifies the GameObject to send the message to and null for extra event information, following the Unity manual syntax example.
  4. This is a lamba expression. This is an advanced C# topic that is beyond the scope of this tutorial. Basically, a lambda expression lets you pass code as a parameter into a method. In this case, the code contains the message you want to send (OnPlayerHurt) together with the parameters it needs (playerHitPoints).

The project is already set up to broadcast all necessary messages. You might find some of these useful if you want to extend the project and add your own power-ups later. By convention, all interface names begin with the letter I:

  • IPlayerEvents: Used for messages when player gets hurt or reaches exit.
  • IPowerUpEvents: Used for messages when a power-up gets collected or expires.
  • IMainGameEvents: Used for messages when player wins or loses.

The above interfaces have comments throughout if you do choose to explore them. It’s not critical that you understand them for this tutorial, so you can move along if you like.

A Power-Up for Increased Speed

Now that you know about message-based communication, you’re going to put it into practice and listen for a message!

You will create a power-up that gives the player extra speed until they bump into something. The power-up will detect when the player bumps into something by “listening in” to the gameplay. More specifically, the power-up will listen for the player to broadcast the message saying “I am hurt”.

To listen to a message, you need to follow these steps:

  1. Implement the appropriate C# interface to define what the listener GameObject should listen to.
  2. Make sure that the listener GameObjects themselves exist in the list EventSystemListeners.main.listeners.

Create a new Sprite, name it PowerUpSpeed and position it somewhere at the top left corner of the arena above the player. Set its Scale to (X:0.6, Y:0.6). This GameObject will be a listener, so give it a tag of Listener in the inspector.

Add a Box Collider 2D and Size it to (X:0.2, Y:0.2). In the Sprite Renderer, assign the Sprite as fast and color it as you did previously with the Star power-up. Make sure you also enable Is Trigger. When you have finished, the GameObject should look something like this:

Add a new script to this GameObject called PowerUpSpeed, and add the following code to the script:

class PowerUpSpeed : PowerUp
{
    [Range(1.0f, 4.0f)]
    public float speedMultiplier = 2.0f;

    protected override void PowerUpPayload()          // Checklist item 1
    {
        base.PowerUpPayload();
        playerBrain.SetSpeedBoostOn(speedMultiplier);
    }

    protected override void PowerUpHasExpired()       // Checklist item 2
    {
        playerBrain.SetSpeedBoostOff();
        base.PowerUpHasExpired();
    }
}

Review the coding checklist items. The script addresses each checklist point as follows:

  1. PowerUpPayload. This calls the base method to ensure the parent class code is called, then sets the speed boost on the player. Notice that the parent class defines playerBrain, which contains a reference to the player that collected the power-up.
  2. PowerUpHasExpired. You have to remove the speed boost you gave and then call the base method.
  3. The final checklist item is to call PowerUpHasExpired when the power-up has expired. You’ll handle this in a bit by listening to player messages.

Adjust the class declaration to implement the interface for player messages:

class PowerUpSpeed : PowerUp, IPlayerEvents
Note: If you use Visual Studio, you can hover over the IPlayerEvents term after you type it in and choose the menu option Implement interface explicitly. This will create method stubs for you.

Add or adjust the methods until they look like the following, ensuring they are still part of the PowerUpSpeed class:

    void IPlayerEvents.OnPlayerHurt(int newHealth)
    {
        // You only want to react once collected
        if (powerUpState != PowerUpState.IsCollected)
        {
            return;
        }

        // You expire when player hurt
        PowerUpHasExpired();                 // Checklist item 3
    }

    /// <summary>
    /// You have to implement the whole IPlayerEvents interface, but you don't care about reacting to this message
    /// </summary>
    void IPlayerEvents.OnPlayerReachedExit(GameObject exit)
    {

    }

The method IPlayerEvents.OnPlayerHurt is called every time the player receives damage. This is the “listening to the broadcast message” part. In this method, you first check to ensure that the power-up is only going to react after collection. Then the code calls PowerUpHasExpired in the parent class, which will handle the expiry logic.

Save the method and switch back to Unity to make the necessary inspector settings.

Creating the Speed Power-Up in the Scene

The SpeedPowerUp GameObject will now look like this in the inspector:

Fill in the inspector values as follows:

  • Power Up Name: Speed
  • Explanation: Super fast movement until enemy contact
  • Power Up Quote: (Make the Kessel run in less than 12 parsecs)
  • Expires Immediately: unticked
  • Special Effect: ParticlesCollected (same as for Star power-up)
  • Sound Effect power_up_collect_01 (same as for Star power-up)
  • Speed Multiplier: 2

Once you have done this, your power-up will look like this:

Once you’re happy with the Speed power-up settings, drag it into the project tree folder Prefabs/Power Ups to create a prefab. You won’t be using this in the demo project, but it’s a good idea to do this for completeness.

Run the scene and move the hero to collect the Speed power-up, and you’ll gain some extra speed until the next enemy contact.

A Push Power-Up

This next power-up lets the player push objects out of the way by pressing the P key and has a limited number of uses. You should be familiar with the steps to create a power-up by now, so to keep things simple you will only review the interesting parts of the code and then drop in the prefab. This power-up does not need to listen to messages.

In the project hierarchy, find and inspect the prefab called PowerUpPush. Open its script, named PowerUpPush, and review the code.

You will see familiar methods covered already. The interesting activity for the Push power-up happens all in the Update method, as shown below:

    private void Update ()
    {
        if (powerUpState == PowerUpState.IsCollected &&     //1
            numberOfUsesRemaining > 0)                      //2
        {
            if (Input.GetKeyDown ("p"))                     //3
            {
                PushSpecialEffects ();                      //4
                PushPhysics ();                             //5
                numberOfUsesRemaining--;
                if (numberOfUsesRemaining <= 0)
                {
                    PowerUpHasExpired ();                   //7
                }
            }
        }
    }

Here's what's going on in the code above:

  1. The script should only execute for collected power-ups.
  2. The script should only execute if there are uses remaining.
  3. The script should only execute if the player presses 'P'.
  4. The script triggers a pretty particle effect around the player.
  5. The script does the pushing of the enemies away from the player.
  6. The power-up gets used once more.
  7. If the power-up has no more uses remaining, it expires.

The push power-up is fun to use, so you place two or more in the scene as you see fit. Play the scene once more, and mess around with the new push power-up.

Optional Challenge: An Invulnerability Power-Up

This section is optional, but it's a good bit of fun. Armed with the knowledge you have so far, create a power-up that will make the player invulnerable for a certain amount of time.

Some tips and suggestions to complete this challenge:

  1. Sprite: See the sprite in the project folder Textures/shield
  2. Power Up Name: Invulnerable
  3. Power Up Explanation: You are Invulnerable for a time
  4. Power Up Quote: (Great kid, don't get cocky)
  5. Coding: Work through the same coding checklist you used in the Star and Speed power-up sections. You will need a timer that controls the expiry of the power-up. The SetInvulnerability method in PlayerBrain will toggle invulnerability on and off.
  6. Effects: The project contains a particle effect for a nice pulse effect around the player while they are invulnerable. See the prefab in Prefabs/Power Ups/ParticlesInvuln. You can instantiate this as a child of the player while they are invulnerable.

Need the full solution, or want to check your solution against ours? Have a look at the solution below:

Solution Inside SelectShow>

Hopefully you gave the challenge a try before peeking!

Where To Go From Here?

You can download the completed project for this tutorial here.

If you want to pursue the project further, you could do the following:

  • Add more power-ups. How about a power-up that shoots out rays and kills enemies?
  • Create a factory class to spawn power-ups randomly in the play area at runtime.
  • If you want to explore Unity further, check out the Unity Games by Tutorials book, available from our store.

Are you still wondering what film series the quotes are from? Have a look at the answer below:

Solution Inside SelectShow>

I hope you have enjoyed the tutorial! If you have any questions or comments, please join the discussion below.

The post How to make a Power-Up System in Unity appeared first on Ray Wenderlich.

Viewing all 4374 articles
Browse latest View live


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