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

Creating a Framework


CloudKit Tutorial: Getting Started

$
0
0
Learn how to store your app's data in the cloud with CloudKit!

Learn how to store your app’s data in the cloud with CloudKit!

Update note: This tutorial has been updated to Xcode 7.3, iOS 9.3, and Swift 2.2. The original tutorial was written by Michael Katz.

CloudKit is Apple’s remote data storage service based on iCloud. It provides a low-cost option to store and share app data using your users’ iCloud accounts as a back-end storage service.

There are two main components to CloudKit:

  1. A web dashboard to manage record types and any public data.
  2. A set of APIs to transfer data between iCloud and the device.

CloudKit is secure as well. Users’ private data is completely protected, as developers can only access their own private database and aren’t able to look at any users’ private data.

CloudKit is a good option for iOS-only applications that use a lot of data, but don’t require a great deal of server-side logic. In addition, CloudKit can be used for web and server applications.

In this CloudKit tutorial, you’ll get hands-on experience using CloudKit by creating a restaurant rating app with a twist called, BabiFüd.

Note: To work with the sample app in this CloudKit tutorial you’ll need an active iOS developer account. Without one, you won’t be able to enable the iCloud entitlements or access the CloudKit dashboard.

Why CloudKit?

You might wonder why you should choose CloudKit over Core Data, other commercial BaaS (Back end as a Service) offerings, or even rolling your own server.

There are three reasons: simplicity, trust, and cost.

Simplicity

Unlike other backend solutions, CloudKit requires little setup. You don’t have to choose, configure, or install servers. Security and scaling are handled by Apple as well.

Simply registering for the iOS Developer Program makes you eligible to use CloudKit. You don’t have to register for additional services or create new accounts. When you enable CloudKit capabilities in your app all necessary server setup magic happens automatically.

There’s no need to download additional libraries and configure them. CloudKit is imported like any other iOS framework. The CloudKit framework itself also provides a level of simplicity by offering convenient APIs for common operations.

It’s also easy for users. Since CloudKit uses the iCloud credentials entered when the device is set up (or entered after set up via the Settings app), there’s no need to build complicated login screens. As long as they are logged in, users can seamlessly start using your app. That should put you on Cloud 9!

Trust

Another benefit of CloudKit is that users can trust the privacy and security of their data by relying on Apple rather than app developers. CloudKit insulates user data from you, the developer.

While this lack of access can be frustrating while debugging, it is a net plus since you don’t have to worry about security or convince users their data is secure. If an app user trusts iCloud, then they can also trust you.

Cost

Finally, for any developer, the cost of running a service is a huge deal. Even the least expensive server hosts cannot offer low-cost solutions for small, free or cheap apps. So there will always be a cost associated with running an app.

With CloudKit, you get a reasonable amount of storage and data transfer for public data for free. There is a very thorough explanation of fees in the What’s New in CloudKit WWDC 2015 Video.

These strengths make the CloudKit service a low-hassle solution for Mac and iOS apps.

Introducing BabiFüd

The sample app for this tutorial, BabiFüd, is the freshest take on the standard “rate a restaurant” style of app. Instead of reviewing restaurants based upon food quality, speed of service, or price, users rate child-friendliness. This includes availability of changing facilities, booster seats, and healthy food options.

The app contains four tabs: a list of nearby restaurants, a map of nearby restaurants, user-generated notes, and settings. The list of nearby restaurants is the only tab you’ll use in this tutorial. You can get a glimpse of the app in action below.

NearbyMap

A model class backs these views and wraps the calls to CloudKit. CloudKit objects are called records. The main record type in your model is an Establishment, which represents the various restaurants in your app.

Getting Started

Start by downloading the starter project for this tutorial.

You’ll have to change the Bundle Identifier and Team of your app before you can start coding. You need to set the team in order to get the necessary entitlements from Apple. Having a unique bundle identifier makes the process a whole lot easier.

Open BabiFud.xcodeproj in Xcode. Select the BabiFud project in the Project Navigator, then select the BabiFud target. With the General tab selected, replace the Bundle Identifier with something unique. Standard practice is to use reverse domain name notation and include the project name. Next, select the appropriate Team:

S1 - BabiFud Bundle ID

That takes care of the Bundle Identifier and Team. Now you’ll need to get your app set up for CloudKit and create some containers to hold your data.

Entitlements and Containers

You’ll need a container to hold the app’s records before you can add any data via your app. A container is the term for the conceptual location of all the app’s data on the server. It is the grouping of public and private databases.

CloudKit-container-diagram

To create a container, you first need to enable the iCloud entitlements for your app. Select the Capabilities tab in the target editor. Next flip the switch in the iCloud section to ON.

S2 - Enable iCloud

At this point, Xcode might prompt you to enter the Apple ID associated with your iOS developer account. If so, then type it in as requested. Finally, enable CloudKit by checking the CloudKit checkbox in the Services group.

This creates a default container named iCloud.<your app’s bundle id>, as illustrated below:

S3 - Enable CloudKit

Troubleshooting iCloud Setup in Xcode

If you see any warnings or errors when creating entitlements, building the project, or running the app, and Xcode is complaining about the container ID, then here are some troubleshooting tips:

  • If there are any warnings or errors shown in the Steps group in the iCloud section, then try pressing the Fix Issue button. This might need to be done a few times.
    Fix Issues
  • It’s important that the app’s bundle id and iCloud containers match and exist in the developer account. For example, if the bundle identifier is “com.<your domain>.BabiFud”, then the iCloud container name should be “iCloud.” plus the bundle bundle id: “iCloud.com.<your domain>.BabiFud”.
  • The iCloud container name must be unique because this is the global identifier used by CloudKit to access the data. Since the iCloud container name contains the bundle id, the bundle id must also be unique (which is why it has to be changed from com.raywendrelich.BabiFud).
  • In order for the entitlements piece to work, the app/bundle id has to be listed in the App IDs portion of the Certificates, Identifiers, and Profiles portal. This means the certificate used to sign the app has to be from the set team id and has to list the app id, which also implies the iCloud container id.Normally, Xcode does all of this automatically if you are signed in to a valid developer account. Unfortunately, this sometimes gets out of sync. It can help to start with a fresh ID and, using the iCloud capabilities pane, change the CloudKit container ID to match. Otherwise, to fix it you may have to edit the info.plist or BabiFud.entitlements files to make sure the id values there reflect what you set for the bundle id.

Introducing the CloudKit Dashboard

After setting up the necessary entitlements, the next step is to create some record types that define the data used by your app. You can do this using the CloudKit dashboard. Click CloudKit Dashboard, found in the target’s Capabilities pane, under iCloud.

S5 - CloudKit Dashboard Button

Note: You can also launch the CloudKit dashboard by opening the URL https://icloud.developer.apple.com/dashboard/ in your browser.

Here’s what the dashboard looks like:

S6 - CloudKit Dashboard

The CloudKit dashboard consists of four sections: Schema, Public Data, Private Data, and Admin.

The SCHEMA section represents the high level objects of a CloudKit container: Record Types, Security Roles, and Subscription Types. You’ll only be concerned with Record Types in this tutorial.

A Record Type is a set of fields that defines individual records. In terms of object-oriented programming, a Record Type is like a class. A record can be considered an instance of a particular Record Type. It represents structured data in the container, much like a typical row in a database, and encapsulates a series of key/value pairs.

The PUBLIC DATA and PRIVATE DATA sections let you add data to, or search for data in the databases to which you have access. Remember, as a developer you access all public data, but only your own private data. The User Records store data about the current iCloud user such as name and email. A Record Zone (here noted as the Default Zone) is used to provide a logical organization to a private database by grouping records together. Custom zones support atomic transactions by allowing multiple records to be saved at the same time before processing other operations. Custom zones are outside the scope of this tutorial.

The ADMIN section provides the ability to configure the dashboard permissions for your team members. If you have multiple development team members, you can restrict their ability to edit data here. This, too, is out-of-scope for this tutorial.

Adding the Establishment Record Type

Think about the design of your app for a moment. Each establishment you’ll want to track has lots of data: name, location, and availability of various child-friendly options. Record types use fields to define the various pieces of data contained in each record.

With Record Types selected, click the + icon in the top left of the detail pane to add a new record type.

S7 - Add Record Type

Name your new record type Establishment.

You’ll see a row of fields where you can define the Field Name, Field Type, and Index, as shown below. A field with the default name of, StringField, has been automatically created for you.

S8 - New Record Type

Start by replacing StringField with Name. The Field Type and Index defaults already match what you need for this first field definition, but you’ll need to make changes to the Field Type and Index for some of the other fields. Click Add Field… to add new fields as required. Add the following fields:

T1 - Entitlement Record Fields

When you’re done, your list of fields should look like this:

S10 - List of Fields

Click Save at the bottom of the page to save your new record type.

You’re now ready to add some sample establishment records to your database.

Select Default Zone under the PUBLIC DATA section in the navigation pane on the left. This zone will contain the public records for your app. Select the Establishment record type from the dropdown list in the center pane if it’s not already selected. Then click the + icon or the New Record button in the right detail pane, as shown in the screenshot below:

S11 - Create New Establishment Record

This will create a new, empty Establishment record.

S12 - New Establishment Record Blank

At this point you’re ready to enter some test data for your app.

The following sample establishment data is fictional. The establishments are located near Apple’s headquarters so they’re easy to find in the simulator.

Enter each record as described below:

Note: The image for each CoverPhoto element is included in the Supporting Files\Sample Images folder in the Xcode project. To add the image to the establishment record, simply drag it to the CoverPhoto field.

T2 - Entitlement Records Data

Once all three records have been saved, the dashboard should look like this:

S14 - All Three Records

For each record, the values entered are the database representation of the data. On the app side, the data types are different. For example, SeatingType and ChangingTable are structs. So the specified Int value for a SeatingType might correspond to a “high chair” or a “booster” seat. For HealthyOption and KidsMenu, the Int values represent Boolean types: a 0 means that establishment doesn’t have that option and a 1 means that it does.

Running the app requires you to have an iCloud account that can be used for development.
Creating an iCloud Account for Development.

You will also need to enter into the iOS Simulator the iCloud credentials associated with this account.
Enter iCloud Credentials Before Running Your App

Return to Xcode. It’s time to start integrating this data into your app!

Querying Establishment Records

CKQuery objects are used to select records from a database. A CKQuery describes how to find all records of a specified record type that match certain criteria. These criteria can be something like “all records with a Name field that starts with ‘M’”, or “all records that have booster seats”, or “all records within 3km.” These types of expressions are coded in Cocoa with NSPredicate objects. An NSPredicate evaluates objects to see if they match the specified criteria. Predicates are also used in Core Data and are a natural fit for CloudKit, because predicates commonly are defined as a comparison on a field.

CloudKit supports only a subset of available NSPredicate functions. These include mathematical comparisons, some string and set operations (such as “field matches one of the items in a list”), and a special distance function. The function distanceToLocation:fromLocation: was added to NSPredicate for CloudKit to match records with a location field within a specified radius from a known location. This type of predicate is covered in detail below. For other types of queries, the CKQuery Class Reference contains a detailed list of the supported functions and descriptions of how to use them.

Note: CloudKit includes support for CLLocation objects. These are Core Location Framework objects that contain geospatial coordinates. This makes it quite easy to create a query for finding establishments inside of a geographic region – without doing all of the messy coordinate math yourself.

So, in Xcode, open Model/Model.swift. This file contains stubs for all the server calls your app will make.

Replace the fetchEstablishments(_:radiusInMeters:) method with the following:

func fetchEstablishments(location:CLLocation, radiusInMeters:CLLocationDistance) {
  // 1
  let radiusInKilometers = radiusInMeters / 1000.0
  // 2
  let locationPredicate = NSPredicate(format: "distanceToLocation:fromLocation:(%K,%@) &lt; %f", "Location", location, radiusInKilometers)
  // 3
  let query = CKQuery(recordType: EstablishmentType, predicate: locationPredicate)
  // 4
  publicDB.performQuery(query, inZoneWithID: nil) { [unowned self] results, error in
    if let error = error {
      dispatch_async(dispatch_get_main_queue()) {
        self.delegate?.errorUpdating(error)
        print("Cloud Query Error - Fetch Establishments: \(error)")
      }
      return
    }
 
    self.items.removeAll(keepCapacity: true)
    results?.forEach({ (record: CKRecord) in
      self.items.append(Establishment(record: record,
        database: self.publicDB))
    })
 
    dispatch_async(dispatch_get_main_queue()) {
      self.delegate?.modelUpdated()
    }
  }
}

Taking each numbered comment in turn:

  1. CloudKit uses kilometers in its distance predicates. This line simply converts radiusInMeters to kilometers.
  2. The predicate filters establishments based on their distance in kilometers from the current location. This statement finds all establishments with a location value within the specified distance from the user’s current location.
  3. CKQuery objects are created using a predicate and a record type. Both will be used when performing the query.
  4. Finally, performQuery(_:inZoneWithID:completionHandler:) sends your query up to iCloud, and waits for any matching results. By passing nil as the inZoneWithID parameter, you’re running the query against your default zone; that is, your public database. If you want to retrieve records from both public and private databases, then you have to query each database using a separate call.

Oh. That reminds me. What did CKQuery say to iCloud?

Solution Inside: Caution When Entering SelectShow>

After making a miraculous recovery from such a bad joke, you’re probably wondering where the CKDatabase instance, publicDB, comes from. Take a look the top of Model.swift.

let container: CKContainer
let publicDB: CKDatabase
let privateDB: CKDatabase
 
init() {
  // 1
  container = CKContainer.defaultContainer()
  // 2
  publicDB = container.publicCloudDatabase
  // 3
  privateDB = container.privateCloudDatabase
}

Here you define your databases:

  1. The default container represents the one you specified in the iCloud capabilities pane.
  2. The public database is the one shared amongst all users of your app.
  3. The private database contains only the data belonging to the currently logged-in user; in this case, you.

This code will retrieve some local establishments from the public database, but it has to be wired up to a view controller in order to see anything in the app.

Setting Up the Requisite Callbacks

You can take care of notifications with the familiar delegate pattern. Here’s the protocol from the top of Model.swift that you’ll implement in your view controller:

protocol ModelDelegate {
  func errorUpdating(error: NSError)
  func modelUpdated()
}

Open MasterViewController.swift and replace the modelUpdated() method with the following:

func modelUpdated() {
  refreshControl?.endRefreshing()
  tableView.reloadData()
}

This is called when new data is available. All the wiring up of the table view cells to CloudKit objects has already been taken care of in tableView(_:cellForRowAtIndexPath:). Feel free to take a look.

Next, in MasterViewController.swift, replace the errorUpdating(_:) method with the following:

func errorUpdating(error: NSError) {
    let alertController = UIAlertController(title: nil,
                                            message: error.localizedDescription,
                                            preferredStyle: .Alert)
 
    alertController.addAction(UIAlertAction(title: "Dismiss",
                                            style: .Default,
                                            handler: nil))
 
    presentViewController(alertController, animated: true, completion: nil)
}

This method is called when the query produces an error. Errors can occur as a result of poor network conditions or CloudKit-specific issues (such as missing or incorrect user credentials or no records being returned from the query).

Good error handling is essential when dealing with any kind of remote server. For now, this code just displays to the user the message returned with the error.

One very common issue, however, is the user not being logged into iCloud and/or not having the iCloud drive turned on for this app. Can you modify errorUpdating(_:) to at least handle these situations? Hint: Both errors return a CKErrorCode of 1.

Solution Inside SelectShow>

Build and run. You should see a list of nearby establishments.

Build Run 1 - No Images

Troubleshooting Queries

If you’re using the iOS simulator and the list doesn’t populate, then make sure you have the correct location set by selecting from the Xcode menu, Debug\Simulate Location\San Francisco, CA, USA. If you needed to change the location in Xcode, then pull the table down in the app to force a refresh instead of waiting for a location trigger.

If you’re using an iPhone or iPad, location services are enabled, and the list still isn’t populating, then the establishments aren’t close enough to your current location. You have two options: change the coordinates of the sample data to be closer to your current location or use the simulator to run the app. There is a third option, but it’s not terribly practical as you’d have to travel to Cupertino and hang around the Apple campus.

If the data isn’t appearing properly – or isn’t appearing at all – inspect the sample data using the CloudKit dashboard. Make sure all of the records are present, you’ve added them to the default zone and they have the correct values. If you need to re-enter the data, then you can delete records by clicking the trash icon.

S16 - Delete Record

Debugging CloudKit errors can be tricky at times. As of this writing, CloudKit error messages don’t contain a tremendous amount of information. To determine the cause of the error you’ll need to look at the error code in conjunction with the particular database operation you’re attempting. Using the numerical error code, look up the matching CKErrorCode enum. The name and description in the documentation will help narrow down the cause of the issue. See below for some examples.

Note: For a list of error codes that can be returned by CloudKit, read the CloudKit Framework Constants Reference.

Here are some common error enums and related descriptions:

  • .BadContainer – The specified container is unknown or unauthorized.
  • .NotAuthenticated – The current user is not authenticated and no user record was available. This might happen if the user is not logged into iCloud.
  • .UnknownItem – The specified record does not exist.

When you fetched the list of establishments, you probably noticed that you can see the establishment name and the services the establishments offer. But none of the images are being displayed! Are the clouds in the way?

When you retrieved the establishment records, you automatically retrieved the images as well. You still, however, need to perform the necessary steps to load the images into your app. That’ll chase those clouds away! :]

Working with Binary Assets

An asset is binary data, such as an image, that you associate with a record. In your case, your app’s assets are the establishment photos shown in the MasterViewController table view.

In this section you’ll add the logic to load the assets that were downloaded when you retrieved the establishment records.

Open Model/Establishment.swift and replace the loadCoverPhoto(_:) method with the following code:

func loadCoverPhoto(completion:(photo: UIImage!) -&gt; ()) {
  // 1
  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
    var image: UIImage!
 
    // 4
    defer {
      completion(photo: image)
    }
 
    // 2
    guard let asset = self.record["CoverPhoto"] as? CKAsset,
      path = asset.fileURL.path,
      imageData = NSData(contentsOfFile: path) else {
        return
    }
 
    // 3
    image = UIImage(data: imageData)
  }
}

This method loads the image from the asset attribute as follows:

  1. Although you download the asset at the same time you retrieve the rest of the record, you want to load the image asynchronously. So wrap everything in a dispatch_async block.
  2. Assets are stored in CKRecord as instances of CKAsset, so cast appropriately. Next load the image data from the local file URL provided by the asset.
  3. Use the image data to create an instance of UIImage.
  4. Execute the completion callback with the retrieved image. Note that this defer block gets executed regardless of which return is executed. For example, if there is no image asset, then image never gets set upon the return and no image appears for the restaurant.

Build and run. You’ve chased the clouds away and the establishment images should now appear. Great job!

Build Run 2 - With Images

There are two gotchas with CloudKit assets:

  1. Assets can only exist in CloudKit as attributes on records. You can’t store them on their own. Deleting a record will also delete any associated assets.
  2. Retrieving assets can negatively impact performance because the assets are downloaded at the same time as the rest of the record data. If your app makes heavy use of assets, then you should store a reference to a different type of record that holds just the asset.

Where To Go From Here?

You can see what’s been built so far in the Final Project. The app is now able to download Establishment records and load their details and photos into the table view.

You can enhance the app in several ways:

  • Allow the user to add their own pictures, notes, reviews, and complaints. This will prevent them from re-visiting a bad experience.
  • Let the user create new Establishment records using the map. The functions added to your Model class can serve as an example for saving the record to either the public or private databases.
  • Add filtering and searching. The Model class constructs a CKQuery with a distance predicate, but this can be modified to be a more complex predicate. CloudKit supports text searching of string fields as well.
  • Improve the performance of the app and the data loading experience. This tutorial used the available convenience methods to invoke the necessary completion handlers when everything is ready. Instances of CKDatabase also have NSOperation-based methods that provide more control over how the API is executed.
  • Provide caching and synchronization so the app remains responsive offline and keeps the content up to date when it reconnects to a network.

You can also check out Brian Moakley’s Video Tutorial Series on CloudKit.

If you have any questions or comments about this tutorial, then please join the forum discussion below!

With CloudKit you can really take your apps to the next level and beyond with this great Apple-provided backend API. We can’t wait to see what you make. In the meantime, feel free to join us and our kids for a slice at Caesar’s Pizza!

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

RWDevCon 2016 Inspiration Talk – The Power of Small by Cesare Rocchi

$
0
0

Note from Ray: At our recent RWDevCon tutorial conference, in addition to hands-on tutorials, we also had a number of “inspiration talks” – non-technical talks with the goal of giving you a new idea, some battle-won advice, and leaving you excited and energized.

We recorded these talks so that you can enjoy them, even if you didn’t get to attend the conference. Here’s our next talk – The Power of Small by Cesare Rocchi – I hope you enjoy!

Transcript

Grow, grow, grow!

sapling-154734_640

We are surrounded by podcasts, conferences, books, blog posts, all forcing us to grow. Grow our user base, grow the number of downloads of our apps, grow our mailing lists. Always grow!

This is probably propelled by the Silicon Valley movement in which hockey stick growth is a requirement if you want to chase the next round of funding.

We also are used to hearing that size matters.

giant-1013693_640

Even excluding all the nasty interpretations of that, probably you’ll think that the bigger the better. The bigger my team is, the more projects I can take on. The bigger is the market, the bigger is the potential income. I don’t want to even mention the bigger the code base…

It’s all true. Grow, grow, it’s all true. Probably. But is it worth it? Have you ever asked yourself is it worth it to chase something bigger? Do I want to give up the power of small?

Well, in the 70’s IBM was the king – I’d say the emperor of computers. Then out of the blue, two dudes in a garage started small – and you know the rest of the story.

Today I’m going to talk about the power of small. I’m going to show you some example of the advantages of working in a small market with a small team and exploiting the advantages of a small launch.

The Power of Small

Let’s start with the advantages of a small market or niche.

rwanda-1430595_640

Note it’s pronounced niche, not nitch, because it’s French.

  1. First of all, big companies do not usually care about small markets because there’s not a lot of money to be made there.
  2. Advertisements usually in niche markets are way cheaper and more cost effective.
  3. The third part is there are fewer competitors, so it’s much easier for you to stand out.
  4. The fourth point, probably the most important, is that probably you’ll end up talking to the real customers, experiencing the real problem that your app or product or service is trying to solve, as opposed for example to the enterprise in which you usually talk to the CTO or the marketing manager that represent the people having the real problem.

Here’s a quick example of a small successful market:

Screen Shot 2016-06-27 at 5.30.30 PM

This is Soda Pop Stop. John Nese and his family have been running this business in LA for a long time. They started as a grocery store and now they have a website that sells and ships sodas worldwide. Probably you’ve never heard of this company. We all know that the sodas market is dominated by huge companies that I’m not even going to mention.

But Johnny’s family has been able to carve out a small niche in which people prefer something alternative, I’d say unique, like for example the Werewolf Howling Ginger Beer or the Pumpkin Spice Tonic, which you’ve probably never heard of. That’s fine. Because that’s a nitch or niche?

Audience replies: Niche.

Great. Johnny’s family have been able to run this company for 100 years. Are you seeing the power of small already?

Advantage 1: Moving Faster

Let’s talk about the advantages of a small team. You can move faster.

Screen Shot 2016-06-27 at 5.31.07 PM

Let me tell you a quick story. I joined a startup a few years ago. I was the only mobile developer, front end developer, and the other developers took care of the back end. We used Git but honestly we could have used a shared Dropbox folder because we never had a merge issue, our changes never overlapped, and after years that we both spent in the enterprise and convoluted processes we felt wild and young and free.

Really, I was committing code to the master branch and I felt like this when I did it.

surfing

But things changed. The company grew. We had to put in place formal process and documents and agreeing on a time slot for a meeting took longer than the meeting itself.

I could not commit to the master branch anymore unfortunately. You know the drill. You had to branch out, do your thing, run the tests, code review and then merge, and then Q&A, and then staging, and then production.

Don’t get me wrong. I mean, having a process is a great thing, because you have fewer chances to screw up. But it also can enlarge the distance between you building the product and the people using the product.

Advantage 2: Easier Decision Making

Now a small team is a competitive advantage so make the most of it. In a small team for example making decisions is much easier.

Screen Shot 2016-06-27 at 5.31.28 PM

This is a story that Luke Parham, an iOS team member at raywenderlich.com, told me. He worked at a company. They had an app that allowed to consult used car reports. So instead of going to the dealer you just browse cars in the app.

They had a back end in Java. It was in Struts framework. (I can’t believe I mentioned both Java and Struts at a Mac and iOS friendly conference!)

Now if you look in the dictionary for the definition of “long”, there are a few examples there. One of them is the discussion that you can spark when you ask a bunch of developers, “Should I use vi or Emacs?”

Still in the dictionary, if you look up the definition of endless, one of the examples says, “The discussion that you can spark when somebody in a room full of developer says, ‘We should use a more modern framework for our back end.’”

Now at Luke’s company there were 7 people, 7 developers. It’s an odd number. It should be easy to come up with a majority. 2 wanted to go with Rails, 2 with Django, 1 with node JS, 1 didn’t care, the other one wanted to stick with the old framework. You can image which kind of discussions they had.

At some point somebody started building prototypes trying to show the advantages of a framework over the other. As it happens usually the meeting started with 7 people and after 2 months 20 people were attending the meeting and contributing and discussing and essentially wasting time.

Guess what? In the end they decided to stick to the old framework.

Now who here heard or lived a similar story? I see somebody can relate to this. This is what happens in a big, big team unfortunately.

Advantage 3: Small Launch

Now let’s see the advantages of a small launch.

Imagine you had your idea. You designed it. You built it. You are ready to ship. But at some point one thought, especially if your app has some back end, this thought is going to hit you: “What if it doesn’t scale? What if some famous blogger talks about us and all the customers use our app and hog our servers?”

Have you ever heard something along the lines of this? Yeah.

A few observations.

  1. It’s a very nice to have problem.
  2. It’s probably not going to happen.
  3. Instead of postponing the launch by 6 months because you’ve got to reword all the back end to scale it up, why not just soft launching to friends, to people you trust, to people that you have meet at some conference? Why not just soft launching to some people that drop their email address on the landing page? Why not just testing the ground and see how it goes, instead of getting in a tunnel that is 6 months long.

The Story of Buffer

Take Buffer for example.

Screen Shot 2016-07-04 at 2.14.36 PM

They started with a simple landing page. Buffer if you don’t know is a service that allows you to schedule social media posts. They support Twitter, Facebook, Pinterest, LinkedIn, and so on. They started just with Twitter. They started just with 1 web page that explained the product and they noticed that people clicked.

After a while they added a second page, fake, showing the pricing plans. It was fake and again people were clicking. Bottom line after 7 weeks they build a product just with Twitter and they had the first few paying customers. They did exactly that, start slow.

A small launch can help you in testing the ground, testing the code, testing the design, spotting bugs.

paper-plane-149424_640

It’s not a new idea at all. Restaurants do soft openings every time to give the stuff a test for example and to spot issues in the menu, typos in the menu for example.

dining-room-103464_640

Have you ever watched the Ocean’s Thirteen? A few of you, okay. So no spoilers, but there’s a pretty good scene of a casino doing a soft opening in the movie.

Tips and Tricks

Now let’s see some tricks that you can exploit to stay small and focused.

The first one probably my preferred one is to set a time limit.

hourglass-620397_640

Think along the lines of will submit this app in 3 weeks with feature A, B, and C, and that’s it. Or let’s take big app, break it down in 6 milestones, and then finish just the first one and ship it to the store in 3 weeks.

Set a time limit because if you do that … Well, first of all, the end is in sight, so I got to get there and not somewhere unknown. You go with small steps. That helps the morale because you easily notice the progress day by day.

Set a limit on features. I’m sure any of us probably at some point in their career started with an app, big ideas, many features, I’m going to do everything, and then you end up struggling along the way, you are 40% done and you don’t even know if you’re ever going to finish the app.

check-off-1345864_640

Why not starting with fewer features? By the way, you don’t even know if all those features are relevant and valuable to your customers. So why not just starting with fewer features and maybe talking to your customers about those features? Much easier.

The third suggestion is break it down.

strength-1148029_640

Try to break it down as much as possible. Now, I am a father, I have a family. I cannot afford anymore 10 hours of uninterrupted work a day. Although sometimes I think if I could have 3 good solid days, but I can’t. But I happen to have on the spot 20 minutes here and there.

Now if I carefully organize my to-do list with small actions easy to chew, then it’s great. What can I do in 20 minutes? Well,

  • I can come up with 3 headlines for the landing page.
  • I can draft a welcome email message on my service.
  • I can write a test for the logging procedure.
  • There’s so many things that I can do in this on the spot 20 minutes that I happen to have.

    Summing up here is the list of my suggestions.

  • Set a time limit
  • Set a limit on features and
  • Break it down as much as possible.
  • Real World Example: Base Camp

    Let’s see a few examples in the world of software. You probably are familiar with Basecamp.

    Screen Shot 2016-07-04 at 9.45.25 PM

    They’re not a publicly traded company so they are not forced to share numbers at all. Pretty good place to be. But we can make an educated guess that they have around 10 million users.

    Do you want to venture and answer to the question how many people are working at Basecamp? 50. That’s CEO, CTO, designers, developers, janitors, everybody. 50 people doing everything.

    There’s a lot of advantages in this situation. They’re also bootstrapped. First of all, they’ve been able to grow the company culture slowly. No revolutions. Also that means that people tend to leave the company less often.

    Also they are careful in hiring because you know in this case hiring means cutting a part of your check every month to pay someone else to work for the company. But it’s been working great for them so far because they’ve been around for 12 or 13 years as far as I remember.

    Real World Example: Quip

    Another example is Quip.

    Screen Shot 2016-07-04 at 9.45.08 PM

    This is a VC funded company in the Valley so they have money, but probably they don’t spend it on developers because they have an app that is compatible with the Mac, Windows, Linux, Android tablets, iPhone, iPad, Apple watch. And it’s just 13 people, including CEO and CTO which probably are not going to code every single day.

    They have a small team, tight-knit, super effective communication and they are forced to prioritize. This is the result and it’s great.

    Real World Example: Desk PM

    There’s also solo developers. Have you ever heard of the app Desk PM?

    Screen Shot 2016-07-04 at 9.47.38 PM

    It’s made by John Saddington. Just one guy. He won the Apple award 2 years in a row. It’s a blogging application. I’m sure I can say there’s no shortage of blogging applications in the App Store and yet he’s been so successful.

    Now when you’re solo, again, there are advantages. Like you can choose your own pace. It took John 13 years to build the app.

    You can experiment and you can decide where do you want to go. Also, how to reinvest your income. For example, there’s a pretty famous blog post in which he describes how he dropped either 9 or 10k as sponsorship on Daring Fireball and it was totally worth it.

    Where To Go From Here?

    Summing up, being small has advantages. So being bigger isn’t always the best option.

  • You can move faster.
  • You can experiment more.
  • You get to choose your own pace.
  • I’d like to close the presentation with a Chinese proverb that really distills my message.

    “It is better to take many small steps in the right direction than to make a great leap forward only to stumble backward.”

    Now, what is your next small step?

    footprint-1345564_640

    Note from Ray: Hopefully after this talk, your next step is to sign up for RWDevCon 2017! :] We’ve sold out for the past two years so don’t miss your chance.

    The post RWDevCon 2016 Inspiration Talk – The Power of Small by Cesare Rocchi appeared first on Ray Wenderlich.

    CloudKit JS Tutorial for iOS

    $
    0
    0
    Learn how to access CloudKit databases from a web app in this CloudKit JS tutorial!

    Learn how to access CloudKit databases from a web app in this CloudKit JS tutorial!

    iCloud does a lot of great things. It bridges the gap between iOS and macOS by storing and syncing app data and files so the user can access their stuff from any Apple device. Notes and Photos are excellent examples of the power of this service — if your stuff’s on one device, it’s reliably on the rest of them within moments. It’s almost magical.

    In addition to the obvious use cases, iCloud hosts apps’ public and private databases and handles user authentication.

    CloudKit is the framework that affords access to iCloud, providing tons of APIs to make it easier to incorporate iCloud’s magical ways into your creations.

    When Apple announced CloudKit in 2014, web services topped the list of feature requests. Then in 2015, Apple announced CloudKit Web Services, a JSON/HTTPS interface for CloudKit.

    Apple took it a step further and provided CloudKit JS, which makes it simple to create a web-based interface to access a CloudKit app’s databases. CloudKit JS wraps the REST API in concise code, so you don’t have to compose paths manually or parse JSON.

    As you work through this CloudKit JS tutorial, you’ll create a web app to access the database of a CloudKit iOS app. When you’re done, it’ll provide web access to users and even make app data available to non-iOS users!

    Prerequisites

    You’ll need basic understanding of HTML and JavaScript for this tutorial. For a quick refresher, check out W3Schools.

    This CloudKit JS tutorial also assumes you have working knowledge of CloudKit. If you don’t, we suggest starting with our CloudKit Tutorial: Getting Started.

    Also nice to have, but not required:

    • Membership in the Apple Developer or Apple Developer Enterprise program.
    • Some familiarity with Knockout.js to create data bindings and Skeleton to layout the web page.

    Carry on FTW!  TBH YOLO... and also FOMO

    CloudKit JS

    CloudKit JS features a similar design to CloudKit iOS, which makes it easier for iOS developers to create CloudKit web apps. Its main features include:

    • Web sign in with Apple ID — your app won’t see usernames and passwords, but you’ll give users the option to be discoverable. When a user opts-in, the app will be given their name. Other users will be able to discover them if they know their email address.
    • Full CRUD (create, read, update, and delete) access to public and private databases.
    • Feature parity with CloudKit iOS, including subscriptions and notifications, using completions via JavaScript promises.

    I promise to tell you all about promises soon

    Best of all, because CloudKit JS feels familiar to web developers, you can simply give them your container ID, API key and database schema and let them build the web app. ;]

    CloudKit JS works on mainstream browsers, including Safari, Firebox, Chrome, Internet Explorer and Microsoft Edge.

    In February 2016, Apple announced that CloudKit now supports server-to-server web service requests, enabling reading and writing to CloudKit databases from server-side processes or scripts. You’ll see why this is significant at the end of this tutorial.

    Getting Started

    As a relative n00b to social media, I often learn new acronyms from people I follow on Twitter.

    For instance, TIL means “Today I Learned” — I felt it’s the perfect name for this sample app. It’s a simple premise: users can view and add acronym definitions to a public CloudKit database.

    To run the sample CloudKit iOS app, you must be a member of the Apple Developer Program or the Apple Developer Enterprise Program. You won’t be able to run the iOS app if you’re not. :[

    However, non-members can still build the web app to access my CloudKit container. You’ll just need to skip certain sections related to CloudKit setup — it’ll be clear what to skip.

    If you don’t have a Mac, that’s okay! You don’t need one to build the web app.

    Download and unzip TIL Starter. It contains the starter iOS app, web app, and server files.

    Setting up CloudKit and the iOS App

    Note: This is one of those spots where “Apple Developers” part ways with those who are not. ;]

    • If you’re not an Apple Developer, skip to the Configuring CloudKit JS section — although you won’t play around with the sample config, you’ll see what’s needed from a CloudKit app in order to create its web app.
    • If you are a member, follow the steps below to set up the sample CloudKit iOS app using your own iCloud container.

    Open TIL.xcodeproj. Select the TIL project in the project navigator, and then under Targets\TIL\General change the Bundle Identifier and Team to match your information. Tap Fix Issue to get Xcode to create the provisioning profile.

    xcode01

    In Targets\TIL\Capabilities, toggle iCloud OFF then ON again, and select Key-value storage, CloudKit, and Use default container.

    Note: Enabling CloudKit in your app automatically creates a default container to store the app’s databases and user records. However, it only stores your app’s public data. Private data saves directly to users’ iCloud accounts. Fortunately, iCloud automatically handles user registration and creates a unique identifier for each user. You’ll add authentication later in this tutorial.

    Tap CloudKit Dashboard to open the CloudKit Dashboard in a browser. You can use the dashboard to access, set up and view records online, and manage your CloudKit app.

    xcode02

    Sign in to the iCloud account that matches the Team you set in Targets\TIL\General. Select the TIL container from the list.

    dashboard01

    Note: If you don’t see TIL, try refreshing the page. Sometimes CloudKit’s dashboard won’t show new data, but waiting a few seconds and refreshing typically fixes the issue.

    Select Schema\Record Types and press + to create a new record type. Name it Acronym and add two fields. Name the first short and the second long. Make sure both fields’ type is set to String. Tap Save.

    dashboard02

    In Public Data\Default Zone, create two new Acronym records. For the first, set its long value to Today I Learned and short to TIL. For the second, set long to For The Win and short to FTW.

    Note: As with the TIL container, you may not see Acronym appear under Default Zone straight away. You might just see NewRecordType until you refresh the page.

    dashboard03

    Go to the iPhone simulator, open Settings and sign in to iCloud. Build and run the TIL iOS app. Your new records should appear!

    TIL Starter App screenshot

    In the iOS app, tap the + button and add two items: BTW/By The Way and TBH/To Be Honest.

    Back in your browser, change the Sort by order in the CloudKit dashboard’s Default Zone to sort by new items — it’s a little hack that “refreshes” the records in the CloudKit dashboard.

    dashboard04

    A Word About Knockout and Skeleton

    Your web app will update its UI when users sign in or out and when the database changes by using knockout.js to create dynamic data bindings between the UI in index.html and the data model in TIL.js.

    If you’re familiar with the MVVM design pattern, then know that the CloudKit database is the model, index.html is the view, and TIL.js is the view model.

    Knockout provides data bindings for text, appearance, control flow and forms. You’ll inform Knockout of which view model properties can change by declaring them as observable.

    You’ll also use the Skeleton responsive CSS framework to create a grid-based web UI. Each row contains 12 columns to use to display elements.

    Configuring CloudKit JS

    Inside the TIL Starter/Web folder are TIL.js and index.html. You’ll add JavaScript code to TIL.js to fetch and save Acronym records, and you’ll update index.html to display and get user input for Acronym records.

    Open TIL.js and index.html in Xcode and go to Xcode\Preferences. In Text Editing\Indentation, uncheck Syntax-aware indenting: Automatically indent based on syntax. Xcode’s auto-indent doesn’t work well with JavaScript, but its Editor\Structure functions are still useful.

    Take a look at the code in TIL.js:

    // 1
    window.addEventListener('cloudkitloaded', function() {
      console.log("listening for cloudkitloaded");
      // 2
      CloudKit.configure({
        containers: [{
          // 3
          containerIdentifier: 'iCloud.com.raywenderlich.TIL',
          apiToken: '1866a866aac5ce2fa732faf02fec27691027a3662d3af2a1456d8ccabe9058da',
          environment: 'development'
        }]
      });
      console.log("cloudkitloaded");
      // 4                      
      function TILViewModel() {
        var self = this;
        console.log("get default container");
        var container = CloudKit.getDefaultContainer();
      }
      // 5
      ko.applyBindings(new TILViewModel());
    });
    1. window is the browser window. Apple recommends loading cloudkit.js asynchronously, so window.addEventListener('cloudkitloaded', function() { ... } attaches the function as the event handler of the cloudkitloaded event. The rest of the code in TIL.js is the cloudkitloaded event handler.
    2. After cloudkit.js loads, you configure the CloudKit containers by specifying each one’s identifier, API token and environment.
    3. Change the containerIdentifier to match the value of the default container, which should be iCloud, followed by the iOS app’s bundle identifier you set earlier.
    4. Next, TILViewModel() simply renames JavaScript’s this to self, which is more familiar to iOS developers, and gets the default container.
    5. The last line applies Knockout bindings: there aren’t any bindings yet, but this also creates and runs TILViewModel().

    Create an API Token

    Note: If you’re not an Apple Developer, leave my container identifier and API token as they are in TIL.js and advance to the Error Codes section. If you want to create a web app to access someone else’s CloudKit container, you’ll need their container identifier and a fresh API token for your web app — see below.

    In the CloudKit dashboard, create an API token for your container. Select Admin\API Access and then Add new API token. Name it JSToken, check Discoverability and click Save.

    dashboard05

    Copy the token.

    dashboard06

    Back in TIL.js, paste your new token in place of the current apiToken. Leave environment set to development and save.

    Error Codes

    TIL.js contains console.log statements that perform the same role as debug print statements in Swift. The messages appear in the browser’s console — Safari’s Error Console, Chrome’s JavaScript Console, or Firefox’s Browser Console.

    Showing the Safari Error Console

    Open index.html in Safari. To show the error console, select Safari\Preferences\Advanced, and check Show Develop menu in menu bar.

    Close the preferences window and select Develop\Show Error Console. Refresh the page to see console.log messages.

    browser01

    Note: If you’re using Chrome, its console is in the View\Developer menu.

    If you’re using Firefox, find it under the Tools\Web Developer menu.

    Querying the Public Database

    Anyone can view the public database, even without signing in to iCloud, as long as you fetch the public records and display them on a webpage. That’s what you’ll do in this section.

    In TIL.js, add the following to TILViewModel(), right before the method’s ending curly brace:

    console.log("set publicDB");
    var publicDB = container.publicCloudDatabase;
    self.items = ko.observableArray();

    This little block gets you a reference to the public database via publicDB then it declares items as a Knockout observable array that contains the public records.

    Add the following right after the lines you just added:

    // Fetch public records
    self.fetchRecords = function() {
      console.log("fetching records from " + publicDB);
      var query = { recordType: 'Acronym', sortBy: [{ fieldName: 'short'}] };
     
      // Execute the query.
      return publicDB.performQuery(query).then(function(response) {
        if(response.hasErrors) {
          console.error(response.errors[0]);
          return;
        }
        var records = response.records;
        var numberOfRecords = records.length;
        if (numberOfRecords === 0) {
          console.error('No matching items');
          return;
        }
     
        self.items(records);
      });
    };

    Here you define the fetchRecords function, which retrieves the public records sorted by the short field and stores them in items.

    Note: If you want to create a web app to access someone else’s CloudKit container, you need to know how its databases are organized, namely record types, field names and field types.

    TIL’s public database stores records of type Acronym, which has two String fields named short and long.

    Lastly, add the following right after the previous lines:

    container.setUpAuth().then(function(userInfo) {
      console.log("setUpAuth");
      self.fetchRecords();  // Don't need user auth to fetch public records
    });

    Here you run container.setUpAuth() to check whether a user is signed in, and then it presents the appropriate sign-in/out button. You don’t need authentication yet, but you still call fetchRecords() to get the Acronyms to display.

    Save TIL.js.

    Next, open index.html and scroll to the bottom. Add the following right above the End Document comment:

    <div data-bind="foreach: items">
      <div class="row">
        <div class="three columns">
          <h5><span data-bind="text: fields.short.value"></span></h5>
        </div>
        <div class="nine columns">
          <p><span data-bind="text: fields.long.value"></span></p>
        </div>
      </div>
    </div>

    Here you iterate through the items array. Each element in items is an acronym record.

    Knockout’s text binding displays the short and long text values. The foreach control flow binding duplicates the Skeleton row for each element in items, and it binds each row to the corresponding items element.

    Because items is an observable array, this binding efficiently updates the displayed rows every time items changes.

    Save index.html and reload it in the browser. Public database records appear in the browser window and console.log messages still show in the error console.

    browser02

    Note: Because there are no signed in users, a 421 error appears when you initialize publicDB. Don’t worry, this won’t stop the list from appearing. Select Logs instead of All to see only log messages. If the list doesn’t appear, check the console messages to see if CloudKit failed to load, and if so, reload the web page.

    Authenticating iCloud Users

    To add items to the public database, users must sign in to iCloud. Apple handles user authentication directly and provides sign-in and sign-out buttons. If a user has no Apple ID, the sign-in dialogue lets them create one.

    In TIL.js, add this code to the end of container.setUpAuth(), just below the call to fetchRecords():

    if(userInfo) {
     self.gotoAuthenticatedState(userInfo);
    } else {
     self.gotoUnauthenticatedState();
    }

    container.setUpAuth() is a JavaScript promise — the outcome of an asynchronous task. In this case, the task determines whether there’s an active CloudKit session with an authenticated iCloud user. When the task finishes, the promise resolves to a CloudKit.UserIdentity dictionary or null, or it rejects to a CloudKit.CKError object.

    When the promise resolves, the CloudKit.UserIdentity dictionary becomes available to the then function as the parameter userInfo. You just added the body of the then function; if userInfo isn’t null, you pass it to gotoAuthenticatedState(userInfo); otherwise, you call gotoUnauthenticatedState().

    I fulfilled my promise to tell you about JavaScript promises!
    Now, you’ll define these two functions, starting with gotoAuthenticatedState(userInfo).

    Add these lines right above container.setUpAuth().then(function(userInfo) {:

    self.displayUserName = ko.observable('Unauthenticated User');
    self.gotoAuthenticatedState = function(userInfo) {
      if(userInfo.isDiscoverable) {
        self.displayUserName(userInfo.firstName + ' ' + userInfo.lastName);
      } else {
        self.displayUserName('User Who Must Not Be Named');
      }
     
      container
      .whenUserSignsOut()
      .then(self.gotoUnauthenticatedState);
    };

    Because you checked Request user discoverability at sign in when you created the API key, users can choose to let the app know their names and email addresses.

    If the user isDiscoverable, the web page will display their name. Otherwise, they’ll be called the User Who Must Not Be Named; while you could display the unique userInfo.userRecordName returned by the iCloud sign-in, that’d be far less amusing. ;]

    Either way, iCloud remembers the user’s choice and doesn’t ask again.

    container.whenUserSignsOut() is another promise — its then function calls gotoUnauthenticatedState().

    Right after the code you just inserted, add the following to define gotoUnauthenticatedState():

    self.gotoUnauthenticatedState = function(error) {
      self.displayUserName('Unauthenticated User');
     
      container
      .whenUserSignsIn()
      .then(self.gotoAuthenticatedState)
      .catch(self.gotoUnauthenticatedState);
    };

    When no user is signed in, you reset displayUserName and wait for a user to sign in. If the container.whenUserSignsIn() promise rejects to an error object, the app remains in an unauthenticated state.

    Save TIL.js, and go back to index.html in Xcode.

    Add the following right after <h2>TIL: Today I Learned <small>CloudKit Web Service</small></h2>:

    <h5 data-bind="text: displayUserName"></h5>
      <div id="apple-sign-in-button"></div>
      <div id="apple-sign-out-button"></div>

    The h5 header creates a text binding to the observable displayUserName property in TIL.js. To fulfill its promise, container.setUpAuth() displays the appropriate sign-in/out button.

    Save and reload index.html to see Unauthenticated User and the sign-in button.

    browser03

    Click the sign-in button and login to an iCloud account. Any Apple ID works; it need not be an Apple Developer account.

    browser04

    After you sign in, the web page will update displayUserName and display the sign-out button.

    browser05

    Sign out of iCloud before continuing — the next step will clear userInfo and display the sign-in button. You’ll feel more in control if you sign out now. :]

    Updating the Public Database

    You need a web form where users can add new items and some corresponding JavaScript that’ll save items to the public database.

    In TIL.js, right after the fetchRecords() definition, add these lines:

    self.newShort = ko.observable('');
    self.newLong = ko.observable('');
    self.saveButtonEnabled = ko.observable(true);
    self.newItemVisible = ko.observable(false);

    Here you declare and initialize observable properties that you’ll bind to the UI elements in index.html.

    There will be two input fields, newShort and newLong and a submit button that you’ll disable when saving the new item.

    Only authenticated users can add items to the database, so newItemVisible controls whether the new-item form is visible. Initially, it’s set to false.

    Add this line to the gotoAuthenticatedState function right after its open curly brace:

    self.newItemVisible(true);

    This block makes the new-item form visible after a user signs in.

    Add this to the top of the gotoUnauthenticatedState function:

    self.newItemVisible(false);

    In here, you’re hiding the new-item form when the user signs out.

    Next, add the following to define the saveNewItem function, right below the self.newItemVisible = ko.observable(false); line:

    self.saveNewItem = function() {
      if (self.newShort().length > 0 && self.newLong().length > 0) {
        self.saveButtonEnabled(false);
        var record = { recordType: "Acronym",
            fields: { short: { value: self.newShort() },
              long: { value: self.newLong() }}
        };
        publicDB.saveRecord(record).then(function(response) {
          if (response.hasErrors) {
            console.error(response.errors[0]);
            self.saveButtonEnabled(true);
            return;
          }
          var createdRecord = response.records[0];
          self.items.push(createdRecord);
          self.newShort("");
          self.newLong("");
          self.saveButtonEnabled(true);
        });
      } else {
        alert('Acronym must have short and long forms');
      }
    };

    This checks that input fields are not empty, disables the submit button, creates a record and saves it to the public database. The save operation returns the created record, which you push (append) to items instead of fetching all the records once again. Lastly, you clear the input fields and enable the submit button.

    Save TIL.js, and return to index.html in Xcode.

    Add the following right before <div data-bind="foreach: items">:

    <div data-bind="visible: newItemVisible">
    <div class="row">
      <div class="u-full-width">
        <h4>Add New Acronym</h4>
      </div>
    </div>
    <form data-bind="submit: saveNewItem">
    <div class="row">
      <div class="three columns">
        <label>Acronym</label>
        <input class="u-full-width" placeholder="short form e.g. FTW" data-bind="value: newShort">
      </div>
      <div class="nine columns">
        <label>Long Form</label>
        <input class="u-full-width" placeholder="long form e.g. For the Win" data-bind="value: newLong">
        <input class="button-primary" type="submit" data-bind="enable: saveButtonEnabled" value="Save Acronym">
      </div>
    </div>
    </form>
    <hr>
    </div>

    The heart of this code is a web form with two input fields — short gets three columns and long gets nine. You also created a submit button that’s left-aligned with the long input field. Whenever the submit button is tapped, saveNewItem is invoked.

    For the value bindings, you name the observable properties newShort and newLong that saveNewItem uses. The visible binding will show or hide the web form, according to the value of the observable property newItemVisible. Lastly, the enable binding enables or disables the submit button, according to the value of the observable property saveButtonEnabled.

    Save the file and reload index.html in a browser.

    Sign in to an iCloud account and the fancy new form should show itself. Try adding a new item, such as YOLO/You Only Live Once:

    browser06

    Click Save Acronym and watch your new item appear at the end of the list!

    browser07

    Go back to the CloudKit Dashboard \ Default Zone and change the sort order to see your new item appear.

    dashboard07

    Getting Notification of Changes to the Public Database

    When users add or delete items the web page should update to show the current list. Like any respectable CloudKit iOS app, your app can subscribe to the database for updates.

    In TIL.js, add the following inside the gotoAuthenticatedState function, right after self.newItemVisible(true):

    //1 
    var querySubscription = {
      subscriptionType: 'query',
      subscriptionID: userInfo.userRecordName,
      firesOn: ['create', 'update', 'delete'],
      query: { recordType: 'Acronym', sortBy: [{ fieldName: 'short'}] }
    };
     
    //2
    publicDB.fetchSubscriptions([querySubscription.subscriptionID]).then(function(response) {
      if(response.hasErrors) {  // subscription doesn't exist, so save it
        publicDB.saveSubscriptions(querySubscription).then(function(response) {
          if (response.hasErrors) {
            console.error(response.errors[0]);
            throw response.errors[0];
          } else {
            console.log("successfully saved subscription")
          }
        });
      }
    });
     
    //3
    container.registerForNotifications();
    container.addNotificationListener(function(notification) {
      console.log(notification);
      self.fetchRecords();
    });

    Here’s what you set up:

    1. Subscriptions require users to sign in because they use per-user persistent queries, so you set subscriptionID to userInfo.userRecordName.
    2. To avoid firing off the error message triggered by saving a pre-existing subscription, you attempt to fetch the user’s subscription first. If the fetch fails then the subscription doesn’t exist, so it’s safe to save it.
    3. You register for notifications and add a notification listener that calls fetchRecords() to get the new items in the correct sorted order.

    Save TIL.js, reload index.html in a browser and sign in. Add a new acronym (perhaps AFK/Away From Keyboard) in the CloudKit dashboard, another browser window, or in the iOS app.

    The notification appears in the console and the list of updates on the page! Magic!

    browser08

    Handling Race Conditions

    Sometimes the list doesn’t update, even when the notification appears and fetchRecords successfully completes.

    The reason this happens is that race conditions are possible with asynchronous operations, and fetchRecords sometimes runs before the new item is ready. Try printing records.length to the console at the end of the performQuery(query) handler so you can see that this number doesn’t always increase after a notification.

    You can mitigate this risk by replacing the first class="row" div of index.html with the code below to provide a manual refresh button:

    <div class="row">
      <div class="u-full-width">
        <h2>TIL: Today I Learned <small>CloudKit Web Service</small></h2>
      </div>
    </div>
    <div class="row">
      <div class="six columns">
        <h5 data-bind="text: displayUserName"></h5>
      </div>
      <div class="four columns">
        <div id="apple-sign-in-button"></div>
        <div id="apple-sign-out-button"></div>
      </div>
      <div class="two columns">
        <div><button data-bind="click: fetchRecords">Manual Refresh</button></div>
      </div>
    </div>

    Save and reload index.html to see the new button. By the way, it even works without signed in users:

    browser09

    Bonus: Server-Side CloudKit Access

    On February 5, 2016 — a week after Facebook announced plans to retire the Parse service — Apple announced that CloudKit now supports server-to-server web service requests, enabling reading and writing to CloudKit databases from server-side processes or scripts.

    Talk about a Big Deal: now you can use CloudKit as the backend for web apps that rely on admin processes to update data — like most modern web apps.

    However, the API key isn’t enough. You need a server key.

    Note: If you’re not in an Apple Developer Program, you won’t be able to do this part of the tutorial because it requires my private key. At least read through it so you’re familiar with the process of implementing this excellent feature.

    Open Terminal, cd to the TIL Starter/Server directory, and enter this:

    openssl ecparam -name prime256v1 -genkey -noout -out eckey.pem

    This creates a server-to-server certificate: eckey.pem contains the private key.

    Still in Terminal, enter the following to display the new certificate’s public key:

    openssl ec -in eckey.pem -pubout

    In the CloudKit Dashboard, navigate to API Access\Server-to-Server Keys and click Add Server-to-Server Key.

    dashboard08

    Name the key Server2ServerKey.

    Copy the public key from Terminal’s output, paste it into Public Key and tap Save. Then, copy the generated Key ID.

    dashboard09

    Open config.js in Xcode, and replace my containerIdentifier and keyID with your own:

    module.exports = {
      // Replace this with a container that you own.
      containerIdentifier:'iCloud.com.raywenderlich.TIL',
     
      environment: 'development',
     
      serverToServerKeyAuth: {
        // Replace this with the Key ID you generated in CloudKit Dashboard.
        keyID: '1f404a6fbb1caf8cc0f5b9c017ba0e866726e564ea43e3aa31e75d3c9e784e91',
     
        // This should reference the private key file that you used to generate the above key ID.
        privateKeyFile: __dirname + '/eckey.pem'
      }
    };

    To run index.js from a command line, you’ll need to complete a few more steps.

    First, go to nodejs.org and install Node.js on your computer if you don’t have it. Next, follow the advice at the end of the setup and add /usr/local/bin to your $PATH, if it’s not there already.

    Back in Terminal and still in the TIL Starter/Server directory, run these commands:

    npm install
    npm run-script install-cloudkit-js

    These commands install the npm module and the CloudKit JS library, which index.js uses.

    Now, enter this command in Terminal to run index.js:

    node index.js

    The output of this command looks similar to the following:

    CloudKitJS Container#fetchUserInfo
    --> userInfo:
    a {
      userRecordName: '_a4050ea090b8caace16452a2c2c455f4',
      emailAddress: undefined,
      firstName: undefined,
      lastName: undefined,
      isDiscoverable: false }
     
    CloudKitJS CloudKit Database#performQuery { recordType: 'Acronym', sortBy: [ { fieldName: 'short' } ] } {}
    --> FOMO: Fear Of Missing Out
    Created Sun Jun 19 2016 20:16:32 GMT+1000 (AEST)
        ...
    --> YOLO: You Only Live Once
    Created Fri Jun 17 2016 14:37:04 GMT+1000 (AEST)
     
    Done

    In here you’ve adapted config.js and the index.js from Apple’s CloudKit Catalog source code to query the TIL public database and print the short, long and created fields.

    Where to Go From Here?

    Here’s the final version of the web app.

    You covered quite a bit in this CloudKit JS tutorial and know the basics of how to use CloudKit JS to make your iOS CloudKit app available to a wider audience via a web interface.

    1. Using CloudKit JS to access CloudKit Web Services
    2. Viewing JavaScript log messages in the browser’s console
    3. Querying the public database to make it visible to everyone
    4. Authenticating users through iCloud
    5. Building the web UI to facilitate new entries
    6. Handling notifications of changes to keep everything in sync
    7. Supporting server-to-server requests for CloudKit databases

    Watch CloudKit JS and Web Services from WWDC 2015, and take some of the features in CloudKit Catalog for a test drive. Explore additional features like user discoverability, record zones and syncToken.

    Watch What’s New with CloudKit from WWDC 2016 for an in-depth look at record sharing and the new record sharing UI — you can try this out in CloudKit Catalog, too. Apple keeps refining CloudKit to make it easier for developers to create reliable apps: look at CKOperation‘s QualityOfService to handle long-running operations and CKDatabaseSubscription and CKFetchDatabaseChanges to get changes to record zones that didn’t even exist when your app started!

    I hope you enjoyed this tutorial — I sure had fun putting it together! Please join the discussion below to share your observations, feedback, ask questions or share your “ah-ha” moments!

    The post CloudKit JS Tutorial for iOS appeared first on Ray Wenderlich.

    videos.raywenderlich.com Giveaway – and Last Day For Discount!

    $
    0
    0

    Videos-feature

    Last week, we launched a major overhaul to our videos platform at raywenderlich.com: videos.raywenderlich.com.

    The new site includes a brand new visual design, along with a ton of new features subscribers have been asking for.

    To celebrate the launch, we had a huge giveaway, where the grand prize winner gets a 1-year raywenderlich.com all-access pass of over $1,000 in value.

    Keep reading to find out who the lucky winners are – and how to get the launch discount before it’s too late!

    Second Prize Winners

    To enter the giveaway, all you had to do was reply to the announcement post with the answer to one simple question:

    What do you like about the video tutorials at raywenderlich.com?

    The team and I were amazed and overwhelmed by the response. Over 150 people left comments, and your kind words have meant so much to myself and the rest of the team – we have literally been talking about it all week. You folks are amazing!

    We’ve randomly selected 10 second prize winners, who each win a free PDF book of their choice from this site. Below is each winner, and their (abbreviated) quote:

    10) steffanestorov

    “I like the video tutorials because they are short and focused and cover the topic deeply.” —steffanestorov

    9) jlchapman

    “What can you say? To the point, good presentation and some challenges!” —jlchapman

    8) uwalum

    “The depth of each topic is fantastic and the rate at which new content is added is quite impressive. This subscription is pure gold!” —uwalum

    7) kwalkerk

    “Many things: 1) Availability, 2) Clarity, 3) Attitude(not snobby), 4) Topics, 5) Thoroughness, etc. I can’t tell you how many people I’ve referred to the site.” —kwalkerk

    6) hwilms

    “Besides the huge improvement with regards to organizing and searching for tutorials I love the features to track progress and continue a video where I left off. Great work!” —hwilms

    5) rntec

    “I like very much to see the love of the developers in connection with programming. You can feel the emotions and that’s very helpful and motivative.” —mtec

    4) chavarria

    “What I like the most are the high quality of the video tutorials. . .and of-course the practical and real examples which you can apply directly at the job.” —chavarria

    3) jsd

    “I love the tutorials – they are always top quality, easy to follow and provide great detail. . . .Anytime I need to learn a new topic in iOS development, I search here first!” —jsd

    2) jcfmunoz.gabhel

    “Because you have with all this videos the exact answer to your questions and the best guidelines… There’s no price for this content.” —jcfmunoz.gabhel

    1) cretech

    “I have watched a lot (and I mean a lot) of Swift and iOS videos and I can tell you that nothing compares to these. I am a second year subscriber and plan to continue.” —cretech

    Congratulations to all of the lucky winners, and thanks so much for supporting all we do on this site! We are so happy to hear you have been enjoying the videos and we will definitely keep them coming.

    All second prize winners receive a free PDF book of your choice from this site – my coworker Christine will be in touch with further details.

    Grand Prize Winner

    But that’s not all… we have one lucky grand prize winner too!

    Betamax-giveaway-1

    The lucky grand prize winner gets a 1-year raywenderlich.com all-access pass. This includes:

    • A free 1-year subscription to raywenderlich.com ($179.88 value)
    • A free copy of all books currently for sale on raywenderlich.com ($494.91)
    • A free copy of three secret books that are in progress, once they are released ($164.97 value)
    • A free copy of the RWDevCon 2016 Vault ($199.99 value)

    This represents over $1,000 in value – w00t!

    We’ve randomly selected a grand prize winner, and the result is… drum roll please…

    1) nkvintage

    “raywenderlich.com videos are always well done. Yes, you can learn a lot from a youtube video but you can learn so much more from a video that was planned out, rehearsed, and filmed by someone who knows what they are talking about.” —nkvintage

    Congratulations! Christine will be in touch soon to deliver your prizes.

    Where To Go From Here?

    If you haven’t checked out the new design for videos.raywenderlich.com, please check it out and let me know what you think!

    And remember – today is your last chance for the special 50% off your first month launch promotion we are currently running to celebrate – so grab it while you still can!

    To get the 50% off your first month discount: Simply sign up now for a monthly subscription and enter the following coupon code at checkout: RW1MV (expires today!)

    Thanks again for all of your kind words about our new videos platform, and our video tutorials in general. Stay tuned for much more in the year to come! :]

    The post videos.raywenderlich.com Giveaway – and Last Day For Discount! appeared first on Ray Wenderlich.

    iOS 10 Screencast: Custom Units

    Android GridView Tutorial

    $
    0
    0

    Android GridView

    These days, people are always being told to relax, go off-grid and put their smartphones down. But where’s the fun in that? I’m here to encourage you not to get off the grid. Instead, get onto our grid—our Android GridView tutorial, that is!

    Today you’ll learn how to tame this widely-used Android component and construct your own Bookcase application containing various books for babies.

    If you’re familiar with Android’s ListView component, you should feel right at home here. We also have a great tutorial on ListViews if you’d like to familiarize yourself with them first (although you don’t need to for this tutorial).

    GridView follows the same formula to render each cell. Basically, you:

    1. Create a BaseAdapter subclass.
    2. Set an instance of this class as your data provider to the GridView.
    3. Return each cell’s view from getView() on your adapter.

    Android’s GridView is a useful component for constructing easy-to-browse lists. And since grids are everywhere these days (notably in the Instagram app) it’s a necessary skill. After completing this tutorial, you’ll be ready to conquer the world with your own amazing grid views!

    Getting Started

    Download the starter project here. Included are the image assets for each book and a list of Book objects describing the contents of our Baby Bookcase. Open the project by starting Android Studio and selecting Open an existing Android Studio project:

    open_project

    Navigate to the directory where you unzipped the sample project and hit OK:

    open_project_in_studio_browser

    Build and run the project on your preferred emulator or Android device—you should see the most amazing blank screen ever:
    blank_screen

    You are now ready to start integrating your GridView.

    Navigate to app\res\layout\activity_main.xml and insert the following block of XML between the RelativeLayout tags (make sure to view the file as “Text” by clicking the tab near the bottom):

    <GridView
        android:id="@+id/gridview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:columnWidth="100dp"
        android:numColumns="auto_fit"
        android:verticalSpacing="24dp"
        android:horizontalSpacing="10dp"
        android:stretchMode="spacingWidthUniform"
        />

    Your editor should now show a preview of your GridView:

    gridview_xml_preview

    The snippet above specifies a GridView with some customized properties. We’ll discuss property customization in more detail later on.

    Setting The Data Provider

    Empty grids are hungry for data to display. To feed this one, you’ll set up a class called BooksAdapter, an adapter which is a subclass of the BaseAdapter class, as your data provider for the GridView. In the project navigator pane, right-click on com.raywenderlich.babybookcase, and select New/Java Class. After that, type in BooksAdapter for Name, keep Class for Kind, and hit OK.

    create_booksadapter_class

    The adapter acts as the middleman between the GridView and the data source. It loads the information to be displayed in your grid view from a data source, such as an array or database query, then creates a view for each item. If you’re interested, the ListView tutorial has more information on adapters.

    Replace the contents of this file with the following:

    package com.raywenderlich.babybookcase;
     
    import android.content.Context;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    import android.widget.TextView;
     
    public class BooksAdapter extends BaseAdapter {
     
      private final Context mContext;
      private final Book[] books;
     
      // 1
      public BooksAdapter(Context context, Book[] books) {
        this.mContext = context;
        this.books = books;
      }
     
      // 2
      @Override
      public int getCount() {
        return books.length;
      }
     
      // 3
      @Override
      public long getItemId(int position) {
        return 0;
      }
     
      // 4
      @Override
      public Object getItem(int position) {
        return null;
      }
     
      // 5
      @Override
      public View getView(int position, View convertView, ViewGroup parent) {
        TextView dummyTextView = new TextView(mContext);
        dummyTextView.setText(String.valueOf(position));
        return dummyTextView;
      }
     
    }

    Here’s the play-by-play of each step in the above code:

    1. You use this constructor to instantiate a BooksAdapter.
    2. You return the number of cells to render here.
    3. You don’t need to return an id for this tutorial, so just return 0. Android still requires you to provide an implementation for this method.
    4. See #3, but instead return null.
    5. You return a dummy TextView as the cell view for your GridView.

    Now that you have a basic adapter implementation, you can use this class as the data provider for the GridView in MainActivity. Within onCreate() in MainActivity.java, underneath

    setContentView(R.layout.activity_main);

    insert the following:

    GridView gridView = (GridView)findViewById(R.id.gridview);
    BooksAdapter booksAdapter = new BooksAdapter(this, books);
    gridView.setAdapter(booksAdapter);

    Build and run. You should see something like this:

    basic_adapter_impl_preview

    Great—we’re getting somewhere!

    To provide the proper view for the cells that represent each Book object, create a new XML layout file by right-clicking on the layout directory and selecting New/Layout resource file:

    new_book_layout_xml

    Use linearlayout_book as the file name and hit OK:

    create_linearlayoutbook_prompt

    Replace the file contents with the following:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  xmlns:tools="http://schemas.android.com/tools"
                  android:orientation="vertical" android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  android:gravity="center"
        >
     
        <FrameLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
     
            <ImageView
                android:id="@+id/imageview_cover_art"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:scaleType="centerCrop"/>
     
            <ImageView
                android:id="@+id/imageview_favorite"
                android:layout_width="24dp"
                android:layout_height="24dp"
                android:src="@drawable/star_disabled"
                android:layout_gravity="bottom|right"/>
     
        </FrameLayout>
     
        <TextView
            android:id="@+id/textview_book_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="12sp"
            tools:text="Are You My Mother"
            android:textStyle="bold"
            android:paddingTop="4dp"
            android:paddingLeft="8dp"
            android:paddingRight="8dp"
            android:gravity="center_horizontal"/>
     
        <TextView
            android:id="@+id/textview_book_author"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="12sp"
            tools:text="Dr. Seuss"
            android:gravity="center_horizontal"/>
     
    </LinearLayout>

    This new layout file will be used to represent your Book objects inside the grid. Each book will be drawn inside a cell that contains four items:

    1. An ImageView for the cover art.
    2. Another ImageView for a “favorited” star icon.
    3. A TextView for the book name.
    4. Another TextView for the book’s author.

    Here’s a sample of what a book cell will look like:

    cell_book_preview

    Now that your layout is established, you can return a more complex view for your cells. Open BooksAdapter.java again and finish the implementation of getView() by replacing it with the following:

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
      // 1
      final Book book = books[position];
     
      // 2
      if (convertView == null) {
        final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
        convertView = layoutInflater.inflate(R.layout.linearlayout_book, null);
      }
     
      // 3
      final ImageView imageView = (ImageView)convertView.findViewById(R.id.imageview_cover_art);
      final TextView nameTextView = (TextView)convertView.findViewById(R.id.textview_book_name);
      final TextView authorTextView = (TextView)convertView.findViewById(R.id.textview_book_author);
      final ImageView imageViewFavorite = (ImageView)convertView.findViewById(R.id.imageview_favorite);
     
      // 4
      imageView.setImageResource(book.getImageResource());
      nameTextView.setText(mContext.getString(book.getName()));
      authorTextView.setText(mContext.getString(book.getAuthor()));
     
      return convertView;
    }

    Here’s an explanation of each step:

    1. You find the proper book for this cell by using the position index.
    2. GridView optimizes memory usage by recycling the cells. This means that if convertView is null, you instantiate a new cell view by using a LayoutInflater and inflating your linearlayout_book layout.
    3. You create references for each individual view you created in your XML layout file.
    4. You set the book’s cover art, name and author using the above references.

    Build and run the application again. You should see the following:

    gridview_with_books_preview

    Selecting Items

    Now you’ve got a pretty grid of books. Hooray! But what if your user wants to favorite a book by tapping on it? To allow this, set up an on-click listener for your GridView. Open MainActivity.java and add the following snippet at the bottom of onCreate():

    gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
      @Override
      public void onItemClick(AdapterView parent, View view, int position, long id) {
        Book book = books[position];
        book.toggleFavorite();
     
        // This tells the GridView to redraw itself
     	// in turn calling your BooksAdapter's getView method again for each cell
        booksAdapter.notifyDataSetChanged();
      }
    });

    A variable must be declared as final to be used inside an anonymous nested class (like our on-click listener), so to change the booksAdapter variable’s declaration to final, replace this line in onCreate():

    BooksAdapter booksAdapter = new BooksAdapter(this, books);

    with:

    final BooksAdapter booksAdapter = new BooksAdapter(this, books);

    To toggle the star icon in your cell, add this line of code in getView in BooksAdapter, right before you return the convertView:

    imageViewFavorite.setImageResource(
      book.getIsFavorite() ? R.drawable.star_enabled : R.drawable.star_disabled);

    Build and run. You can now tap on each book to favorite your selections:

    favorited_books

    Screen Orientation Changes

    You’ve happily selected some favorite books … but when you rotate the screen (CTRL + F11 for emulator rotation), the selections aren’t remembered. What!?

    Screen Shot 2016-06-21 at 2.43.54 PM

    This is because Android Activities are destroyed and then recreated when the screen rotates. By default, the system uses the Bundle instance state to save information about each View object in your activity layout (such as the text displayed in the TextViews of your GridView). When your activity instance is destroyed and recreated, the state of the layout is restored to its previous state with no code required by you.

    This means that to make the selections behave correctly, you need to save the selection information yourself. Thankfully, Android Activities have two useful methods for this:

    • onSaveInstanceState(): Android will call this method right before the activity is destroyed.
    • onRestoreInstanceState(): Android will call this method when recreating the activity.

    To remember the selected books, the app needs to save the selection information to a list, then use that list to select the books when the activity is recreated.

    First, establish an identifying key for the list at the beginning of your class by adding the following line before onCreate() in MainActivity.java:

    private static final String favoritedBookNamesKey = "favoritedBookNamesKey";

    Add the following to MainActivity.java under onCreate():

    @Override
    protected void onSaveInstanceState(Bundle outState) {
      super.onSaveInstanceState(outState);
     
      // construct a list of books you've favorited
      final ArrayList<Integer> favoritedBookNames = new ArrayList<>();
      for (Book book : books) {
        if (book.getIsFavorite()) {
          favoritedBookNames.add(book.getName());
        }
      }
     
      // save that list to outState for later
      outState.putIntegerArrayList(favoritedBookNamesKey, favoritedBookNames);
    }

    To restore the selections when the activity is recreated, add the following to MainActivity.java under onSaveInstanceState():

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
      super.onRestoreInstanceState(savedInstanceState);
     
      // get our previously saved list of favorited books
      final ArrayList<Integer> favoritedBookNames =
                savedInstanceState.getIntegerArrayList(favoritedBookNamesKey);
     
      // look at all of your books and figure out which are the favorites
      for (int bookName : favoritedBookNames) {
        for (Book book : books) {
          if (book.getName() == bookName) {
            book.setIsFavorite(true);
            break;
          }
        }
      }
    }

    Build and run. Now when you rotate the screen, your books are still favorited!

    rotated_view

    Customizing GridView Properties

    As you play around with the GridView component, you may run into situations where the layout doesn’t suit your design perfectly. Luckily, the great folks at Google have provided a few properties that allow you to tweak how each cell is rendered.

    You can modify columnWidth, horizontalSpacing and verticalSpacing with a dimension value such as 14.5dp. These properties can be set programmatically or from the XML layout files.

    To find properties to set, type gridView.set at the bottom of onCreate() in MainActivity.java and wait for Android Studio to show suggestions.

    Alternatively, take a look at the GridView documentation for a list of available methods, some of which set these properties. You can also head back to app/res/layout/activity_layout.xml and play around with the properties within the GridView tag. The properties are fairly self-explanatory, so I definitely encourage you to experiment with different values.

    To specify the number of columns to render, provide an integer value for the property numColumns. If you want to display as many columns as possible to fill the available horizontal space, use numColumns="auto_fit". Here’s a comparison between the two options in landscape orientation (I’ve used darker grey cell backgrounds for clarity purposes):

    numColumns_property

    Finally, to control how your columns stretch to fill available space, specify stretchMode as one of the following:

    • none: Stretching is disabled.
    • spacingWidth: Spacing between each column is stretched.
    • columnWidth: Each column is stretched equally.
    • spacingWidthUniform: Spacing between each column is uniformly stretched.

    The following screenshot illustrates those options:

    gridview_stretchmode

    Using the customizable properties, you can easily get your GridView looking just the way you want it!

    Performance Tips

    Your first few implementations of GridView will likely be simple in terms of view layouts, but as your app scales and you get more content, the stress on your users’ devices can become quite high in terms of loading cells and maintaining smooth scrolling.

    The current implementation of this sample app recycles each cell view as needed within BooksAdapter.getView(), so make sure to use this strategy whenever you need to provide views for your cells.

    One technique to improve performance is called the ViewHolder design pattern.  As the name suggests, you implement a class to “hold” the subviews inside of your cells. This avoids memory-expensive calls to findViewById()

    To see what this pattern looks like, add this private class inside BooksAdapter, directly below getView(). Remember to paste inside the BooksAdapter class brackets!

      // Your "view holder" that holds references to each subview
      private class ViewHolder {
        private final TextView nameTextView;
        private final TextView authorTextView;
        private final ImageView imageViewCoverArt;
        private final ImageView imageViewFavorite;
     
        public ViewHolder(TextView nameTextView, TextView authorTextView, ImageView imageViewCoverArt, ImageView imageViewFavorite) {
          this.nameTextView = nameTextView;
          this.authorTextView = authorTextView;
          this.imageViewCoverArt = imageViewCoverArt;
          this.imageViewFavorite = imageViewFavorite;
        }
      }

    Your ViewHolder is quite simple. It holds references to each subview and doesn’t bother with anything else.

    To take advantage of your ViewHolder, change getView() to the following:

    @Override
      public View getView(int position, View convertView, ViewGroup parent) {
        final Book book = books[position];
     
        // view holder pattern
        if (convertView == null) {
          final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
          convertView = layoutInflater.inflate(R.layout.linearlayout_book, null);
     
          final ImageView imageViewCoverArt = (ImageView)convertView.findViewById(R.id.imageview_cover_art);
          final TextView nameTextView = (TextView)convertView.findViewById(R.id.textview_book_name);
          final TextView authorTextView = (TextView)convertView.findViewById(R.id.textview_book_author);
          final ImageView imageViewFavorite = (ImageView)convertView.findViewById(R.id.imageview_favorite);
     
          final ViewHolder viewHolder = new ViewHolder(nameTextView, authorTextView, imageViewCoverArt, imageViewFavorite);
          convertView.setTag(viewHolder);
        }
     
        final ViewHolder viewHolder = (ViewHolder)convertView.getTag();
        viewHolder.imageViewCoverArt.setImageResource(book.getImageResource());
        viewHolder.nameTextView.setText(mContext.getString(book.getName()));
        viewHolder.authorTextView.setText(mContext.getString(book.getAuthor()));
        viewHolder.imageViewFavorite.setImageResource(book.getIsFavorite() ? R.drawable.star_enabled : R.drawable.star_disabled);
     
        return convertView;
      }

    The ViewHolder is stuffed into convertView‘s tag using setTag() and retrieved using getTag(). With your cells scrolling by, it helps them load quick quickly when they can skip over all the inflation, right to the getTag() call and the fun part of inserting content.

    Build and run. Your app will look the same, but underneath the hood it is now capable of handling much faster view recycling.

    For additional documentation, visit Google’s page on smooth scrolling here.

    Remote Image Loading

    What if your application requires loading external images inside each individual cell? This task generally requires subclassing AsyncTask and firing off an image download task for each cell as the user scrolls down the list and back up.

    Having implemented a custom solution for this in the past, I can tell you that it gets complicated. For example, you’d need to cache images in memory as each download is successfully completed, while making sure you’re not firing off multiple download tasks for the same image file download.

    Fortunately, there is a fantastic library available from Square called Picasso that solves many of the common issues with list views and image downloads. To install the library, open up build.grade (Module: app) in your project and add the following line of code inside dependencies:

    dependencies {
      ...
      compile 'com.squareup.picasso:picasso:2.5.2'
    }

    Your build file should look like this:

    Picasso Gradle Installation

    Next, click the Sync Now link to install Picasso and update your project:

    sync_gradle

    After successfully syncing your project, you can let Picasso do all the heavy lifting of downloading your images. To do this, comment out the line in BooksAdapter.getView() where the cover art is set and include Picasso like this:

    // make sure to comment out this image setter
    //viewHolder.imageViewCoverArt.setImageResource(book.getImageResource());
     
    Picasso.with(mContext).load(book.getImageUrl()).into(viewHolder.imageViewCoverArt);

    Build and run, then scroll through the GridView to test the external image loading. Note that the images are still the same for each book, but they are coming from a remote URL now.

    Where to Go From Here

    Congratulations! You’ve conquered the powerful GridView component, created a library for your favorite kids’ books and learned how to do the following:

    • Add a GridView to your layouts.
    • Create an adapter to provide your GridView with the proper cell views.
    • React to item selections.
    • Persist selections for orientation changes.
    • Customize the GridView.
    • Optimize performance.

    You can download the completed project here. If you’re curious about what else you can do with GridViews, check out Google’s documentation.

    I hope you’ve enjoyed this introduction to Android’s GridView. If you have any questions, comments or feedback please join the forum discussion below.

    The post Android GridView Tutorial appeared first on Ray Wenderlich.

    A Secret Book Coming Next Monday!

    $
    0
    0

    Over the past few months, we’ve been working hard on a secret book project.

    Next Monday we’re going to reveal what it is. But first, you get a chance to guess!

    Surprise

    What’s your best guess? Simply comment on this post and answer the following question:

    What do you think this secret book is about?

    To make it fun, we’ll give away a free copy of the book to two lucky winners:

    • We’ll choose one random person who guesses correctly
    • We’ll choose one random person with the most creative or funny answer as well!

    That way, even if you’re not sure what the secret book will be, you can still make a creative stab at it in the comments.

    Good luck to everyone — and don’t forget to check back here Monday to find out what the new book is!

    The post A Secret Book Coming Next Monday! appeared first on Ray Wenderlich.


    Screencast: Beginning C# Part 9: Ternary Operator

    Swift Algorithm Club: Swift Binary Search Tree Data Structure

    $
    0
    0

    SwiftAlgClub-BinarySearch-feature

    The Swift Algorithm Club is an open source project on implementing data structures and algorithms in Swift.

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

    In this tutorial, you’ll learn how about binary trees and binary search trees. The binary tree implementation was first implemented by Matthijs Hollemans, and the binary search tree was first implemented by Nico Ameghino.

    Note: New to the Swift Algorithm Club? Check out our getting started post first.

    Getting Started

    The Binary Tree is one of the most prevalent data structures in computer science. More advanced trees like the Red Black Tree and the AVL Tree evolved from the binary tree.

    Binary trees themselves evolved from the general purpose tree. If you don’t know what that is, check out last month’s tutorial on Swift Tree Data Structure.

    Let’s see how this works.

    Binary Tree Data Structure

    A binary tree is a tree where each node has 0, 1, or 2 children. The important bit is that 2 is the max – that’s why it’s binary.

    Here’s what it looks like:

    BinaryTree

    Terminology

    Before we dive into the code, it’s important that you understand some important terminology first.

    On top of all the terms related to a general purpose tree, a binary tree adds the notion of left and right children.

    Left Child

    The left child descends from the left side:

    BinaryTree-2

    Right Child

    Surprisingly, the right side is the right child:

    BinaryTree-2

    Leaf Node

    If a node doesn’t have any children, it’s called a leaf node:

    BinaryTree-2

    Root

    The root is the node at the top of the tree (programmers like their trees upside down):

    BinaryTree-2

    Binary Tree Implementation in Swift

    Like other trees, a binary tree composed of nodes. One way to represent a node is using a class (don’t enter this into a Playground yet, this is just an example):

    class Node<T> {
      var value: T
      var leftChild: Node?
      var rightChild: Node?
     
      init(value: T) {
        self.value = value
      }
    }

    In a binary tree, every node holds some data (value), and has a left and right child (leftChild and rightChild). In this implementation, the leftChild and rightChild are optionals, meaning they can be nil.

    That’s the traditional way to build trees. However, the thrill seeker you are shall rejoice today, because you’ll try something new! :]

    Value Semantics

    One of the core ideas of Swift is using value types (like struct and enum) instead of reference types (like class) where appropriate. Well, creating a binary tree is a perfect case to use a value type – so in this tutorial, you’ll you’ll implement the binary tree as an enum type.

    Note: To learn more about reference types vs. value types in Swift, check out our Reference vs. Value Types in Swift series.

    Create a new Swift playground (this tutorial uses Xcode 8 beta 5) and add the following enum declaration:

    enum BinaryTree<T> {
     
    }

    You’ve declared a enum named BinaryTree. The syntax declares this to be a generic enum that allows it to infer it’s own type information at the call site.

    States

    Enumerations are rigid, in that they can only be in one state or another. Fortunately, this fits into the idea of binary trees quite elegantly. A binary tree is a finite set of nodes that is either empty, or consists of the value at the node and references to it’s left and right children.

    Update your enum accordingly:

    enum BinaryTree<T> {
      case empty
      case node(BinaryTree, T, BinaryTree)
    }

    If you’re coming from another programming language, the node case may seem a bit foreign. Swift enums allow for associated values, which is a fancy term for saying you can attach stored properties with a case.

    In node(BinaryTree, T, BinaryTree), the parameter types inside the brackets correspond to the left child, value, and the right child, respectively.

    That’s a fairly compact way of modelling a binary tree. However, you’re immediately greeted with a compiler error:

    Recursive enum 'BinaryTree<T>' is not marked 'indirect'

    Xcode should make an offer to fix this for you. Accept it, and your enum should now look like this:

    indirect enum BinaryTree<T> {
      case empty
      case node(BinaryTree, T, BinaryTree)
    }

    Indirection

    Enumerations in Swift are value types. When Swift tries to allocate memory for value types, it needs to know exactly how much memory it needs to allocate.

    The enumeration you’ve defined is a recursive enum. That’s an enum that has an associated value that refers to itself. Recursive value types have a indeterminable size.

    Screen Shot 2016-08-01 at 1.27.40 AM

    So you’ve got a problem here. Swift expects to know exactly how big the enum is, but the recursive enum you’ve created doesn’t expose that information.

    Here’s where the indirect keyword comes in. indirect applies a layer of indirection between two value types. This introduces a thin layer of reference semantics to the value type.

    The enum now holds references to it’s associated values, rather than their value. References have a constant size, so you no longer have the previous problem.

    While the code now compiles, you can be a little bit more concise. Update BinaryTree to the following:

    enum BinaryTree<T> {
      case empty
      indirect case node(BinaryTree, T, BinaryTree)
    }

    Since only the node case is recursive, you only need to apply indirect to that case.

    Example: Sequence of Arithmetical Operations

    An interesting exercise to check out is to model a series of calculations using a binary tree. Take this for an example for modelling (5 * (a - 10)) + (-4 * (3 / b)):

    Operations

    Write the following at the end of your playground file:

    // leaf nodes
    let node5 = BinaryTree.node(.empty, "5", .empty)
    let nodeA = BinaryTree.node(.empty, "a", .empty)
    let node10 = BinaryTree.node(.empty, "10", .empty)
    let node4 = BinaryTree.node(.empty, "4", .empty)
    let node3 = BinaryTree.node(.empty, "3", .empty)
    let nodeB = BinaryTree.node(.empty, "b", .empty)
     
    // intermediate nodes on the left
    let Aminus10 = BinaryTree.node(nodeA, "-", node10)
    let timesLeft = BinaryTree.node(node5, "*", Aminus10)
     
    // intermediate nodes on the right
    let minus4 = BinaryTree.node(.empty, "-", node4)
    let divide3andB = BinaryTree.node(node3, "/", nodeB)
    let timesRight = BinaryTree.node(minus4, "*", divide3andB)
     
    // root node
    let tree = BinaryTree.node(timesLeft, "+", timesRight)

    You need to build up the tree in reverse, starting with the leaf nodes and working your way up to the top.

    CustomStringConvertible

    Verifying a tree structure can be hard without any console logging. Swift has a handy protocol named CustomStringConvertible, which allows you define a custom output for print statements. Add the following code just below your BinaryTree enum:

    extension BinaryTree: CustomStringConvertible {
      var description: String {
        switch self {
        case let .node(left, value, right):
          return "value: \(value), left = [" + left.description + "], right = [" + right.description + "]"
        case .empty:
          return ""
        }
      }
    }

    Print the tree by writing the following at the end of the file:

    print(tree)

    You should see something like this:

    value: +, left = [value: *, left = [value: 5, left = [], right = []], right = [value: -, left = [value: a, left = [], right = []], right = [value: 10, left = [], right = []]]], right = [value: *, left = [value: -, left = [], right = [value: 4, left = [], right = []]], right = [value: /, left = [value: 3, left = [], right = []], right = [value: b, left = [], right = []]]]

    With a bit of imagination, you can see the tree structure. ;-) It helps if you indent it:

    value: +,
        left = [value: *,
            left = [value: 5, left = [], right = []],
            right = [value: -,
                left = [value: a, left = [], right = []],
                right = [value: 10, left = [], right = []]]],
        right = [value: *,
            left = [value: -,
                left = [],
                right = [value: 4, left = [], right = []]],
            right = [value: /,
                left = [value: 3, left = [], right = []],
                right = [value: b, left = [], right = []]]]

    Getting The Count

    Another useful feature is being able to get the number of nodes in the tree. Add the following just inside your BinaryTree enumeration:

    var count: Int {
      switch self {
      case let .node(left, _, right):
        return left.count + 1 + right.count
      case .empty:
        return 0
      }
    }

    Test it out by adding this to the end of your playground:

    tree.count

    You should see the number 12 in the sidebar, since there are 12 nodes in the tree.

    Great job making it this far. Now that you’ve got a good foundation for binary trees, it’s time to get acquainted with the most popular tree by far – the Binary Search Tree!

    Binary Search Trees

    A binary search tree is a special kind of binary tree (a tree in which each node has at most two children) that performs insertions and deletions such that the tree is always sorted.

    “Always Sorted” Property

    Here is an example of a valid binary search tree:

    Tree1

    Notice how each left child is smaller than its parent node, and each right child is greater than its parent node. This is the key feature of a binary search tree.

    For example, 2 is smaller than 7 so it goes on the left; 5 is greater than 2 so it goes on the right.

    Insertion

    When performing an insertion, starting with the root node as the current node:

    • If the current node is empty, you insert the new node here.
    • If the new value is smaller, you go down the left branch.
    • If the new value is greater, you go down the right branch.

    You traverse your way down the tree until you find an empty spot where you can insert the new value.

    For example, imagine you want to insert the value 9 to the above tree:

    1. Start at the root of the tree (the node with the value 7), and compare it to the new value 9.
    2. 9 > 7, so you go down the right branch
    3. Compare 9 with 10. Since 9 < 10, go down the left branch.
    4. This left branch is empty, thus you’ll insert a new node for 9 at this location.

    The new tree now looks like this:

    Tree2

    Here’s another example. Imagine you want to insert 3 to the above tree:

    1. Start at the root of the tree (the node with the value 7), and compare it to the new value 3.
    2. 3 < 7, so you go down the left branch
    3. Compare 3 with 2. Since 3 > 2, go down the right branch.
    4. Compare 3 with 5. Since 3 < 5, go down the left branch.
    5. The left branch is empty, thus you’ll insert a new node for 3 at this location.

    The new tree now looks like this:

    added

    There is always only one possible place where the new element can be inserted in the tree. Finding this place is usually pretty quick. It takes O(h) time, where h is the height of the tree.

    Note: If you’re not familiar with the height of a tree, check out the previous article on Swift Trees.

    Challenge: Implementing Insertion

    Now that you’ve got an idea of how insertion works, it’s implementation time. Add the following method to your BinaryTree enum:

    // 1. 
    mutating func naiveInsert(newValue: T) {
      // 2.
      guard case .node(var left, let value, var right) = self else {
        // 3. 
        self = .node(.empty, newValue, .empty)
        return
      }
     
      // 4. TODO: Implement rest of algorithm!
     
    }

    Let’s go over this section by section:

    1. Value types are immutable by default. If you create a method that tries to mutate something within the value type, you’ll need to explicitly specify that by prepending the mutating keyword in front of your method.
    2. You’re using the guard statement to expose the left child, current value, and right child of the current node. If this node is empty, then guard will fail into it’s else block.
    3. In this block, self is empty. You’ll insert the new value here.
    4. This is where you come in – hang tight for a second.

    In a moment, you will try to implement section 4 based on the algorithm discussed above. This is a great exercise not only for understanding binary search trees, but also honing your recursion skills.

    But before you do, you need to make a change to the BinaryTree signature. In section 4, you’ll need to compare whether the new value with the old value, but you can’t do this with the current implementation of the binary tree. To fix this, update the BinaryTree enum to the following:

    enum BinaryTree<T: Comparable> {
      // stuff inside unchanged
    }

    The Comparable protocol enforces a guarantee that the type you’re using to build the binary tree can be compared using the comparison operators, such as the < operator.

    Now, go ahead and try to implement section #4 based on the algorithm above. Here it is again for your reference:

    • If the current node is empty, you insert the new node here. Done!
    • If the new value is smaller, you go down the left branch. You need to do this.
    • If the new value is greater, you go down the right branch. You need to do this.

    If you get stuck, you can check the solution below.

    Solution Inside: Solution SelectShow>

    Copy on Write

    Though this is a great implementation, it won't work. Test this by writing the following at the end of your playground:

    var binaryTree: BinaryTree<Int> = .empty
    binaryTree.naiveInsert(newValue: 5) // binaryTree now has a node value with 5
    binaryTree.naiveInsert(newValue: 7) // binaryTree is unchanged
    binaryTree.naiveInsert(newValue: 9) // binaryTree is unchanged

    Screen Shot 2016-08-10 at 8.55.46 PM

    Copy-on-write is the culprit here. Every time you try to mutate the tree, a new copy of the child is created. This new copy is not linked with your old copy, so your initial binary tree will never be updated with the new value.

    This calls for a different way to do things. Write the following at the end of the BinaryTree enum:

    private func newTreeWithInsertedValue(newValue: T) -> BinaryTree {
      switch self {
      // 1
      case .empty:
        return .node(.empty, newValue, .empty)
      // 2 
      case let .node(left, value, right):
        if newValue < value {
          return .node(left.newTreeWithInsertedValue(newValue: newValue), value, right)
        } else {
          return .node(left, value, right.newTreeWithInsertedValue(newValue: newValue))
        }
      }
    }

    This is a method that returns a new tree with the inserted element. The code is relatively straightforward:

    1. If the tree is empty, you want to insert the new value here.
    2. If the tree isn't empty, you'll need to decide whether to insert into the left or right child.

    Write the following method inside your BinaryTree enum:

    mutating func insert(newValue: T) {
      self = newTreeWithInsertedValue(newValue: newValue)
    }

    Test your code by replacing the test lines at the bottom of your playground:

    binaryTree.insert(newValue: 5)
    binaryTree.insert(newValue: 7)
    binaryTree.insert(newValue: 9)

    You should end up with the following tree structure:

    value: 5,
        left = [],
        right = [value: 7,
            left = [],
            right = [value: 9,
                left = [],
                right = []]]

    Congratulations - now you've got insertion working!

    Insertion Time Complexity

    As discussed in the spoiler section, you need to create a new copy of the tree every time you make an insertion. Creating a new copy requires going through all the nodes of the previous tree. This gives the insertion method a time complexity of O(n).

    Note: Average time complexity for a binary search tree for the traditional implementation using classes is O(log n), which is considerably faster. Using classes (reference semantics) won't have the copy-on-write behaviour, so you'll be able to insert without making a complete copy of the tree.

    Traversal Algorithms

    Traversal algorithms are fundamental to tree related operations. A traversal algorithm goes through all the nodes in a tree. There are three main ways to traverse a binary tree:

    In-order Traversal

    In-order traversal of a binary search tree is to go through the nodes in ascending order. Here's what it looks like to perform an in-order traversal:

    Traversing

    Starting from the top, you head to the left as much as you can. If you can't go left anymore, you'll visit the current node and attempt to traverse to the right side. This procedure continues until you traverse through all the nodes.

    Write the following inside your BinaryTree enum:

    func traverseInOrder(process: @noescape (T) -> ()) {
      switch self {
      // 1
      case .empty:
        return
      // 2
      case let .node(left, value, right):
        left.traverseInOrder(process: process)
        process(value)
        right.traverseInOrder(process: process)
      }
    }

    This code is fairly straightforward:

    1. If the current node is empty, there's no way to go down further. You'll simply return here.
    2. If the current node is non empty, then you can go down further. The definition of in-order traversal is to go down the left side, visit the node, and then the right side.

    To see this in action, you'll create the binary tree shown above. Delete all the test code at the bottom of your playground and replace it with the following:

    var tree: BinaryTree<Int> = .empty
    tree.insert(newValue: 7)
    tree.insert(newValue: 10)
    tree.insert(newValue: 2)
    tree.insert(newValue: 1)
    tree.insert(newValue: 5)
    tree.insert(newValue: 9)
     
    tree.traverseInOrder { print($0) }

    You've created a binary search tree using your insert method. traverseInOrder will go through your nodes in ascending order, passing the value in each node to the trailing closure.

    Inside the trailing closure, you're printing the value that was passed in by the traversal method. $0 is a shorthand syntax that references the parameter that is passed in to the closure.

    You should see the following output in your console:

    1
    2
    5
    7
    9
    10

    Pre-order Traversal

    Pre-order traversal of a binary search tree is to go through the nodes whilst visiting the current node first. The key here is calling process before traversing through the children. Write the following inside your BinaryTree enum:

    func traversePreOrder( process: @noescape (T) -> ()) {
      switch self {
      case .empty:
        return
      case let .node(left, value, right):
        process(value)
        left.traversePreOrder(process: process)
        right.traversePreOrder(process: process)
      }
    }

    Post-order Traversal

    Post-order traversal of a binary search tree is to visit the nodes only after traversing through it's left and right children. Write the following inside your BinaryTree enum:

    func traversePostOrder( process: @noescape (T) -> ()) {
      switch self {
      case .empty:
        return
      case let .node(left, value, right):
        left.traversePostOrder(process: process)
        right.traversePostOrder(process: process)
        process(value)
      }
    }

    These 3 traversal algorithms serve as a basis for many complex programming problems. Understanding them will prove useful for many situations, including your next programming interview!

    Mini Challenge

    What is the time complexity of the traversal algorithms?

    Solution Inside: Solution SelectShow>

    Searching

    As the name suggests, a binary search tree is known best for facilitating efficient searching. A proper binary search tree will have all it's left child less than it's parent node, and all it's right children equal or greater than it's parent node.

    By exploiting this guarantee, you'll be able to determine which route to take - the left child, or the right child - to see if your value exists within the tree. Write the following inside your BinaryTree enum:

    func search(searchValue: T) -> BinaryTree? {
      switch self {
      case .empty:
        return nil
      case let .node(left, value, right):
        // 1
        if searchValue == value {
          return self
        }
     
        // 2
        if searchValue < value {
          return left.search(searchValue: searchValue)
        } else {
          return right.search(searchValue: searchValue)
        }
      }
    }

    Much like the traversal algorithms, searching involves traversing down the binary tree:

    1. If the current value matches the value you're searching for, you're done searching. Return the current subtree
    2. If execution continues to this point, it means you haven't found the value. You'll need to decide whether you want to go down to the left or right. You'll decide using the rules of the binary search tree.

    Unlike the traversal algorithms, the search algorithm will traverse only 1 side at every recursive step. On average, this leads to a time complexity of O(log n), which is considerably faster than the O(n) traversal.

    You can test this by adding the following to the end of your playground:

    tree.search(searchValue: 5)

    Where To Go From Here?

    I hope you enjoyed this tutorial on making a Swift Binary Tree data structure!

    Here is a Swift playground with the above code. You can also find alternative implementations and further discussion in the Binary Search Tree section of the Swift Algorithm Club repository.

    This was just one of the many algorithm clubs focused on 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: Swift Binary Search Tree Data Structure appeared first on Ray Wenderlich.

    iOS 10 Screencast: Creating an Xcode 8 Extension

    Screencast: Creating a CocoaPod

    Introducing Unity Games by Tutorials!

    $
    0
    0

    For the past six months, we’ve been working on a top-secret book project: Unity Games by Tutorials.

    Today, we are happy to announce that the first 8 chapters of the book are available now. These chapters teach you how to make a twin-stick shooter called Bobblehead Wars. See for yourself below:

    Trust me, all the games are as good at this! :]

    To celebrate the early access release, we’ll be posting a few free chapters from the book, announcing the winners from last week’s “secret announcement” post, and giving away some free copies of the book.

    Along with all that, we’re also giving everyone who orders Unity Games by Tutorials now an early access discount.

    Read on for all the details!

    What is Unity?

    Unity is a a professional game engine used to create games like City Skylines, Hearthstone, the Long Dark, and more.

    Unity’s aim is to “democratize” game development, by providing a AAA-level engine to independent game developers in a way that is both affordable and accessible.

    Here are our top 5 reasons why Unity is great:

    1. It’s free to use. If you’re an indie game developer, you can download and start using Unity for free, which is great when you’re just learning.
    2. It’s cross-platform. With Unity, you make your game once and you can build it for a variety of platforms, including Windows, macOS, Linux, iOS, and more.
    3. It has a visual editor. Unlike other game platforms where you have to type tons of code before you see anything on the screen, with Unity you can simply import an asset and drag and drop. This visual style of development is great for beginners and professionals alike, and makes game development fast and fun.
    4. Live debugging. With Unity you can click a button to preview your game instantly in the editor, and you can even modify game objects on the fly. For example, you can drag new enemies onto the level as you play it, tweak gameplay values and more, allowing for an iterative game design process.
    5. Unity is fun! You can think of Unity like a box of legos: the only limits are those of your own imagination.
    Unity vs. Sprite Kit and Scene Kit: You might wonder which you should use: Unity, or one of the Apple game frameworks like Sprite Kit or Scene Kit.

    Here’s our recommendation:

    • If you are an experienced iOS developer making a simple game and want to target iOS devices only, you may want to consider using one of Apple’s game frameworks. They are very easy to learn and leverage much of your existing iOS development experience.
    • If you want to target non-iOS devices, or if you want to make games at a professional level, you may want to consider using Unity. Unity is much more powerful than the Apple game frameworks, and does not lock you into the iOS ecosystem, and that’s well worth the increased learning curve.

    What Is Unity Games by Tutorials?

    Unity Games by Tutorials is for complete beginners to Unity, or for those who’d like to bring their Unity skills to a professional level. Its goal is to teach you everything you need to know to make your own Unity games – via hands-on experience.

    In Unity Games by Tutorials, you’ll learn how to build four games:

    1. A twin-stick shooter
    2. A first-person shooter
    3. A tower defense game (with VR support!)
    4. A 2D platfomer

    Here’s a sneak peek of what you can look forward to in the full release:

    Section I: Hello, Unity!

    This section covers everything you need to know to get started with Unity. You’ll learn your way around the UI, how to work with game assets and physics, and create a 3D twin-stick combat game: Bobblehead Wars.

    Bobblehead Wars

    Here’s what you’ll cover while saving the world from creepy-crawly aliens:

    • Chapter 1, Hello Unity: Learn how the Unity interface works and how to import assets into your project.
    • Chapter 2, GameObjects: Learn about GameObjects and Prefabs by adding and laying out the initial objects for Bobblehead Wars.
    • Chapter 3, Components: Learn how to use components to give your hero the ability to walk and blast away at the oncoming horde.
    • Chapter 4, Physics: Learn the basics of game physics by adding collision detection and giving the hero the ability to turn on a dime.
    • Chapter 5, GameManager and Pathfinding: Learn how to create the tools that spawn the aliens, and then make them chase after the hero.
    • Chapter 6, Animations: Learn how to add animations to the marine and the aliens. It’s time for some shooting and chomping!
    • Chapter 7, Sounds: Learn how to bring your game to life by adding background music and a variety of sound effects.
    • Chapter 8, Finishing Touches: Learn how to add a winning and losing condition, and wrap up the game with some classy touches.

    Section II: First-Person Games

    Now that you’re up to speed with Unity game development, you can move on to more complex game development topics, such as adding in-game UI elements, advanced camera techniques and using multiple weapons.

    In this section, you’ll build a fast-paced first-person shooter: Robot Rampage.

    Robot Rampage

    Here’s a brief outline of what this section has in store:

    • Chapter 9, Making a First Person Shooter: Learn how to set up your FPS game, create the map, add the player and build some kick-ass weaponry for mowing down enemies.
    • Chapter 10, Adding Enemies: Learn how to create powerups, add enemies to your game, and create some damage mechanics for you and your robot nemeses.
    • Chapter 11, Unity UI: Learn how to add in-game UI, craft waves of robot enemies, add enhanced sound and music, and give your player the right weapon for the right job.

    Section III: Unity 2D Games

    3D games are undeniably awesome, but you just can’t beat a classic 2D platformer game.

    In this section, you’ll build a game to test your reflexes as you help your hero battle his way to a well-deserved lunch in Super Soy Boy:

    Super Soy Boy

    Here’s the chapters and topics you’ll cover while helping Super Soy Boy avoid those terrifying buzzsaws:

    • Chapter 12, Beginning Unity 2D: Learn the 2D workflow in Unity and begin creating the building blocks for your 2D platformer game.
    • Chapter 13, More Unity 2D: Learn how to work with 2D physics, how to build levels with sprites and colliders, and how to work with raycasting, animation controllers, and more.
    • Chapter 14, Saving Data: Learn some great ways to store and retrieve player data for your games.

    Section IV: Tower Defense

    Combining strategy and action results in compelling games that are easy to pick up — and hard to put down.

    In this section, you’ll create a 3D tower defense game — Runestrife — with such beautifully-rendered enemies it almost seems a shame to shoot them:

    Runestrife

    When you’re not busy defending your towers from advancing waves of enemies, here’s what you’ll learn:

    • Chapter 15, Making a Tower Defense Game: Learn how to build a title screen, create a map using 3D tiles, make enemies move around on a path, and make your life easier with utility scripts.
    • Chapter 16, Waves of Enemies: Learn how to create multiple waves of advancing enemies, make your towers shoot projectiles, add winning and losing game states, and craft a UI to bind everything together.
    • Chapter 17, Virtual Reality: Learn how to bring your game into the 21st century and make your game VR-compatible with the virtual reality hardware now available.
    • Chapter 18, Publishing your Game: Learn how to prepare your game for publication and how to make it available on the various online game portals.

    The book also will also include a few bonus chapters beyond this – but our lips are sealed! :]

    Unity Games by Tutorials Week and Giveaway

    To help celebrate the early access release, each day this week we’ll do something special:

    unitygames-calendar

    • Monday: That’s today! Enjoy the early access release of Unity Games by Tutorials.
    • Tuesday: Check out the first chapter of the book in tutorial form on the site.
    • Wednesday: Read a second free chapter! But for the rest, you’ll have to order the book. :]
    • Thursday: Enjoy a special tutorial on creating a simple first-person shooter through Unity scripting.
    • Friday: Close out the celebrations with our Unity Games by Tutorials giveaway!

    Giveaway details: Three lucky readers will win a free PDF copy of Unity Games by Tutorials (or any one of our books, if you’ve already purchased Unity Games by Tutorials).

    To enter into the giveaway, simply leave a comment on this post answering the following question:

    What are you looking forward to in Unity Games by Tutorials?

    Last Week’s Giveaway Winners

    Last week, we gave everyone a chance to guess the topic of this secret book for a chance to win a free copy, and today we’re happy to announce the winners:

    • The random winner person who guessed correctly was… pencilpoint!
    “I hope it’s Unity… I hope it’s Unity… Come on lucky 7…. It’s Unity!!! And the crowd goes wild……..”pencilpoint
    • The random winner person who most creative or funny answer was… skiwalker!
    “the secret spy life of The Ray wenderlich team! Realistically an android programming book!”skiwalker

    Both readers earned a free copy of Unity Games by Tutorials. Thanks to everyone for your creative guesses!

    Where To Go From Here?

    There’s one final piece of good news.

    To celebrate the early access release of Unity Games by Tutorials, you can order the book and receive an automatic $10 early access discount.

    To take advantage of the special discount and get the first early access release, order your copy now.

    The Unity team and I hope you enjoy the book, and we can’t wait to see your future games!

    The post Introducing Unity Games by Tutorials! appeared first on Ray Wenderlich.

    Introduction to Google Cardboard for iOS

    $
    0
    0
    Google Cardboard VR

    Dive into the world of virtual reality with Google Cardboard VR.

    Many of the biggest tech firms in the world are investing heavily in virtual reality technologies: Facebook spent $2 billion to acquire Oculus Rift; Disney invested $65 million into a VR film company called Jaunt; Microsoft introduced its HoloLens this year and is selling the device to developers for $3000 apiece.

    Apple spent $32 million to acquire the engineers from Metaio and $345 million to acquire PrimeSense, two companies of VR innovators, and pre-orders for Sony’s Playstation VR sold out even quicker than they’d expected, proving there’s a strong consumer market for VR.

    Of all the exciting new VR technology being introduced, however, Google Cardboard VR has made virtual reality most accessible to the hobbyist. In fact, with just a low-cost Google Cardboard VR headset, a smartphone and your iOS skills, you can go farther than you ever thought possible.

    In this intro to Google Cardboard VR tutorial, fellow jetsetters, you’ll embark on a worldwide 360° vacation by clicking through multiple 360° vacation images and pausing/playing your way through a 360° vacation video.

    Note: This Google Cardboard VR tutorial assumes you know the basics of iOS and Swift development. If you’re new to iOS development and Swift, check out our “Learn to Code iOS Apps with Swift Tutorial” series first.

    Getting Started

    Download the starter project and open Vacation 360.xcodeproj in Xcode. In the 360 images folder in the Navigation Bar on the left-hand side of your Xcode console, you’ll see three 360° panorama images you’ll eventually display in the app. In Main.storyboard, you’ll find a VacationViewController containing a few labels, two empty UIViews and some constraints.

    The interface may not look like much yet, but you’ll eventually change these two UIViews into Google Cardboard photo and video VR views. Build and run your app; you won’t see much except for the labels describing the behaviors you’ll implement in this Google Cardboard VR tutorial.

    Starter app screenshot

    Starter app screenshot

    Installing the Google Cardboard VR SDK

    Before you start coding your Google Cardboard VR app, the first step is to install the Google Cardboard VR SDK with CocoaPods. Or rather, if you’ve never used CocoaPods before, the first step is to install CocoaPods and the second is to install Google Cardboard VR using CocoaPods.

    As described in Joshua Green’s great tutorial on How to Use CocoaPods with Swift, install CocoaPods and the Google VR SDK using the following steps.

    Open Terminal, then execute the following command:

    sudo gem install cocoapods

    Enter your computer’s password when requested. To install the Google VR SDK in the project, navigate to the Vacation_360 starter project folder by using the cd command:

    cd ~/ComputerLocation/Vacation_360

    Next, create a Podfile for your project:

    pod init

    Then open the Vacation_360 folder, open the Podfile with a text editor and replace all of its current text with the following:

    target "Vacation 360" do
        pod 'GVRSDK'
    end

    This tells CocoaPods that you want to include the GVRSDK, i.e. the Google VR SDK, as a dependency for your project. Save and close Podfile. Then in Terminal, in the same directory to which you navigated earlier, enter:

    pod install

    That’s it! You’ve installed Google’s VR SDK. As the log output states, “Please close any current Xcode sessions and use `Vacation 360.xcworkspace` for this project from now on.”

    terminal

    As with any app in which you install CocoaPods, you’ll be working from the .xcworkspace file instead of the .xcodeproj from this point forward.

    Because the Google VR SDK is an Objective-C framework, you’ll have to use an Objective-C bridging header to access it from your Swift code. Go to File\New\File…, select iOS\Source\Header File and then click Next. Name it Vacation 360-Bridging-Header, select the Vacation 360 folder for the Group, then hit Create.

    Create Bridging Header

    Next, select the Vacation 360 project in the Project Navigator, then select Vacation 360 under TARGETS. Go to Build Settings, look for Objective-C Bridging Header under the Swift Compiler – Code Generation section and enter “Vacation 360/Vacation 360-Bridging-Header.h”.

    Bridging Header Build Setting - Google Cardboard VR

    As you might have guessed, this tells the compiler where to look for your bridging header.

    Replace the contents of Vacation 360-Bridging-Header.h with the following:

    #import "GVRPanoramaView.h"
    #import "GVRWidgetView.h"
    #import "GVRVideoView.h"

    Now you have access to the three Google Cardboard VR SDK classes you’ll be using in this tutorial.

    Start packing those bags; Vacation 360, here we come! :]

    Hula, hula!

    Hula, hula!

    Coding the Groundwork

    The Google Cardboard VR SDK has three VR view types: GVRCardboardView, GVRPanoramaView, and GVRVideoView. GVRCardboardView is by far the most powerful of the three, since in VR mode it lets you determine the user’s head and eye positions, layout 3D audio, and dynamically alter the landscape. Unfortunately, GVRCardboardView requires complex OpenGL rendering beyond the scope of this tutorial; but GVRPanoramaView, Google VR’s image viewer, and GVRVideoView, Google VR’s video viewer, are more than adequate vessels for an international adventure.

    Before you start diving into the Google VR methods, you’ll have to lay some groundwork. First, you’ll connect and load the Google Cardboard 360° panoramic photo and video views.

    Navigate to Main.storyboard and select the transparent UIView directly under the Click through Sindhu Beach, Grand Canyon, & Underwater Photos label. In the Utilities menu on the right hand side of Xcode, navigate to the Identity Inspector, then in the Custom Class section, enter “GVRPanoramaView” in the Class field. Similarly, select the UIView directly below Play/Pause “Living with Elephants” Safari Video by Photos of Africa and enter “GVRVideoView” in the Class field.

    Using the Assistant Editor, control-drag from these two views in Interface Builder to the top of the VacationViewController class in VacationViewController.swift and create Outlets. For GVRPanoramaView, use the name imageVRView and for GVRVideoView use videoVRView. Similarly connect the label outlets to the top of VacationViewController. Name the top label imageLabel and the bottom label videoLabel.

    Connecting GVRVideoView outlet - Google Cardboard VR

    Next, make the media file URLs accessible by defining them in an enumeration. Directly under the IBOutlets, define enum Media as follows:

    enum Media {
      static var photoArray = ["sindhu_beach.jpg", "grand_canyon.jpg", "underwater.jpg"]
      static let videoURL = "https://s3.amazonaws.com/ray.wenderlich/elephant_safari.mp4"
    }

    In this enumeration, photoArray holds the file names of the 360° images stored in the bundle and videoUrl holds the URL of the 360 video you’ll display. The photoArray is variable and not constant so you can alter the array to easily cycle through the images later on.

    Monoscopic 360° of Sindhu Beach, Indonesia by Eggy Sayoga

    Monoscopic 360° of Sindhu Beach, Indonesia by Eggy Sayoga

    Set the initial photo and video by adding the following in viewDidLoad() just below super.viewDidLoad():

    imageVRView.loadImage(UIImage(named: Media.photoArray.first!),
                            ofType: GVRPanoramaImageType.Mono)
    videoVRView.loadFromUrl(NSURL(string: Media.videoURL))

    You load imageVRView‘s UIImage with Media.photoArray.first! while passing the type GVRPanoramaImageType.Mono to indicate that the image is monoscopic.

    Then you load videoVRView with an NSURL created from the Media.videoURL string.

    There are two format types for 360° images and videos: stereoscopic and monoscopic – stereo and mono for short. Although both formats render 360° media by converting a rectangular panorama into a spherical layout, the stereoscopic format adds some depth to the viewing experience by including two slightly offset images or videos, one stacked above the other, that mimic the viewer’s perspective.

    In VR mode, even monoscopic media appears stereoscopic. - Google Cardboard VR

    In VR mode, even monoscopic media appears stereoscopic. Photo by Eggy Sayoga

    Monoscopic media features the image or video from a single point of view. Google Cardboard VR supports both formats, but displays either format as stereoscopic. When viewing either format in fullscreen VR mode, the viewer shows two side-by-side images or videos slightly offset from one another. You can find the ideal specifications for both mono and stereo here.

    Stereoscopic 360° of Sindhi Beach, Indonesia by Eggy Sayoga

    Stereoscopic 360° of Sindhi Beach, Indonesia by Eggy Sayoga

    Build and run the app without your Google Cardboard VR headset to see what these views provide with minimal configuration. You’ll see the 360° image in the top view and, as long as you’re connected to the internet and thus able to load from the web URL, you’ll see the 360° video in the bottom view.

    Rotating the device will rotate both embedded views. Tap the info symbol at the bottom left corner of either VR view and you’ll be directed to a Google Cardboard VR help webpage. Tap elsewhere on the VR views, and nothing will happen.

    Initial VR View - Google Cardboard VR

    In order to enable the fullscreen mode and fullscreen VR mode, you’ll need to enable the corresponding buttons on the GVRPanoramaView and GVRVideoView. Add the following below the line in viewDidLoad() where you load imageVRView‘s image:

    imageVRView.enableCardboardButton = true
    imageVRView.enableFullscreenButton = true

    Next, add the following below the line where you load videoVRView‘s video:

    videoVRView.enableCardboardButton = true
    videoVRView.enableFullscreenButton = true

    Build and run again; two new buttons should appear on the bottom right of each VR view. Tap the outer right button, i.e. the Fullscreen Button, on either VR view, and the view will resize to fit the full screen. While in full screen, tap the back button on the top left corner to return to the main view.

    Next tap the inner right button, i.e. the Cardboard Button, and a view should appear with instructions on how to connect your viewer. To view the media in fullscreen VR mode, insert your device into your Google Cardboard VR headset as instructed such that the top of the device is on the left side of the viewer and the bottom is on the right:

    (1) Main embedded view (2) Fullscreen view (3) Google Cardboard instruction view - Google Cardboard VR

    (1) Main embedded view (2) Fullscreen view (3) Google Cardboard instruction view

    Note: Tapping the Switch button at the bottom left corner of the Google Cardboard instructions screen will allow you to sync your app to your current VR headset by capturing the QR code on your viewer.

    To get the full immersive VR experience from this tutorial, I suggest you use a Google Cardboard compatible device. You can purchase a headset on the Google Cardboard website for as little as $14.95.

    Or you can even make your own! To do this, just sit back and order a pizza. … What? You’re still VR-less 30 minutes later? Oh right – you also have to cut up that box, add some lenses, a magnet, velcro, and a rubber band to MacGyver your way into your worldwide vacation. The do-it-yourself instructions are available at that same Google Cardboard website link towards the bottom of the page.

    You can build your own Google Cardboard! - Google Cardboard VR

    You can build your own Google Cardboard!

    But if you’re content with viewing a 360° panorama from your device without being fully immersed, this tutorial will still work for you without a viewer.

    Making the VR Views Interactive

    In Vacation 360, the user can click through images while viewing imageVRView and can play and pause video while viewing videoVRView. The backing classes for each of these inherit from GVRWidgetView, which implements the GVRWidgetViewDelegate protocol. This protocol lets GVRWidgetViewnotify its delegate of various state changes and interactions, which will come in handy while customizing the VR view behaviors.

    Directly underneath the closing bracket of the VacationViewController class, add the following:

    extension VacationViewController: GVRWidgetViewDelegate {
      func widgetView(widgetView: GVRWidgetView!, didLoadContent content: AnyObject!) {
      }
     
      func widgetView(widgetView: GVRWidgetView!, didFailToLoadContent content: AnyObject!,
        withErrorMessage errorMessage: String!)  {
      }
     
      func widgetView(widgetView: GVRWidgetView!, didChangeDisplayMode displayMode: GVRWidgetDisplayMode) {
      }
     
      func widgetViewDidTap(widgetView: GVRWidgetView!) {
      }
    }

    You’ve implemented the GVRWidgetViewDelegate and all of its methods in an extension. It’s time to fill in each method one by one.

    widgetView(_:didLoadContent:) is called when a VR view has loaded its content successfully. What’s that you say? How about using this method to only reveal elements of the view once they have loaded? Sounds like a great idea! :]

    First, head back to viewDidLoad() and add the following just below super.viewDidLoad():

    imageLabel.hidden = true
    imageVRView.hidden = true
    videoLabel.hidden = true
    videoVRView.hidden = true

    This will hide all of the labels and VR views initially, so that they won’t appear until the content loads.

    Now, grouped with the other imageVRView code in viewDidLoad(), add the following:

    imageVRView.delegate = self

    Similarly, add the following with the videoVRView code:

    videoVRView.delegate = self

    This sets both view’s GVRWidgetViewDelegates to the VacationViewController.

    You can now unhide the labels and views once their corresponding content has loaded. Back in widgetView(_:didLoadContent:), add the following:

    if content is UIImage {
     imageVRView.hidden = false
     imageLabel.hidden = false
    } else if content is NSURL {
     videoVRView.hidden = false
     videoLabel.hidden = false
    }

    widgetView(_:didLoadContent:) is passed the loaded content object – in this case a UIImage for GVRPanoramaViews and an NSURL for GVRVideoViews. For the UIImage, unhide the imageVRView and its corresponding label. For an NSURL, unhide the videoVRView and its corresponding label.

    Build and run; you’ll see that each VR view and label now only appears when its corresponding content has loaded:

    The VR views now appear after they load. (1) The image VR view has loaded. (2) The video VR view has also loaded.

    The VR views now appear after they load. (Left) The image VR view has loaded. (Right) The video VR view has also loaded.

    Add the following to widgetView(_:didFailToLoadContent:withErrorMessage:):

    print(errorMessage)

    This is called when there’s an issue loading the content. In that case, you simply print the passed errorMessage.

    Next you’ll use widgetView(_:didChangeDisplayMode:) to store the current display mode and selected view, so that tapping on the widgets will trigger the appropriate actions only when a VR view is in fullscreen or VR mode. This method is called each time you switch between embedded, fullscreen, or VR mode and passes the involved widgetView.

    First, in the main VacationViewController class below the enum Media declaration block, add the following:

    var currentView: UIView?
    var currentDisplayMode = GVRWidgetDisplayMode.Embedded

    currentView will maintain a reference to the view currently displayed in fullscreen or VR mode. currentDisplayMode is used to hold the current display mode. It is initialized to GVRWidgetDisplayMode.Embedded which represents the initial display mode when the VR views are embedded in the VacationViewController.

    Then in widgetView(_:didChangeDisplayMode:), add the following:

    currentView = widgetView
    currentDisplayMode = displayMode

    widgetView(_:didChangeDisplayMode:) passes the new displayMode as well as the widgetView where the mode was changed. These are stored in currentDisplayMode and currentView, respectively, for later reference.

    Knowing the display mode and displayed view, you can finally start to implement the interactive behaviors while in fullscreen or VR mode. Tapping the magnetic widget button on Cardboard or directly tapping the screen should cycle through the photos in Media.photoArray when the imageVRView is in fullscreen or VR mode. To implement this behavior, add the following to widgetViewDidTap(_:):

    // 1
    guard currentDisplayMode != GVRWidgetDisplayMode.Embedded else {return}
    // 2
    if currentView == imageVRView {
      Media.photoArray.append(Media.photoArray.removeFirst())
      imageVRView?.loadImage(UIImage(named: Media.photoArray.first!),
        ofType: GVRPanoramaImageType.Mono)
    }
    1. Since you only want to handle taps while in fullscreen or VR mode, a currentDisplayMode of .Embedded triggers an early return.
    2. If currentView is imageVRView, advance the Media.photoArray queue by removing the first element of the array and appending it to the end. Since Media.photoArray.removeFirst() returns the removed element, you can remove the first element and append it to the end in a single line of code. Then you load imageVRView‘s UIImage using the file now in the first index of the photo array.

    Build and run your project; open the image VR view into either fullscreen or VR fullscreen, then tap either the device screen or the widget button respectively. You should be able to click through the images.

    Clicking through images in fullscreen - Google Cardboard VR

    Clicking through images in fullscreen

    You may notice one minor issue: the other elements of the view show through between each click. To prevent that, hide the elements whenever you’re not viewing the embedded display mode by adding the following to the end of widgetView(_:didChangeDisplayMode:):

    if currentView == imageVRView && currentDisplayMode != GVRWidgetDisplayMode.Embedded {
      view.hidden = true
    } else {
      view.hidden = false
    }

    If the currentView is the imageVRView and the currentDisplayMode isn’t embedded, this means you’re viewing the image view in fullscreen or VR mode. In that case, hide the view controller’s root view; otherwise, unhide it.

    Build and run; click through the images again, and the transition between images should be almost seamless:

    Clicking through images in fullscreen

    Clicking through images in fullscreen

    Note: Even after setting view.hidden to true, the GVRPanoramaView stays unhidden because it and the GVRVideoView are not subviews of the VacationViewController‘s view when in fullscreen or VR mode.

    Congrats on successfully creating a 360 image slideshow!

    congrats!

    But don’t get too lost in your vacation yet. The interactions are only halfway done!

    What? It gets even better??

    What? It gets even better??

    Video View Interaction

    You still have to implement the video view interaction which will let you pause and play the “Living with Elephants” video by Photos of Africa so that each moment of your vacation can last even longer.

    Back in the main VacationViewController class, add the following new variable underneath the var currentDisplayMode declaration:

    var isPaused = true

    There is no property inherent to the GVRVideoView that indicates whether the video is paused or playing, so the variable you’ve just created can serve as a state marker.

    Also create a method to set the initial play state behavior dependent on the display mode. Underneath viewDidLoad() add:

    func refreshVideoPlayStatus() {
      // 1
      if currentView == videoVRView && currentDisplayMode != GVRWidgetDisplayMode.Embedded {
        videoVRView?.resume()
        isPaused = false
      }
      // 2
      else {
        videoVRView?.pause()
        isPaused = true
      }
    }
    1. If videoVRView is in fullscreen or VR mode, calling this method plays the video and appropriately sets isPaused to false.
    2. Otherwise, if the videoVRView‘s display mode is in its embedded state or the imageVRView is in fullscreen, calling this method pauses the video and appropriately sets isPaused to true.

    Then within widgetView(_:didLoadContent:)‘s else if block, add:

    refreshVideoPlayStatus()

    This pauses the video as soon as it loads.

    Now in widgetView(_:didChangeDisplayMode:), just before the if block and after setting currentDisplayMode, insert the following:

    refreshVideoPlayStatus()

    By calling refreshVideoPlayStatus() whenever the display mode changes, the video will play when entering fullscreen or VR mode, and pause otherwise.

    Now that you’ve set videoVRView‘s initial display mode behaviors, you can implement a play/pause toggle triggered by user interaction. In widgetViewDidTap(_:), after the if block, add:

    else {
      if isPaused {
        videoVRView?.resume()
      } else {
        videoVRView?.pause()
      }
      isPaused = !isPaused
    }

    You hit this else clause when you tap a videoVRView. If the video is paused, resume playing; if the video is playing, pause it. Then you update isPaused to reflect the new play state.

    Build and run your app, open the video into fullscreen or VR mode, then tap the screen or widget button and the video should toggle between play and pause states:

    Play/pause while watching the video by Photos of Africa - Google Cardboard VR

    Play/pause while watching the video by Photos of Africa

    Note: There is currently a minor bug in the SDK that causes the video to unpause when the VR mode is selected, but not actually entered. In other words, if you back out of the VR view without actually tilting the device to start playback, the video will unpause.

    You don’t want your vacation to stop after a few minutes though, do you? Of course not! So therefore you’ll loop the video to the beginning once it reaches the end.

    Add a GVRVideoViewDelegate extension below the final bracket of the GVRWidgetViewDelegate extension to implement the looping behavior:

    extension VacationViewController: GVRVideoViewDelegate {
      func videoView(videoView: GVRVideoView!, didUpdatePosition position: NSTimeInterval) {
        if position >= videoView.duration() {
          videoView.seekTo(0)
          videoView.resume()
        }
      }
    }

    videoView(_:didUpdatePosition:) is called at approximately one-second intervals as the video plays. Once the NSTimeInterval position of the video is greater than or equal to the duration of the video, the video has reached its end. videoView.seekTo(0) then sets the position back to the beginning before resuming the video.

    Note: There is no need to set VacationViewController as the GVRVideoViewDelegate because…it’s already set! GVRVideoViewDelegate inherits from GVRWidgetViewDelegate, which you’ve already adopted and set up in viewDidLoad() of VacationViewController.

    There you have it! Now you can build, run, sit back and enjoy the worldwide vacation you’ve just created with your bare hands. Isn’t iOS development spectacular?

    kick back with cardboard - Google Cardboard VR

    Where to Go From Here?

    Download the finished project here, and check out Google’s sample projects here.

    The Google Cardboard mobile SDK had originally only been available for Android devices until Google graciously opened up its Cardboard SDK to iOS earlier this year. Google VR for iOS is still very new and will evolve over time, so keep an eye on raywenderlich.com for Google Cardboard VR tutorials using the enthralling new features Google will undoubtedly roll out in the near future.

    Have comments or questions? Please join the forum discussion below!

    The post Introduction to Google Cardboard for iOS appeared first on Ray Wenderlich.

    RWDevCon 2016 Inspiration Talk – Embracing Failure by Janie Clayton

    $
    0
    0

    Note from Ray: At our recent RWDevCon tutorial conference, in addition to hands-on tutorials, we also had a number of “inspiration talks” – non-technical talks with the goal of giving you a new idea, some battle-won advice, and leaving you excited and energized.

    We recorded these talks so that you can enjoy them, even if you didn’t get to attend the conference. Here’s our next talk – Embracing Failure by Janie Clayton – I hope you enjoy!

    Transcript

    Hi, everybody. I am Janie Clayton and I’m going to talk about something that a lot of us really don’t like to think about. I’m going to talk about how to embrace failure.

    Back when I was a little kid, I started playing the piano and I was really good at it immediately. I was the best person in my class of like 60 people and my town of 2000 people. I could play anything I wanted without having to practice too much.

    So I thought that I was like a total prodigy genius person. I thought that when I grew up I was going to be a concert pianist and I was going to go to Juilliard and perform in front of all of these giant multitudes of people. This was what I was going to do with my life.

    piano-1531788_640

    Well, then something unfortunate happened. I went to a different school where I met other people who’d actually been playing the piano longer than I had and who were a lot better than I was. I would talk and I’m like, “Holy crap. You guys are amazing.” They were like, “No, no, no. We’re not. We’re actually not all that great.”

    I was really disappointed because I thought that this was something that I was going to do with my life. Finding out that I wasn’t the greatest piano player in the world, that this wasn’t what I was going to do, I got really discouraged and I gave up on it because I’d never practiced before and I never had to practice. I didn’t have any discipline to go in and actually do things to make myself better.

    I just assumed that you’re either born good at something, or you weren’t good at it immediately and it just wasn’t something that you were supposed to be doing.

    The Influence of Childhood and School

    I’ve noticed over the last couple of years, I’ve been really thinking about how we go about what we do with our lives. When you’re a kid and later in high school, you’re trying to figure out who you are. When you’re a kid you think you’re going to be an astronaut or you think you’re going to be president of the United States.

    astronaut-1082335_640

    You have all of these ideas about what you’re going to do and we have all of these high stakes things where you have to decide immediately when you’re a little kid about what you’re going to do so that you can take all the right classes in high school and later go on to college.

    Then you get into high school and you don’t really have time to go and pick up any of these cool, neat hobbies that you have. You have to specialize in what it is that you’re going to do. There’s a lot of pressure on you, when you’re a high school student, to go and actually continue to make straight A’s. If you don’t get an A, if you get a B on a test, then your GPA goes down. Then you can’t get into Harvard and everything is ruined.

    urban-998216_640

    This is pressure that we’re putting on these poor 16 year-old kids to tell them that they can’t make any mistakes because if they make one mistake, their entire future is completely screwed. It’s really hard to get yourself out of that mindset even after you get out of high school.

    Fear of Failure Continues into Adulthood

    We as a society are terrified of failure. We have this idea that everything that we do has to lead to something else. Like I said:

    • If you don’t get into the right college, you can’t get the right job.
    • If you don’t do all the right things, then bad stuff will happen to you.
    • You have to go out and you have to get married because that’s what you’re supposed to do.
    • Then you’re supposed to have kids.
    • Then you’re supposed to have a job.

    You figure out when you’re like 40 that you have this life that you have to keep living, that you didn’t really want because you were so afraid of acknowledging that you didn’t like something. You weren’t willing to go in and make changes when it was possible for you to actually do so.

    This leads to a thing that we see in the programming community, where everybody is terrified of ever acknowledging that they don’t know something.

    This leads to a lot of really bad, toxic mindsets and behaviors because everybody’s completely absorbed with trying to maintain this façade that we’re all perfect, that we don’t make any mistakes, that we don’t have failures. Nobody is willing to ask for help; everybody has to pretend like everything that they do is perfect. You get people threatening to kill each over on Stack Overflow because they’re putting their semicolons on the wrong lines.

    This is just a really bad way of going about living, so I just wanted to talk a little bit about my own experiences of failing upwards through life over the last 20 years or so. I want to give people an idea about how we can break out of this cycle and embrace failure so that we can learn and be more happy and productive people.

    Confidence Isn’t Proportional to Competence

    One of the first things I want to talk about is the cycle of learning. Back when I was trying to play the piano and I figured out that I wasn’t actually all that good at it, I quit on it because it was something that I didn’t think I could better at by training.

    The Viking Code School blog had this great thing about why programming is hard and it was talking about this cycle of coding competence versus confidence.

    Attribution: https://www.vikingcodeschool.com/posts/why-learning-to-code-is-so-damn-hard

    Attribution: https://www.vikingcodeschool.com/posts/why-learning-to-code-is-so-damn-hard

    I’m going to talk about my own experiences with programming, even though this is applicable to basically anything that you’d want to be doing.

    When you first start out, you have this nice hand-holding honeymoon stage. When I learned programming, I learned on Codecademy, where you’d go and you would for-loop. Then you get a nice little, “Hey, you did a great job! Here’s a cookie!”

    You feel really good and awesome. It’s cool, because you went and you did something successful and everything was broken down into nice happy, little competent tasks that you could do modularly and you feel really good.

    smiley-1248608_640

    Then you get done with that and then you wind up on the Cliffs of Confusion. You get done with programming and you go and find your first job or you find other people. Then all of a sudden, you hear all of this stuff that nobody talked about when you were learning how to program because it was such an overwhelming thing that there wasn’t any time to go over it.

    You go to a conference and you hear people talk about the Gang of Four and you’re like, “What’s the Gang of Four?” Or people telling you that you need to do things on GitHub or contribute to open source and you’re asking, “How do you contribute to open source?” and then they give you a look like, “Oh, you’re one of those people.”

    child-1121178_640

    You’re too afraid to ask about it ever again and then everybody thinks poorly of you. So you’re spending all of this time bouncing around, trying to figure out all of these institutional knowledge that it seems like everybody else has that you didn’t have.

    It gets very confusing and then eventually that leads to the Desert of Despair. You feel like you’re never going to catch up. That everybody knows all of this stuff. They were born with this knowledge. It wasn’t that they learned it over a course of time. You feel like you’re a failure and there’s nothing you can do. You get on your first project and you don’t have all of these nice little modular tasks like you did on Codecademy.

    You have to figure out what you’re supposed to be doing. You’re talking to a client that doesn’t know what they want to be doing. It leads to this really powerful pit of despair where you just feel like you’re a failure and you don’t think you’re going to be able to do anything. You feel like you have to keep working harder and harder and harder to keep up.

    portrait-317041_640

    Then everybody else around you is also trying to work harder and harder and harder to keep up. It leads to this horrible endless cycle of everybody trying to pretend like we all know what we’re doing when we really don’t.

    This is the cycle we’re in right now and we don’t have to live this way. It’s important to be able to realize that you can fail at something and that your world is not going to end. If you do one thing wrong, it isn’t going to lead to you having your entire life be destroyed. You’re not going to lose everything.

    Advice from My Own Experiences

    I want to talk a little bit about a couple of pieces of advice that I have from my own failures. Now unfortunately, failing is incredibly painful.

    stairs-932806_640

    In the original version of this talk, I was talking about the worst day of my life, which happened in 2008. I was going to school for audio engineering, video editing and other stuff after going to school to get a journalism degree. I’d spent about 10 years and 60 thousand dollars going to school trying to pursue this career.

    In one day all of that was gone. My career was gone, all my network was gone. Everything was just completely gone. It was a really horrible, painful experience that I never want to go through ever again.

    I learned so much from that experience that I decided to write this talk. It was such a horrible, painful experience. I learned all of these things that I knew I never wanted to deal with ever again.

    For some reason we remember painful things a little bit better than we remember things that were successful and things that made us happy. Failing is a good thing because, if you think about it properly, you can really learn a lot of stuff about yourself and how to avoid having to deal with this painful stuff in the future.

    Anything that you do is going to be difficult at first.

    boxer-557143_640

    I don’t know how many people have not actually been programming for very long, but I haven’t been programming for very long. I talk to people who’ve been programming since they were seven and they don’t remember that programming used to be hard.

    When you first start off, you’re really slow and there’s a bunch of stuff that you don’t know, but you don’t think about it. Then as you get better and better, you start getting faster. Then eventually things get better.

    Tip #1: Practice Is Necessary

    Nobody is born being able to do something like this.

    motorcycle-654429_640

    This takes a lot of time and work and dedication. We just see the end result. You need to be aware of the fact that when you first start out with something, you’re not going to be like this, but you can get to be this skilled if you work really hard and you are focused and willing to work through all of the pain and the Cliffs of Confusion and the Desert of Despair.

    Tip #2: What You Do Doesn’t Define You

    We also need to stop trying to find something that’s going to define us.

    I have heard of all of these problems in the last couple of years with gamer gate, where you have these people who have adopted the persona of thinking of themselves as a gamer. They don’t think of gaming as something that they enjoy doing. It’s just who they are.

    hands-514479_640

    That causes a lot of problems, especially when you’re in online communities of people. Then people can’t give you advice about how you can be better at what you do because you confuse what you’re doing with who you are. Every time somebody tells you that you could be making your code more efficient, you take it as a personal attack because you completely adopted that as your persona.

    You don’t have your nice patronus out there that can absorb all of the negative energy that you’re getting from people. You have no buffer because you have decided to identify yourself with what it is that you’re doing.

    It’s really important to try to get away from that mindset so that you can be a happier person and be able to accept that sometimes you’re going to do something that doesn’t quite work out.

    Tip #3:Don’t Compare Yourself With Others

    We also need to stop comparing ourselves to other people.

    Screen Shot 2016-07-31 at 4.50.37 PM

    As Vicky mentioned in my bio, I spent a year working for Brad Larson. Brad Larson is the creator of GPUImage, he’s a moderator on Stack Overflow and he had one of the first video series on iOS development before raywenderlich.com really got big.

    He’s been programming for 30 years. I’ve been programming for 3 years. I was working with him and I kept comparing myself to him because I thought he was really cool.

    We have people in our community that we think are really cool and want to be like them, but we have to acknowledge that we’re all different people. We have different experiences and we’ve been doing things for different periods of time.

    I would get really frustrated and depressed because I knew that I was never going to be as good as Brad. I actually had a discussion with another developer, Jeff Biggus, where I was telling him about how I felt like a failure because I was working for this genius guy and I just felt stupid.

    Jeff just looked at me. He’s like, “Do you remember what you were doing last year? Last year you were unemployed. Last year you were doing your first conference talk, you were just getting started out and now you have a book. You’re working for Brad. You’ve done a dozen conference talks. Everybody in the community knows who you are. Look at how far you’ve come in the last year.”

    I hadn’t thought about it that way because I was so busy comparing myself to the people that I admired and wanted to be like, that I didn’t think about who I used to be. If you told me 3 years ago I’d be doing this, I would have thought, “Nah. There’s no way.”

    One of the reasons why I talk about all of this stuff in the community is because there might be people out in the audience who compare themselves to me and go, “Oh, man. Janie, she’s only been doing this for a few years but she’s really successful. I’m never going to be.” I don’t want people to feel that way.

    I want everybody to be able to be happy with what they’re doing on their own without comparing themselves to anybody else. I want everybody to feel okay with saying, “You know what? I’m going to learn something that’s really hard and I’m going to go for it. I’m not going to worry about how I compare to somebody else.”

    Tip #4: Do What Makes You Happy

    Also, just do things that make you happy.

    dance-18766_640

    I know for a really long time, we’ll have the mindset that any hobby or thing that we do has to eventually lead to something else. I don’t know about anybody else, but I’m bad at doing the away from keyboard thing. For me, my hobbies are going and writing code for myself as opposed to code that I’m being paid to write for other people.

    I recently started cooking because it was something I needed to learn how to do. I’d never been on my own before. I was getting really tired of all of the nasty packaged food that I was getting from the grocery store. It was just something I wanted to do for myself.

    woman-hands-1207952_640

    It wasn’t because I wanted to be a chef or because I wanted to write a cook book, even though I’ve been told I should do that at some point. It was a thing that I wanted to do because it was important to me and I wanted to know that I could cook. I wanted to be able to make food and feed myself and do things properly because it was something that was important to me.

    Do things that make you happy, without thinking about where it’s going to lead or what it’s going to do for you. Go out and dance badly if it makes you happy because our lives do not revolve around other people. We have to do what we want to do to make ourselves feel good.

    Tip #5: Acknowledge Your Mistakes

    That also includes being able acknowledge if you’ve made a mistake.

    I know a lot of people who, from the time they were really little, they wanted to be game developers because they loved video games and that was the only thing they ever wanted to do.

    So they spent all of their school time trying to learn how to do game development. They went to college for game development. Then they get into the industry and game development is not the best place to work for a lot of people because there is a lot more people who want to do it than there is market for it.

    I can understand. If you spent all of your life thinking that you were going to do something and you spent a lot of money and you went into a lot of debt. Then you go into this field and find out that it’s something you don’t really like doing. It can be really hard to acknowledge that this is something that you don’t want to do and to walk away from it.

    Since we’re at an Apple developer conference, I feel it is necessary to mention Steve Jobs. Steve Jobs is one of my heroes.

    steve-jobs-1249665_640

    I know I really shouldn’t think of Steve Jobs as one of my heroes because he’s a person who was paying orphans in China 20 cents to make iPhones, but one of the things that I really admire and respect about him that I’ve taken away from his story was what happened to him when he got forcibly removed from Apple.

    This was a horrible, awful experience that he went through where he lost the company that he founded. There were a couple of different ways he could respond to this.

    He could have taken all of his Apple money and go on and bought a scuba shop on the beach and told everybody about how he used to be a big tech guy, but he didn’t do that. He wanted to be able to move forward and do something else.

    He dusted himself off and moved on. He started NeXT. He bought Pixar. He did a whole bunch of stuff after that happened and eventually he came back and he led the company to what it is today.

    I think it’s important for everybody to understand that we’re all going to fail and what happens after you fail is just as important as what happened before you failed.

    Failing doesn’t define you. Your reaction to it does.

    If you’re able to analyze your failures and look at what happened and what led to it, you’re able to get an idea about how you can avoid failing again in the future. I know people who horrible things happened to them because they made really bad decisions, but they didn’t want to acknowledge that they had any personal responsibility for what happened to them. You know, it was just a fluke of the universe.

    ship-aground-1041335_640

    I think of my ex-husband, who lost his job while we were still married because he started taking every single Friday off and made it very clear to his company that he didn’t want to be there. When I talked to him afterward I’m like, “Okay. Do you understand why you lost your job.” He’s like, “Yeah. It’s because the universe sucks” and he wouldn’t acknowledge that he had any control over what happened to him.

    When you fail, you can either walk away and decide the universe sucks, or you can do the really hard thing of taking a look in the mirror and saying, “What can I do to avoid having to do this ever again?”

    I really hope that everybody here feels a little bit more comfortable about trying to embrace their failures and being able to go out and try something that might be a little bit less familiar. It’s not the end of the world if you don’t do particularly well at it the first time. It takes a little while and if you keep working at it, you’ll do better.

    So go forth and be awesome!

    woman-1401616_640

    Note from Ray: If you enjoyed this talk, you should join us at RWDevCon 2017! We’ve sold out for the past two years, so don’t miss your chance.

    The post RWDevCon 2016 Inspiration Talk – Embracing Failure by Janie Clayton appeared first on Ray Wenderlich.


    Unity Tutorial Part 1: Getting Started

    $
    0
    0

    Unity-1-feature

    To say game development is a challenge would be the understatement of the year.

    Until recently, making 3D games required low-level programming skills and advanced math knowledge. It was akin to a black art reserved only for super developers that never saw the sunlight.

    That all changed with Unity. Unity has made this game programming into a craft that’s now accessible to mere mortals. Yet, Unity still contains those complicated AAA features, so as you grow as a developer you can begin to leverage them in your games.

    Just like every game has a beginning, so does your learning journey — and this one will be hands-on. Sure, you could pore over pages and pages of brain-numbing documentation until a lightbulb appears above your head, or you can learn by creating a game.

    You obviously would prefer the latter, so in this Unity tutorial series you’ll build a game: Bobblehead Wars.

    In this game, you take the role of a kickass space marine, who just finished obliterating an alien ship. You may have seen him before; he also starred in our book 2D iOS & tvOS Games in a game called Drop Charge.

    drop-charge

    After destroying the enemy ship, our space marine decides to vacation on a desolate alien planet. However, the aliens manage to interrupt his sun tan — and they are out for blood. After all, space marines are delicacies in this parts of the galaxy!

    This game is a twin-stick shooter, where you blast hordes of hungry aliens that relentlessly attack:

    bobble-wars

    You’ll toss in some random powerups to keep gameplay interesting, but success lies in fast footwork and a happy trigger finger.

    You’ll start by exploring the Unity interface and learn how to import assets into your project.

    Installing and Running Unity

    Before you can take on aliens, you need to download the Unity engine itself.

    Head over to the following URL: http://unity3d.com/get-unity

    You’ll see a page with many options from which to choose:

    options

    You can go Pro if you’d like, but it’s excessive at this stage of your journey. For this tutorial, you only need the free version. In fact, you can even release a complete game and sell it on Steam with the free version.

    Previously, certain engine features were disabled in the free version. With the release of Unity 5, all those closed-off features are now available to everybody that uses the personal version.

    In case you are curious, here are what the three options mean:

    • Unity Personal: This edition allows you to create a complete game and distribute it without paying Unity anything. However, your company must make less than $100,000/year. The other catch is that each game will present a Made by Unity splash screen that you can’t remove.
    • Unity Plus: This edition costs $35/month if you pay yearly, or $50/month if you pay monthly. It comes with performance reporting tools, the Unity Pro skin and some additional features. This version still requires your company make less than $100,000/year, and it still displays a splash screen at launch.
    • Unity Pro: This is the highest tier available. It costs $125 per month and comes with useful Unity services, professional iOS and Android add-ons, and has no splash screen. There is no revenue cap either.

    There’s also an enterprise edition for large organizations that want access to the source code and enterprise support.

    Note: Recently Unity switched from a “perpetual” model, where you paid a one-time fee, to a subscription-based model. If you prefer the perpetual model, note that Unity will offer this payment option until the end of 2017.

    Under Unity Personal, click Download Now.

    personal-edition

    Give it a moment to download then double-click it to start the installation.

    Click through the installer until you reach the following screen where you select components:

    components

    Note: You can develop with Unity equally well on a Windows or Mac machine.

    The screenshots in this tutorial were made on Windows, because that is what the majority of Unity developers use (mainly because Windows is a more popular gaming platform).

    If you are developing on the Mac, your screenshots may look slightly different, but don’t worry — you should still be able to follow along with the tutorial just fine. Several of our tech editors are Mac users and have done exactly that! :]

    By default, you should select the Unity engine, Documentation and Standard Assets. Here’s why they are significant:

    • Unity Engine: This is the powerhouse that will drive all your games. When you update the engine, keep this — and only this — selected to avoid downloading unnecessary files. Don’t worry if your version number is slightly different than this screenshot, as Unity is constantly updating.
    • Documentation: This is your lifeline when you run into issues you don’t understand. Downloading the documentation frees you from reliance on the internet. Having it on hand is particularly helpful when traveling or dealing with unstable networks.
    • Standard Assets: These are additional objects that help you build games such as first-person and third-person character controllers, anti-aliasing and other useful items.

    If you plan on reading the book chapter about publishing your game, then make sure to check Android build support and iOS build support.

    Note: iOS build support will only work on macOS. For Android build support, you’ll need to download Android Studio. The chapter on publishing will cover all of this in detail.

    After you finish reading the book, you may find that you need additional platform support, such as tvOS build support. In that case, you just run the installer again, uncheck everything then check the required platforms. Follow the installer to completion to install those components.

    Run the program once installation completes. The first thing you’ll see is a dialog box asking for your Unity credentials.

    login

    If you don’t have an account, click create one and follow the steps. Unity accounts are free. You’ll have to log in every time you fire it up, but the engine does have an offline mode for those times when you have no network.

    Once you’re logged in, you’ll be presented with a project list that provides an easy place to access all of your projects. Since you don’t have any projects, click the New button.

    new-projects2

    You should be looking at the project creation dialog. You’ll notice that you have a few options, so fill them in as follows:

    new-project

    Here’s what everything on this screen means:

    • The Project name represents the internal name of the game. It’s not published with your final game, so you can name your projects whatever you like. Give this one the name Bobblehead Wars.
    • The Location field is where you’ll save the project and related items. Click the three dots in the Location field to choose a location on your computer.
    • The 3D option determines whether the game is 3D or 2D — it just configures the editor for that mode. You can switch between the two without starting a new project. For Bobblehead Wars, you want 3D.
    • The Add Asset Package button allows you to include additional assets in your game or any others you download from the Unity Asset Store. You don’t need to do anything with this for now.
    • Finally, you have the option to Enable Unity Analytics, which give you insight into your players’ experiences. By reading the data, you can determine areas where players struggle and make changes based on the feedback. The book will not delve into analytics, so set the switch to off.

    Once you’re ready, click the Create project button.

    Welcome to the world of Unity!

    Learning the Interface

    When your project loads, you’ll see a screen packed full of information. It’s perfectly normal to feel a little overwhelmed at first, but don’t worry — you’ll get comfortable with everything as you work through the first few chapters.

    Your layout will probably look like this:

    interface

    If not, click the Layout button in the top-right and select 2 by 3 from the dropdown.

    layout

    Each layout is composed of several different views. A view is simply a panel of information that you use to manipulate the engine. For instance, there’s a view made for placing objects in your world. There’s another view for you to play the game.

    Here’s what the interface looks like when broken down into individual views. Each red rectangle outlines a view that has its own purpose, interface and ways that you interact with it.

    interface-views

    Throughout the book, you’ll learn about many of these views. To see a list of all views, click the Window option on the menu bar.

    views

    The Unity user interface is completely customizable so you can add, remove, and rearrange views as you see fit.

    When working with Unity, you’ll typically want to rearrange views into a Layout that’s ideal for a given task. Unity allows you to save layouts for future use.

    In the Editor, look for the Game tab (the view to the lower right) and right-click it. From the drop-down, select Add Tab then choose Profiler.

    profiler

    The Profiler view lets you analyze your game while it’s running. Unfortunately, the profiler is also blocking the Game view, so you won’t be able to play the game while you profile it — not so helpful.

    Click and hold the Profiler tab and drag it to the Scene tab above.

    move-tab

    As you see, views can be moved, docked and arranged. They can also exist outside the editor as floating windows.

    To save the layout, select Window\Layouts\Save Layout… and name it Debugging.

    layout-name

    Whenever you need to access this particular layout, you can select the Layout button and choose Debugging.

    debugging

    You can also delete layouts. If you ever accidentally trash a stock layout, you can restore the default layouts.

    Organizing Your Assets

    Beginners to Unity might imagine that you develop your game from start to finish in Unity, including writing code, creating 3D models and textures, and so on.

    In reality, a better way of thinking about Unity is as an integration tool. Typically you will write code or create 3D models or textures in a separate program, and use Unity to wire everything together.

    For Bobblehead Wars, we’ve created some 3D models for you, because learning how to model things in Blender would take an entire book on its own! In this tutorial, you will learn how to import them into the game.

    But before you do, it pays to be organized. In this game, you’re going to have a lot of assets, so it’s critical to organize them in way that makes them easy to find.

    The view where you import and organize assets is called the Project Browser. It mimics the organization of your file system.

    assets

    In the Project Browser, select the Assets folder and click the Create button. Select Folder from the drop-down and name it Models.

    This will be home to all your models. You may feel tempted to create folders and manipulate files in your file system instead of the Project Browser. That’s a bad idea — do not do that, Sam I Am!

    Unity creates metadata for each asset. Creating, altering or deleting assets on the file system can break this metadata and your game.

    Create the following folders: Animations, Materials, Models, Prefabs, Scenes, Scripts and Textures.

    Your Project Browser should look like this:

    folder-list

    Personally, I find large folder icons to be distracting. If you also have a preference, you can increase or decrease the size by using the slider at the bottom of the Project Browser.

    slider

    Note: All the screenshots in the book will show the smallest setting.

    Importing Assets

    Now that you’ve organized your folders, you’re ready to import the assets for the game.

    To start, download the starter resources for this tutorial here.

    First, you’ll import the star of the show: the space marine.

    Open the resources folder and look for three files:

    1. BobbleMarine-Head.fbx
    2. BobbleMarine-Body.fbx
    3. Bobble Wars Marine texture.psd

    Drag these three files into the Models folder. Don’t copy BobbleWars.unitypackage: that comes later.

    What is an FBX file? FBX files typically contain 3D models, but they can also include textures and animations. 3D programs, such as Maya and Blender, allow you to export your models for import into programs such as Unity using this file format.

    Select the Models folder and you’ll see that you have a bunch of new files. Unity imported and configured the models for you and created a folder named Materials.

    first-import

    To keep things tidy, move Bobble Wars Marine texture from the Models folder to the Textures folder. Also move the contents of the newly generated Materials folder (in the Models folder) into the parent-level Materials folder, and then delete that new Materials folder by pressing delete (or command-delete on the Mac).

    What are materials? Materials provide your models with color and texture based upon lighting conditions. Materials use what are known as shaders that ultimately determines what appears onscreen. Shaders are small programs written in a specific shader language which is far beyond the score of this intro book. You can learn more about materials through Unity’s included documentation.

    Switch back to the Models folder and select BobbleMarine-Body. The Inspector view will now display information specific to that model as well as a preview.

    If you see no preview, then its window is closed. At the bottom of the Inspector, find a gray bar then drag it upwards with your mouse to expand the preview.

    model-preview

    The Inspector allows you to make changes to the model’s configuration, and it allows changes to any selected object’s properties. Since objects can be vastly different from one another, the Inspector will change context based on the object selected.

    Installing Blender

    At this point, you’ve imported the models and texture for the space marine. The models were in FBX format, and the texture was in PSD format.

    We supplied the space marine models to you in the FBX format, as this is a popular format for artists to deliver assets. But there’s another popular format you should understand how to use as well: Blender files.

    Unlike FBX, Blender files contain the source model data. This means you can actually edit these files inside Blender, and the changes will immediately take effect in Unity, unlike an FBX file.

    With an FBX, you’d need to export and re-import the model into Unity every time you change it.

    There is a small tradeoff for all this delicious functionality. For Unity to work with Blender files, you need Blender installed on your computer. Blender is free, and you’ll be happy to know that you’ll use it to make your own models in a few chapters.

    Download and install Blender from the following URL: https://www.blender.org/download/

    blender

    Note: Blender evolves at a rapid pace, so the version you see on your desktop will probably be different than this screenshot.

    After you install Blender, run the app and then quit. That’s it: you can now use Blender files with Unity.

    Importing Packages

    Now that you’ve installed Blender, you can now import the rest of the assets.

    The rest of the assets are combined into a single bundle called a Unity package. This is a common way that artists deliver assets for Unity, especially when you purchase them from the Unity store.

    Let’s try importing a package. Select Assets\Import Package\Custom Package…, navigate to your resources folder and select BobbleheadWars.unitypackage then click Open.

    You’ll be presented with a list of assets included in that package, all of which are selected by default. Note that some of these are Blender files, but there are also other files like textures and sounds as well. Click the Import button to import them into Unity.

    import-package

    The import will add a bunch of additional assets to your project. If you get a warning, just dismiss it.

    As you did before, to keep things tidy, single click the newly generated Materials folder (in the Models folder) and rename it to Models. Drag this new folder into the parent-level Materials folder.

    Adding Models to the Scene View

    At this point, you have imported everything into Unity. It’s time to start putting your game together, and you’ll kick it off by adding your models to the Scene view.

    The Scene view is where game creation happens. It’s a 3D window where you’ll place, move, scale and rotate objects.

    First, make sure to select the Scene view tab. Then, in the Project Browser, select BobbleArena from the Models subfolder and drag it into the Scene view.

    arena-add

    Check out the arena in the Scene view:

    scene-view

    Pretty cool, eh?

    The Scene view gives you a way to navigate your game in 3D space:

    • Right-click and rotate your mouse to look around.
    • Hold down the right mouse button and use the WASD keys to actually move through the scene.
    • Moving too slow? Give it some juice by holding down the Shift key.
    • Scroll with your mouse wheel to zoom.
    • Press your mouse wheel and move your mouse to pan.

    By default, the view displays everything with textures in a shaded mode. You can switch to other viewing modes such as wireframes or shaded wireframe.

    Let’s try this out. Just underneath the Scene tab, click the Shaded dropdown and select Wireframe. Now you’ll see all your meshes without any textures, which is useful when you’re placing meshes by eye.

    wireframe

    Switch the Scene view back to Shaded textures.

    In the Scene view, you’ll notice a gizmo in the right-hand corner with the word Persp underneath it. This means the Scene view is in perspective mode; objects that are closer to you appear larger than those that are farther away.

    perspective

    Clicking on a colored axis will change your perspective of the scene. For example, click the green axis and the Scene view will look down from the Y-axis. In this case, the Persp will read Top because you’re looking at the world from that perspective. How’s it feel to be on top of the world? :]

    y-axis

    Clicking the center box will switch the view into Isometric mode aka Orthographic mode. Essentially, objects are the same size regardless of their proximity to you.

    iso

    To return to Perspective mode, simply click the center box again. You’ll learn more about Isometric mode later in the book.

    Adding the Hero

    At this point, you have the arena set up, but it’s missing the guest of honor!

    To fix this, in the Project Browser find and open the Models folder then drag BobbleMarine-Body into the Hierarchy view.

    hierarchy

    In Unity, games are organized by scenes. For now, you can think of a scene as a level of your game. The Hierarchy view is a list of all objects that are currently present in the scene.

    Note that your scene already contains several objects. At this point, it contains your arena, the space marine, and two default objects: the main camera and a directional light.

    With the marine body still selected, hover the mouse over the Scene view and press the F key to zoom to the marine. This shortcut is useful when you have many objects in your scene, and you need to quickly get to one of them.

    f-key

    Don’t worry if your space marine isn’t placed at this exact position. You’ll fix that later.

    While the space marine’s dismembered body is pretty intimidating, he’s going to have a hard time seeing and bobbling without a head!

    Drag the BobbleMarine-Head from the Project Browser into the Hierarchy. Chances are, the head will not go exactly where you’d hope.

    marine-head

    Select the head in the Hierarchy to see its navigation gizmos. By selecting and dragging the colored arrows, you can move the head in various directions.

    head

    The colored faces of the cube in the middle of the head allow you to move the object along two axes at the same time. For example, selecting and dragging the red face — the x-axis — allows you to move the head along the y- and z-axes.

    You can use the toolbar to make other adjustments to an object. The first item is the hand tool. This allows you to pan the Scene and is equivalent to holding down the middle mouse button.

    toolbar_hand

    Select the position tool to see the position gizmo that lets you reposition the selected object.

    toolbar_position

    Use the rotate tool to rotate the selected object.

    toolbar_rotate

    The scale tool allows you to increase and decrease the size of an object.

    toolbar_scale

    The rect tool lets you rotate, scale and reposition sprites. You’ll be using this when working with the user interface and Unity 2D.

    toolbar_rect

    Using the aforementioned tools, tweak the position of the helmet so it sits on the neck. Also, see if you can move the space marine so he’s centered in the arena. In the next chapter, you’ll position these precisely with the Inspector. When done, the marine should look like this:

    space-marine

    After positioning the space marine’s head, select File\Save Scene. Unity will present you with a save dialog. Name the scene Main, and after you finish creating it drag the file to the Scenes folder.

    Note: Unity does not autosave and unfortunately can be a little bit “crashy” at times. Make sure to save early and often. Otherwise, you will lose your work (and possibly your sanity).

    Where to Go From Here?

    You can download the completed project for this tutorial here.

    You should keep on reading to the second part of this tutorial series, available tomorrow, where you’ll get to add some creepy-crawly enemies and learn how to work with Prefabs and GameObjects!

    If you’re enjoying this tutorial series and want to learn more, you should definitely check out Unity Games by Tutorials.

    The book teaches you everything you need to know about building games in Unity, whether you’re a beginner or a more experienced game developer. In the book, you’ll build four great games:

    • A 3D twin-stick shooter
    • A classic 2D platformer
    • A 3D tower-defense game (with virtual reality mode!)
    • A first-person shooter

    The book is still in development, but here’s a preview of the first game you’ll build in the book:

    If you have questions or comments on this tutorial, please leave them in the discussion below!

    The post Unity Tutorial Part 1: Getting Started appeared first on Ray Wenderlich.

    iOS 10 Screencast: Introducing DateInterval

    Unity Tutorial Part 2: GameObjects

    $
    0
    0

    Unity-1-feature
    Welcome to the second part of this Unity tutorial mini-series! In this part, you’ll learn all about GameObjects in Unity while you give your hero some creepy-crawly aliens to keep him company!

    This tutorial continues on from Unity Tutorial Part 1: Getting Started. You can continue on with your completed project from the last chapter, or if you would prefer to start over fresh, you can download the starter project for this tutorial here.

    Getting Started

    GameObjects represent pretty much all elements in Unity: your player, the aliens, bullets on the screen, the actual level geometry — basically, everything in the game itself.

    Just like the Project Browser contains all assets, the Hierarchy contains a list of GameObjects in your scene.

    If you don’t have your project open, open it now in Unity.

    Note: Unity’s way of opening project files is a bit strange. You can navigate your file system and look for a scene file. Double-click the scene, then Unity will open your project with the current scene selected.

    Or, if you start Unity or click File\Open Project, you’ll see a project list. Select the desired project and Unity will take care of the rest.

    If your project isn’t listed, click the Open button to bring up a system dialog box. Instead of searching for a particular file, try navigating to the top-level directory of your Unity project and click Select Folder. The engine will detect the Unity project within the folder and open it.

    Once your project is open, take a look at your Hierarchy and count the GameObjects.

    gameobjects-count

    Your first thought may be three because you added three GameObjects in the last chapter: arena, space marine body and space marine head.

    However, there are two other GameObjects: Main Camera and Directional Light. Remember how Unity creates these by default? Yes, these are also GameObjects.

    Yet, there are even more GameObjects. You’ll notice that there are disclosure triangles to the left of the GameObjects you imported.

    Holding down the Alt button on PC or Option on Mac, click each disclosure triangle.

    disclosure

    As you can see, you have a pile of GameObjects:

    lots-of-gameobjects

    There’s three important points to remember about GameObjects:

    • GameObjects can contain other GameObjects. On a base level, this useful behavior allows organizing and parenting of GameObjects that are related to each other. More importantly, changes to parent GameObjects may affect their children — more on this in just a moment.
    • Models are converted into GameObjects. Unity creates GameObjects for the various pieces of your model that you can alter like any other GameObject.
    • Everything contained in the Hierarchy is a GameObject. Even things such as cameras and lights are GameObjects. If it’s in the Hierarchy, it’s a GameObject that’s subject to your command.

    Our hero is so bored that he’s picking his nose with his gun. You need to get him moving, but first, you need to reposition your GameObjects.

    Moving GameObjects

    Before starting, collapse all the GameObject trees by clicking the disclosure triangles.

    Select BobbleArena in the Hierarchy and take a moment to observe the Inspector, which provides information about the selected GameObject.

    GameObjects contain a number of components, which you can think of as small units of functionality. There is one component that all GameObjects contain: the Transform component.

    inspector

    The Transform component contains the position, rotation, and scale of the GameObject. Using the inspector, you can set these to specific numbers instead of having to rely upon your eyeballs. When hovering the mouse over the axis name, you’ll see arrows appear next to the pointer.

    Press the left mouse button and drag the mouse either left or right to adjust those numbers. This trick is an easy way to adjust the values by small increments.

    With BobbleArena selected, set Position to (X:-6.624, Y:13.622, Z:6.35). As I developed this game, the arena ended up in this position. You could just as well place it in the center of the game of the game world.

    Set the Scale to (X:2.0, Y:2.0, Z:2.0). This gives the player more room to navigate the arena.

    arena-setting

    If you zoom out of the Scene view, you’ll probably notice the space marine is suspended in the void; mostly likely, he’s questioning his assumptions about gravity. You could move his head and then his body, but your life will be much easier if you group his body parts into one GameObject.

    In the Hierarchy, click the Create button and select Create Empty.

    create-empty

    An empty is a GameObject that has only the one required component of all GameObjects — the Transform component.

    Note: You can also create an empty GameObject by clicking GameObject\Create Empty. This goes for other things such as components. There is no “preferred” way to do things — go with whatever works best for your workflow.

    Parenting the Space Marine

    In the Hierarchy, you’ll see your new GameObject creatively named: GameObject. Single-click the GameObject and name it SpaceMarine.

    You can insert spaces in GameObjects’ names, e.g., Space Marine. However, for the sake of consistency, you’ll use camel case for names in this book.

    Drag BobbleMarine-Body and BobbleMarine-Head into the SpaceMarine GameObject.

    A few things happen when you parent GameObjects. In particular, the position values for the children change even though the GameObjects don’t move. This modification happens because GameObject positions are always relative to the parent GameObject.

    parented-objects

    Select the SpaceMarine in the Hierarchy. Go to the Scene view and press F to focus on it. Chances are, the arena is blocking your view.

    Thankfully, you don’t need to get Dumbledore on speed dial. You can make it disappear yourself! Select BobbleArena in the Hierarchy, and in the Inspector, uncheck the box to the left of the GameObject’s name. This will make the arena disappear.

    disable

    You only should see the hero now. Select the SpaceMarine GameObject. In the Inspector, mouse over the X position label until you see the scrubber arrows. Hold the left mouse button and move your mouse left or right. Notice how all the GameObjects move relative to the parent.

    As you can see, having parents does have its advantages. No offense to any parentless deities out there.

    god

    When you parent one GameObject in another, the position of the child GameObject won’t change. The difference is the child GameObject is now positioned relative to the parent. That is, setting the child to (0, 0, 0) will move the child to the center of the parent versus the center of the game world.

    You’ll do this now to assemble your marine.

    Select BobbleMarine-Body, and in the Inspector, set Position to (X:0, Y:0, Z:0). Go select BobbleMarine-Head and set Position to (X:-1.38, Y:6.16, Z:1.05) in the Inspector.

    Congratulations! Your hero is assembled.

    Positioning the Marine

    Now to it’s time to place the space marine in his proper starting position. Select BobbleArena, and in the Inspector, check the box next to the name to reenable it.

    Select SpaceMarine, and in the Inspector, set its position to (X:-4.9, Y:12.54, Z:5.87). Also, set the rotation to (X:0, Y:0, Z:0). Your marine should end up directly over the hatch. If this isn’t the case, then feel free to tweak the values until that is the case.

    Once the hero is in place, press F in the Scene view so you can see him standing proudly.

    final-position

    The hero should now be positioned precisely over the elevator, ready to rock. Unfortunately for him, his grandiose rock party will soon degrade into a bug hunt.

    Creating Prefabs

    This game features creepy crawly bugs, and like the hero, they’re composed of many pieces — some assembly required.

    In the Hierarchy, click the Create button and select Create Empty from the drop-down. Single-click the GameObject to name it Alien.

    Select Alien in the Hierarchy, and in the Inspector, set the position to: (X:2.9, Y:13.6, Z:8.41).

    From the Project Browser, drag BobbleEnemy-Body from the Models folder into the Alien GameObject.

    add-body

    Set BobbleEnemy-Body Position to(X:0, Y:0, Z:0). Now the alien and hero should be side by side in the arena.

    side-by-side

    As creepy as the alien is without a head, the hero needs more to shoot at than that spindly little frame. From the Project Browser, drag BobbleEnemy-Head into the Alien GameObject. Set Position to (X:0.26, Y:1.74, Z:0.31), Rotation to (X:-89.96, Y:0, Z:0) and Scale to (X:100, Y:100, Z:100).

    alien-head-values

    That’s one fierce little bug. They go together so well that you could mistake them for the next superstar crime-fighting duo.

    buddy-cop-movie

    At this point, you have one parent GameObject for the hero and another for the alien. For the hero, this works great because you need only one. For the alien, you’re going to need many — so, so many.

    You could copy and paste the alien to make clones, but they’d all be individuals. If you needed to make a change to the alien’s behavior, you’d have to change each instance.

    For this situation, it’s best to use a prefab, which is a master copy that you use to make as many individual copies as you want. Prefabs are your friend because when you change anything about them, you can apply the same to the rest of the instances.

    Making a prefab is simple. Select the Alien GameObject and drag it into the Prefabs folder in the Project Browser.

    prefab

    A few things changed: there’s a new entry in your Prefabs folder with an icon beside it. You’ll also note the name of the GameObject in the Hierarchy is now blue:

    new-prefab

    Note: You don’t have to drag your model into that specific folder to create a prefab — all that’s required is dragging a GameObject into any folder in the Project Browser. Having a Prefabs folder is simply good housekeeping.

    The blue indicates the GameObject has been either instanced from a prefab or a model, such as the BobbleArena. Select the Alien GameObject in the Hierarchy and look at the Inspector; you’ll notice some additional buttons:

    prefab-options

    Here’s the breakdown of these new buttons:

    • Select will select the prefab inside the Project Browser. This is useful when you have lots of files and want easy access to the prefab to make changes.
    • Revert will undo changes you’ve made to your instance. For example, you might play around with size or color but end up with something horrible, like a viciously pink spider. You’d click the Revert button to restore sanity.
    • Apply will apply any changes you made to that instance to its prefab. All instances of that prefab will be updated as well.

    Creating a prefab instance is quite easy. Select the Alien prefab in the Project Browser and drag it next to your other Alien in the Scene view.

    make-a-prefab

    You can also drag an instance to the Hierarchy. As you can see, creating more aliens is as easy as dragging the Alien prefab from the Project Browser. But you don’t need droves of aliens yet, so delete all the Aliens from the Hierarchy. You delete a GameObject by selecting it in the Hierarchy, and pressing Delete on your keyboard, (Command–Delete on a Mac), or you can right-click it and select Delete.

    Fixing the Models

    The next to-do is fixing some of your models. In this case, Unity imported your models but lost references to the textures.

    In the Models folder of your Project Browser, drag a BobbleArena-Column into the Scene view. You’ll find a dull white material.

    textureless-column

    If a material name or texture name changes in the source package, Unity will lose connection to that material. It tries to fix this by creating a new material for you that has no textures attached to it.

    To fix this, you have to assign a new texture to the material. In the Project Browser, select the Models subfolder and then, expand the BobbleArena-Column to see all the child objects.

    fix-model1

    Next, select Cube_001 in the Project Browser, and in the Inspector, click the disclosure triangle for the Main_Material shader.

    fix-model2

    You’ll see that there are a lot of options! These options configure how this material will look.

    materials

    For example, the Metallic slider determines the metal-like quality of the material. A high value metallic value means the texture will reflect light much like metal. You’ll notice a grey box to the left of most of the properties. These boxes are meant for textures.

    In this case, all you want is a an image on your model. In the Project Browser, select the Textures folder. Click and drag the Bobble Wars Marine texture to the Albedo property box located in the shader properties.

    fix-model3

    The Albedo property is for textures, but you can put colors there are well. Once you do this, your columns will now have a texture.

    textured-column

    The arena also suffered a texture mishap. In the Hierarchy, expand the BobbleArena and then expand Floor. Select the Floor Piece.

    floor-piece

    In the Inspector, you’ll notice two materials attached to the floor piece. The BobbleArena-Main_Texture material does not have a texture assigned to it. You can tell because the material preview is all white.

    material-preview

    Like you did for the column, select the Textures folder in the Project Browser. Click and drag the Bobble Wars Marine texture to the Albedo property box located in the shader properties.

    Your floor will now acquire borders. How stylish!

    floor

    You’ll also notice that not just one, but all floor sections acquired borders. This is because they all use the same material.

    Adding Obstacles

    Now, that you have your models fixed, it’s time add a bunch of columns to the arena. You’ll make a total of seven columns, and you’ll use prefabs for this task.

    Note: Whenever it seems like you should make a duplicate of a GameObject, use a prefab instead — it’s another best practice. Some Unity developers insist on using prefabs for everything, even unique objects.

    The thinking is that it’s much easier to create a prefab and make duplicates than it is to turn a group of existing GameObjects into prefab instance. The former method requires minimal work whereas the latter requires you to extract the commonalities into a prefab while maintaining any unique changes for each instance. This results in a lot of work.

    In the Hierarchy, drag the BobbleArena-Column into your Prefabs folder to turn it into a prefab. With BobbleArena-Column instance still selected in the Hierarchy View, go to the Inspector and set position to (X:1.66, Y:12.83, Z:-54.48). Set scale to (X:3.5, Y:3.5, Z:3.5). You do want all the prefabs to be the same scale, so click the Apply button.

    column-position

    Now it’s time for you to make the rest of the columns. Dragging one column at a time from project to project in the Scene view can be a little tedious, especially when there are several instances. Duplicate a column by selecting one in the Hierarchy and pressing Ctrl–D on PC or Command–D on Mac.

    Create a total of six duplicates and give them following positions:

    • Column 1: (X:-44.69, Y:12.83, Z:-28.25)
    • Column 2: (X:42.10, Y:12.83, Z:30.14)
    • Column 3: (X:-8.29, Y:12.83, Z:63.04)
    • Column 4: (X:80.40, Y:12.83, Z:-13.65)
    • Column 5: (X:-91.79, Y:12.83, Z:-13.65)
    • Column 6: (X:-48.69, Y:12.83, Z:33.74)

    You should now have seven columns in the arena.

    column-position4

    The arena looks good, but the Hierarchy is a bit messy. Tidy it up by clicking the Create button and select Create Empty. Rename the GameObject to Columns and drag each column into it.

    total-columns

    You’ll notice the columns have a similar name with unique numbers appended to them. Since they essentially act as one entity, it’s fine for them to share a name. Hold the Shift key and select all the columns in the Hierarchy. In the Inspector, change the name to Column.

    change-name

    Note: As you can see, it’s possible to change a common property for a bunch of GameObjects at once.

    Creating Spawn Points

    What good are bloodthirsty aliens unless they spawn in mass quantities? In this section, you’ll set up spawn points to produce enemies to keep our hero on his toes.

    So far, you’ve assembled the game with GameObjects that you want the player to see. When it comes to spawn points, you don’t want anybody to see them. Yet, it’s important that you know where they are.

    You could create a 3D cube and place it in your scene to represent a spawn point, then remove it when the game starts, but that’s a clunky approach.

    Thankfully, Unity provides a simpler mechanism called labels. These are GameObjects that are visible in the Scene view, but invisible during gameplay.

    To see them in action, you’ll create a bunch of different spawn points similar to how you created the columns.

    Click the Create button in the Hierarchy and select Create Empty. Give it the name Spawn and set position to (X:-5.44, Y:13.69, Z:90.30).

    In the Inspector, click the colored cube next to the checkmark. A flyout with all the different label styles will appear. Click blue capsule.

    label-styles

    Look at your Scene view; you’ll see it’s been annotated with the Spawn point.

    spawn-point

    You need to create ten more spawn points. Make placement easier by doing the following:

    1. In the Scene view, click on the center cube of the scene gizmo to switch the Scene view to Isometric mode.
    2. Click the green y-axis arrow so that you look down on the scene.

    gizmo

    Now duplicate and reposition ten more spawn points, according to the following image:

    spawn-points

    Don’t worry if you don’t get them exactly the same — game design is more of an art than a science!

    Once you’re done, click the Create button in the Hierarchy, select Create Empty and name it SpawnPoints. Drag all the spawn points into it. Batch rename them like you did with the columns to Spawn.

    spawn

    Congratulations! Your game is now properly set up. Make sure to save!

    Where to Go From Here?

    You can download the completed project for this tutorial here.

    At this point, you have your hero, his enemy the alien, and the arena in which they will battle to the death. You’ve even created spawn points for the little buggers. As you set things up, you learned about the following:

    • GameObjects and why they are so important when working with Unity.
    • Prefabs for when you want to create many instances of a single GameObject.
    • Labels to help you annotate game development without interfering with the game.

    In the next section of this tutorial mini-series, you’ll add some action to this game, learn how to work with Components and let your space marine fire away at will!

    If you’re enjoying this tutorial series and want to learn more, you should definitely check out Unity Games by Tutorials.

    The book teaches you everything you need to know about building games in Unity, whether you’re a beginner or a more experienced game developer. In the book, you’ll build four great games:

    • A 3D twin-stick shooter
    • A classic 2D platformer
    • A 3D tower-defense game (with virtual reality mode!)
    • A first-person shooter

    The book is still in development, but here’s a preview of the first game you’ll build in the book:

    If you have questions or comments on this tutorial, please leave them in the discussion below!

    The post Unity Tutorial Part 2: GameObjects appeared first on Ray Wenderlich.

    Readers’ App Reviews – August 2016

    $
    0
    0

    Review-2016-July-feature

    Like clockwork, another month has marched by. That brings us closer to all the goodies Apple will hopefully share with us this fall. I’m sure we’re all getting excited for a new iPhone, an updated MacBook, and maybe even a surprise or two.

    But for me, August has brought another swarm of great apps and games from our readers. :] We write our tutorials for you and its exciting for us to see them put to use in some fantastic apps.

    I’ve tried out all the ones sent to me and I’ve picked just a few to share with you. As always, I don’t have time to write about them all, so make sure you check out the honorable mentions too.

    This month we have:

    • Photo and Video editors that make it fun
    • An app for the Pokemon trainers among us
    • Apps to help you travel anywhere
    • And of course, much more!

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

    GoTypeChart

    GoTypeChart
    Pokemon Go has swept the world, and that means the competition couldn’t be higher. To gain the edge you’ll need to know everything there is about your Pokemon and their abilities. The GoTypeChart can help with that. It has a ton of information on each and every Pokemon from Pokemon Go.

    GoTypeChart lets your search for Pokemon by type, name, move type, index, attack damage, defense, and stamina. Each move is listed with its DPS and type. You can easily find just the right attack to give you the edge. Or you can easily look for fire Pokemon to battle the grass type.

    GoTypeChart also makes it easy to browse Pokemon, their abilities, and their attributes. So it’s easy to find new Pokemon to add to your list to catch to improve your battles.

    AnyMap

    AnyMap
    AnyMap is a very cool custom map application that allows you to get all the benefits we’re used to with regular iPhone maps but while using your custom map. Maybe it’s a trail map or a city landmark map. You can continue to use your custom map while taking advantage of GPS, pinch to zoom, and more.

    AnyMap just needs a picture of the mall you’d like. Then you orient it by walking to a few easy to find landmarks. Now AnyMap knows how to navigate your custom map. You can now easily see where you are on the map at any time as you move around. It doesn’t even require cell service now that it’s synced your map to GPS coordinates.

    Can’t Eat That

    CantEatThat
    Food allergies are a common problem for many people. It may be manageable at home but when you go out it can be hard to find a safe entree. Now imagine being in another country without being a native speaker! Thank goodness for Can’t Eat That, an app that will help you communicate your food allergies in a variety of languages.

    Can’t Eat That lets you select your food allergy and then a language you need to express it in. You can then show the app to your waiter in their native language and they’ll be able to help you find something safe to eat. The app can even read the translation aloud if necessary. Can’t Eat That could be a truly life saving app depending on how severe your allergy may be. You can finally travel and try new foods without fear.

    Crop-Size

    CropSize
    Crop-Size is a photo editing app with some powerful features to make it a step above the rest. It has all the expected features like resizing, cropping, filters, and color correction. But it takes a few of those features to the next level.

    While resizing a photo, you can choose from a ton of preset sizes common for photos. You can input exact sizes to the pixel. You can also choose between cropping, stretching, or a border when resizing the photo. Cropping has easy custom controls, pixel precise inputs, and tons of common presets. Rotation is even a breeze. All the filters, controls, and effects you’d expect are available as well. You can even edit full metadata and choose which data is exported to exercise full control over your private data.

    The best feature of all is the ability to save your edits as a template. After you finish getting an image just right, you can save all your crops, filters, and metadata changes to a template. That template can be used on future photos or on large batches all at once.

    What could be better than large batch processing right on your iPhone? Editing in the field has never been so good.

    Coffee Phone

    CoffeePhone
    Coffee Phone is a unique social network based entirely around coffee. Having a coffee alone wishing you could meet some new people? You can offer to buy a stranger a coffee if they’ll come enjoy it with you.

    Anyone can open the app and see available coffees near them. So if you’re looking for a coffee to meet new people or looking to meet new people by offering a coffee you can easily find someone nearby.

    The conversation is up to you, but you already know you both like coffee. ;] So next time you’re relaxing and looking to meet someone knew, grab a coffee and offer one to your next friend.

    Tandem – Medication Companion

    Tandem
    Tandem is an app for those of us with scheduled medications. Sometimes life is just too busy to remember our medication but often it’s very important we take our pills at the right time. Tandem is here to help us by reminding us to take the right medication at the right time.

    Tandem starts by asking you for the medications you need to track as well as dosages in case you may forget that as well. It will ask you about your dosage schedule. From there it can handle the rest. You’ll get a notification when it’s time to take it and you can even mark it as taken right from the lock screen.

    But if you need a little extra motivation, Tandem has a special feature just for you. You can invite a friend or family member to be your companion. Tandem will text your companion when it’s time to take your medicine. They can reply straight to the text message and you’ll get it in Tandem as an extra reminder. And when you mark your medication as taken, Tandem will also let your companion know. The companion doesn’t need Tandem at all. They can help remind you with simple text messages.

    VSM – Video Subtitle Maker

    VSM
    No more boring videos for you! Video Subtitle Maker will help you spice up your videos.

    Video Subtitle Maker makes it easy to add a ton of effects to your videos. You can add a subtitle with tons of font options, colors, and size. You can even use emoji in your subtitle. But Video Subtitle Maker isn’t just about subtitles. You can easily add a caption or floating text. You can add stickers, artwork, watermarks, or even your own photo overlays.

    Video Subtitle Maker also makes it easy to add background music to make you video epic. Or its just as easy to add sound effecst to bring your video to life. There are tons of built in sound effects like bubbles, censors, or popular quotes like THIS IS SPARTA!!!

    Video Subtitle Maker makes it easy to add all these things to your video. You can easily edit your video right on your iPhone then share it with the world.

    Snapwit

    Snapwit
    First impressions can be hard. But I’m pretty sure a video of your face in a cartoon is a great way to break the ice.

    Snapwit has tons of cartoon overlays it calls MOJIs. You can record your face inside the box and boom there is a video of you as a cartoon super hero. There are tons to choose from monkeys to construction workers to cavemen. It couldn’t be easier. Choose your MOJI, align your face, and record your message. Snapwith makes it quick and easy to share with everyone.

    There are also plenty of video greetings you can create as well. These are more traditional effects and overlays like Happy Birthday, Invitations, or film borders. They are just as easy to create and share as the MOJIs right on your phone.

    Honorable Mentions

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

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

    super meow cat
    Deep Sleep Fan – White Noise for Bedtime
    toGETher Tasks Done GOLD – Eisenhower Matrix Planner
    Hungry Hipster
    Tap Tap Go!
    Boston Truck Tracker
    BalloonPop99
    Budge
    Molecular
    Tagalot Cards
    Sky Up

    Where To Go From Here?

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

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

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

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

    Learning Unity, and Neural Networks on iOS – Podcast S06 E07

    $
    0
    0
    learn unity

    Always wanted to learn Unity but didn’t know where to start? Find out in the episode!

    Join Mic, Jake, and Brian as they discuss how to best learn Unity and what resources are available, before moving on to chat about neural networks and some brand new APIs provided by Apple to make leveraging them a little easier.

    [Subscribe in iTunes] [RSS Feed]

    Our Sponsor

    Hired is the platform for the best iOS developer jobs.

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

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

    Plus you will receive a $2000 bonus from Hired if you find a job through the platform, just for signing up using the show’s exclusive link.

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

    Show Notes

    Contact Us

    Where To Go From Here?

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

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

    The post Learning Unity, and Neural Networks on iOS – Podcast S06 E07 appeared first on Ray Wenderlich.

    Viewing all 4373 articles
    Browse latest View live


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