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

Video Tutorial: CALayers Part 4: Conclusion


Instruments Tutorial with Swift: Getting Started

$
0
0
Learn how to troubleshoot and optimize your code with Xcode Instruments!

Learn how to troubleshoot and optimize your code with Xcode Instruments!

Update note: This tutorial was updated to iOS 8 and Swift by James Frost. Original post was by Tutorial Team member Matt Galloway.

Whether you’ve worked on many iOS apps or are still getting started with your first: you are no doubt coming up with new features and otherwise wondering what you can do to make your apps even better.

Besides improving your app by adding features though, there is one thing that all good app developers should do… instrument their code!

This tutorial will show you how to use the most important features of the tool called Instruments that ships with Xcode. It allows you to check your code for performance issues, memory issues, reference cycles, and other problems.

In this tutorial you’re going to learn:

  • How to determine hot-spots in your code using the Time Profiler instrument in order to make your code more efficient, and
  • How to detect and fix memory management issues such as strong reference cycles in your code using the Allocations instrument.

Note: This tutorial assumes that you are competent in Swift and iOS programming. If you are a complete beginner to iOS programming, you may wish to check out some of the other tutorials on this site. This tutorial makes use of a storyboard, so make sure you’re familiar with the concept; a good place to start is with the tutorial on this site.

All set? Get ready to dive into the fascinating world of Instruments! :]

Getting Started

For this tutorial you won’t go through the process of creating an application from scratch; instead, a sample project has been provided for you. Your task is to go through the application and improve it using Instruments as your guide — very similar to how you would go about optimizing your own apps!

Download the starter project then unzip it and open it up in Xcode.

This sample app uses the Flickr API to search for images. To use the API you’ll need an API key. For demo projects, you can generate a sample key on Flickr’s website. Just perform any search at: http://www.flickr.com/services/api/explore/?method=flickr.photos.search and copy the API key out of the URL at the bottom – it follows the “&api_key=” all the way to the next “&”.

For example, if the URL is:
http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=6593783 efea8e7f6dfc6b70bc03d2afb&format=rest&api_sig=f24f4e98063a9b8ecc8b522b238d5e2f
Then the API key is: 6593783efea8e7f6dfc6b70bc03d2afb.

Paste it into the top of the FlickrSearcher.swift file, replacing the existing API key.

Note that this sample API key is changed every day or so, so you’ll occasionally have to regenerate a new key. The app will alert you whenever the key is no longer valid.

Build and run the app, perform a search, click the result, and you’ll see something like the following:

The starter project for this tutorial

Browse through the application and check out the basic functions. You might be tempted to think that once the UI looks great the app is ready for store submission. However, you’re about to see the value that using Instruments can add to your app.

The remainder of this tutorial will show you how to find and fix the issues that still exist in the app. You’ll see how Instruments can make debugging problems a whole lot easier! :]

Time for Profiling

The first instrument you’ll look at is the Time Profiler. At measured intervals, Instruments will halt the execution of the program and take a stack trace on each running thread. Think of it as pressing the pause button in Xcode’s debugger.

Here’s a sneak preview of the Time Profiler:

Time Profiler - Call Tree

This screen displays the Call Tree. The Call Tree shows the amount of time spent executing in various methods within an app. Each row is a different method that the program’s execution path has followed. The time spent in each method can be determined from the number of times the profiler is stopped in each method.

For instance, if 100 samples are done at 1 millisecond intervals, and a particular method is found to be at the top of the stack in 10 samples, then you can deduce that approximately 10% of the total execution time — 10 milliseconds — was spent in that method. It’s a fairly crude approximation, but it works!

Note: In general, you should always profile your app on an actual device, instead of the simulator. The iOS simulator has all of the horsepower of your Mac behind it, whereas a device will have all of the limitations of mobile hardware. Your app may seem to run just fine in the simulator, but you might discover a performance issue once it’s running on a real device.

So without any further ado, time to get instrumenting!

From Xcode’s menu bar, select Product\Profile, or press ⌘I. This will build the app and launch Instruments. You will be greeted with a selection window that looks like this:

Profiling Template Selection

These are all different templates that come with Instruments.

Select the Time Profiler instrument and click Choose. This will open up a new Instruments document. Click the red record button in the top left to start recording and launch the app. You may be asked for your password to authorize Instruments to analyze other processes — fear not, it’s safe to provide here! :]

In the Instruments window, you can see the time counting up, and a little arrow moving from left to right above the graph in the center of the screen. This indicates that the app is running.

Now, start using the app. Search for some images, and drill down into one or more of the search results. You have probably noticed that going into a search result is tediously slow, and scrolling through a list of search results is also incredibly annoying – it’s a terribly clunky app!

Well, you’re in luck, for you’re about to embark on fixing it! However, you’re first going to get a quick run down on what you’re looking at in Instruments.

First, make sure the view selector on the right hand side of the toolbar has both options selected, like so:

Instruments - View Selector

That will ensure that all panels are open. Now study the screenshot below and the explanation of each section beneath it:

Instruments Main Window

  1. These are the recording controls. The red ‘record’ button will stop & start the app currently being profiled when it is clicked (it toggles between a record and stop icon). The pause button does exactly what you’d expect and pauses the current execution of the app.
  2. This is the run timer. The timer counts how long the app being profiled has been running, and how many times it has been run. If you stop and then restart the app using the recording controls, that would start a new run and the display would then show Run 2 of 2.
  3. This is called a track. In the case of the Time Profiler template you selected, there’s just one instrument so there’s just one track. You’ll learn more about the specifics of the graph shown here later in the tutorial.
  4. This is the detail panel. It shows the main information about the particular instrument you’re using. In this case, it’s showing the methods which are “hottest” — that is, the ones that have used up the most CPU time.

    If you click on the bar at the top which says Call Tree (the left hand one) and select Sample List, then you are presented with a different view of the data. This view is showing every single sample. Click on a few samples, and you’ll see the captured stack trace appear in the Extended Detail inspector.

  5. This is the inspectors panel. There are three inspectors: Record Settings, Display Settings, and Extended Detail. You’ll be learning more about some of these options shortly.

Now onto fixing the clunky UI! :]

Drilling Deep

Perform an image search, and drill into the results. I personally like searching for “dog”, but choose whatever you wish – you might be one of those cat people! :]

Now, scroll up and down the list a few times so that you’ve got a good amount of data in the Time Profiler. You should notice the numbers in the middle of the screen changing and the graph filling in; this tells you that CPU cycles are being used.

You really wouldn’t expect any UI to be as clunky as this; no table view is ready to ship until it scrolls like butter! To help pinpoint the problem, you need to set some options.

On the right hand side, select the Display Settings inspector (or press ⌘+2). In the inspector, under the Call Tree section, select Separate by Thread, Invert Call Tree, Hide Missing Symbols and Hide System Libraries. It will look like this:

Time Profiler Call Tree Settings

Here’s what each option is doing to the data displayed in the table to the left:

  • Separate by Thread: Each thread should be considered separately. This enables you to understand which threads are responsible for the greatest amount of CPU use.
  • Invert Call Tree: With this option, the stack trace is considered from top to bottom. This is usually what you want, as you want to see the deepest methods where the CPU is spending its time.
  • Hide Missing Symbols: If the dSYM file cannot be found for your app or a system framework, then instead of seeing method names (symbols) in the table, you’ll just see hex values corresponding to addresses inside the binary. If this option is selected, then only fully resolved symbols are displayed and the unresolved hex values are hidden. This helps to declutter the data presented.
  • Hide System Libraries: When this option is selected, only symbols from your own app are displayed. It’s often useful to select this option, since usually you only care about where the CPU is spending time in your own code – you can’t do much about how much CPU the system libraries are using!
  • Flatten Recursion: This option treats recursive functions (ones which call themselves) as one entry in each stack trace, rather than multiple.
  • Top Functions: Enabling this makes Instruments consider the total time spent in a function as the sum of the time directly within that function, as well as the time spent in functions called by that function. So if function A calls B, then A’s time is reported as the time spent in A PLUS the time spent in B. This can be really useful, as it lets you pick the largest time figure each time you descend into the call stack, zeroing in on your most time-consuming methods.
  • If you’re running an Objective-C app, there’s also an option of Show Obj-C Only: If this is selected, then only Objective-C methods are displayed, rather than any C or C++ functions. There are none in your program, but if you were looking at an OpenGL app, it might have some C++, for example.

Although some values may be slightly different, the order of the entries should be similar to the table below once you have enabled the options above:

Slow Scrolling Call Tree

Well, that certainly doesn’t look too good. The vast majority of time is spent in the method that applies the ‘tonal’ filter to the thumbnail photos. That shouldn’t come as too much of a shock to you, as the table loading and scrolling were the clunkiest parts of the UI, and that’s when the table cells are constantly being updated.

To find out more about what’s going on within that method, double click its row in the table. Doing so will bring up the following view:

Drill Into Filter

Well that’s interesting, isn’t it! applyTonalFilter() is a method added to UIImage in an extension, and almost 100% of the time spent in it is spent creating the CGImage output after applying the image filter.

There’s not really much that can be done to speed this up: creating the image is quite an intensive process, and takes as long as it takes. Let’s try stepping back and seeing where applyTonalFilter() is called from. Click Call Tree in the breadcrumb trail at the top of the code view to get back to the previous screen:

Call Tree Breadcrumb

Now click the small arrow to the left of the applyTonalFilter row at the top of the table. This will unfold the Call Tree to show the caller of applyTonalFilter. You may need to unfold the next row too; when profiling Swift, there will sometimes be duplicate rows in the Call Tree, prefixed with @objc. You’re interested in the first row that’s prefixed with your app’s target name (InstrumentsTutorial):

Selected Row In Call Tree

In this case, this row refers to the results collection view’s cellForItemAtIndexPath. Double click the row to see the associated code from the project.

Now you can see what the problem is. The method to apply the tonal filter takes a long time to execute, and it’s called directly from cellForItemAtIndexPath, which will block the main thread (and therefore the entire UI) each time it’s ask for a filtered image.

Offloading the Work

To solve this, you’ll take two steps: first, offload the image filtering onto a background thread with dispatch_async; then cache each image after it’s been generated. There is a small, simple image caching class (with the catchy name ImageCache) included in the starter project, that simply stores images in memory and retrieves them based on a given key.

You could now switch to Xcode and manually find the source file you’re looking at in Instruments, but there’s a handy Open in Xcode button right in front of your eyes. Locate it in the panel just above the code and click it:

Open In Xcode Button

There you go! Xcode opens up at exactly the right place. Boom!

Now, within collectionView(_:cellForItemAtIndexPath:), replace the call to loadThumbnail() with the following:

flickrPhoto.loadThumbnail { image, error in
  if cell.flickrPhoto == flickrPhoto {
    if flickrPhoto.isFavourite {
      cell.imageView.image = image
    } else {
      if let cachedImage = ImageCache.sharedCache.imageForKey("\(flickrPhoto.photoID)-filtered") {
        cell.imageView.image = cachedImage
      } else {
      	dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
          if let filteredImage = image?.applyTonalFilter() {
            ImageCache.sharedCache.setImage(filteredImage, forKey: "\(flickrPhoto.photoID)-filtered")
            dispatch_async(dispatch_get_main_queue(), {
              cell.imageView.image = filteredImage
            })
	        }
        })
      }
    }
  }
}

The first section of this code is the same as it was before, and is concerned with loading the Flickr photo’s thumbnail image from the web. If the photo is favorited, the cell displays the thumbnail as-is. However, if the photo isn’t favorited, the tonal filter is applied.

This is where things have changed: first, the code checks to see if a filtered image for this photo exists in the image cache. If yes, great; that image is displayed in the image view. If not, a call to apply the tonal filter to the image is dispatched onto a background queue. This will allow the UI to remain responsive whilst the images are filtered. When the filter has been applied, the image is saved in the cache, and the image view is updated on the main queue.

That’s the filtered images taken care of, but there’s still the original Flickr thumbnails to be taken care of. Open up FlickrSearcher.swift and find loadThumbnail(_:). Replace it with the following:

func loadThumbnail(completion: ImageLoadCompletion) {
  if let image = ImageCache.sharedCache.imageForKey(photoID) {
    completion(image: image, error: nil)
  } else {
    loadImageFromURL(URL: flickrImageURL(size: "m")) { image, error in
      if let image = image {
        ImageCache.sharedCache.setImage(image, forKey: self.photoID)
      }
      completion(image: image, error: error)
    }
  }
}

This is quite similar to the code that handled filtered images. If an image already exists in the cache then the completion closure is called straight away with the cached image. Otherwise, the image is loaded from Flickr and stored in the cache.

Re-run the app in Instruments by navigating to Product\Profile (or ⌘I – remember, those shortcuts will really save you some time).

Notice that this time you are not asked for which instrument to use. This is because you still have a window open for this app, and Instruments assumes you want to run again with the same options.

Perform a few more searches, and notice that this time the UI is not quite so clunky! The image filter is now applied asynchronously and the images are cached in the background, so once they only have to be filtered once. You’ll see a number of dispatch_worker_threads in the Call Tree – these are handling the heavy lifting of applying image filters.

Looks great! Is it time to ship it? Not yet! :]

Allocations, Allocations, Allocations

The next instrument covered in this tutorial is the Allocations instrument. This gives you detailed information about all the objects that are being created and the memory that backs them; it also shows you retain counts of each object.

To start afresh with a new instruments profile, quit the Instruments app. This time, build and run the app, and open the Debug Navigator in the Navigators area. Then click on Memory to display graphs of memory usage in the main window:

Xcode Gauges

These graphs are useful for to get a quick idea about how your app is performing. But you’re going to need a bit more power. Click the Profile in Instruments button and then Transfer to bring this session into Instruments. The Allocations instrument will start up automatically.

Allocations

This time you’ll notice two tracks. One is called Allocations, and one is called Leaks. The Allocations track will be discussed in detail later on; the Leaks track is generally more useful in Objective-C, and won’t be covered in this tutorial.

So what bug are you going to track down next? :]

There’s something hidden in the project that you probably don’t know is there. You’ve likely heard about memory leaks. But what you may not know is that there are actually two kinds of leaks:

  1. **True memory leaks** are where an object is no longer referenced by anything but still allocated – that means the memory can never be re-used. Even with Swift and ARC helping manage memory, the most common kind of memory leak is a retain cycle or strong reference cycle. This is when two objects hold strong references to one another, so that each object keeps the other one from being deallocated. This means that their memory is never released!
  2. **Unbounded memory growth** is where memory continues to be allocated and is never given a chance to be deallocated. If this continues forever, then at some point the system’s memory will be filled and you’ll have a big memory problem on your hands. In iOS this means that the app will be killed by the system.

With the Allocations instrument running on the app, make five different searches in the app but do not drill down into the results yet. Make sure the searches have some results! Now let the app settle a bit by waiting a few seconds.

You should have noticed that the graph in the Allocations track has been rising. This is telling you that memory is being allocated. It’s this feature that will guide you to finding unbounded memory growth.

What you’re going to perform is a “generation analysis”. To do this, press the button called Mark Generation. You’ll find the button at the top of the Display Settings inspector:

Mark Generation Button

Press it and you will see a red flag appear in the track, like so:

Red Flag

The purpose of generation analysis is to perform an action multiple times, and see if memory is growing in an unbounded fashion. Drill into a search, wait a few seconds for the images to load, and then go back to the main page. Then mark the generation again. Do this repeatedly for different searches.

After a drilling into a few searches, Instruments will look like this:

Generations

At this point, you should be getting suspicious. Notice how the blue graph is going up with each search that you drill into. Well, that certainly isn’t good. But wait, what about memory warnings? You know about those, right? Memory warnings are iOS’s way of telling an app that things are getting tight in the memory department, and you need to clear out some memory.

It’s possible that this growth is not just due to your app; it could be something in the depths of UIKit that’s holding onto memory. Give the system frameworks and your app a chance to clear their memory first before pointing a finger at either one.

Simulate a memory warning by selecting Instrument\Simulate Memory Warning in Instruments’ menu bar, or Hardware\Simulate Memory Warning from the simulator’s menu bar. You’ll notice that memory usage dips a little, or perhaps not at all. Certainly not back to where it should be. So there’s still unbounded memory growth happening somewhere.

The reason for marking a generation after each iteration of drilling into a search is that you can see what memory has been allocated between each generation. Take a look in the detail panel and you’ll see a bunch of generations.

Talkin’ Bout My Generation

Within each generation, you’ll see all the objects that were allocated and still resident at the time that generation was marked. Subsequent generations will contain just the objects since the previous generation was marked.

Look at the Growth column and you’ll see that there is definitely growth occurring somewhere. Open up one of the generations and you’ll see this:

Generation Analysis

Wow, that’s a lot of objects! Where do you start?

Unfortunately, Swift clutters up this view a lot more than Objective-C used to, filling it with internal data types that you don’t really need to know about. You can clean it up slightly by switching the Allocation Type to All Heap Allocations. Also, click the Growth header to sort by size.

Right near the top is ImageIO_jpeg_Data, and that’s certainly something that is dealt with in your app. Click on the arrow on the left of ImageIO_jpeg_Data to display the full list. Select one and then select the Extended Detail inspector (or press ⌘+3):

Generation Detail

This shows you a stack trace at the point when this specific object was created. The parts of the stack trace in grey are in system libraries; the parts in black are in your app’s code. To get more context for this trace, double click on the second black frame from the bottom. It’s the only one prefixed with “InstrumentsTutorial” which indicates that it’s from the Swift code. Double clicking will take you to the code for that method – your old friend collectionView(_:cellForItemAtIndexPath:).

Instruments is pretty useful, but it can help you no further in this case! You’re now going to have to work through the code yourself in order to understand what’s going on.

Take a look through the method, and you’ll see it calling setImage(_:forKey:). As you saw when you were looking at Time Profiler, this method caches an image in case it is used again later on in the app. Ah! Well that certainly sounds like it could be a problem! :]

Again, click the Open in Xcode button to jump back into Xcode. Open ImageUtilities.swift and take a look at the implementation of setImage(_:forKey:).:

func setImage(image: UIImage, forKey key: String) {
  images[key] = image
}

This adds an image to a dictionary which is keyed on the photo ID of the Flickr photo. But if you look through the code, you’ll notice that the image is never cleared from that dictionary!

That’s where your unbounded memory growth is coming from: everything is working as it should, but the app never removes things from the cache — it only ever adds them!

To fix the problem, all you need to do is have ImageCache listen to the memory warning notification that UIApplication fires. When ImageCache receives this, it must be a good citizen and clear its cache.

To make ImageCache listen to the notification, add the following initializer and de-initializer to the class:

init() {
  NSNotificationCenter.defaultCenter().addObserverForName(
    UIApplicationDidReceiveMemoryWarningNotification,
    object: nil, queue: NSOperationQueue.mainQueue()) { notification in
      self.images.removeAll(keepCapacity: false)
  }
}
 
deinit {
  NSNotificationCenter.defaultCenter().removeObserver(self,
    name: UIApplicationDidReceiveMemoryWarningNotification,
    object: nil)
}

This registers an observer for UIApplicationDidReceiveMemoryWarningNotification to execute the closure above which clears images.

All that the code needs to do is remove all objects in the cache. This will ensure that nothing is holding onto the images any more and they will be deallocated.

To test this fix, fire up Instruments again (from Xcode with ⌘I) and repeat the steps you followed previously. Don’t forget to simulate a memory warning at the end!

Note: Make sure you launch from Xcode, triggering a build, rather than just hitting the red button in Instruments, in order to make sure you’re using the latest code. You may also want to Build and Run first before Profiling, as sometimes Xcode doesn’t seem to update the build of the app in the simulator to the latest version if you just Profile.

This time the generation analysis should look like this:

Generation Analysis After Fix

You’ll notice the memory usage dropped after the memory warning. There’s still some memory growth overall, but nowhere near as much as before.

The reason there’s still some growth is really due to the system libraries, and there’s not much you can do about those. It appears that the system libraries are not freeing all of their memory, which may be by design or may be a bug. All you can do in your app is free up as much memory as possible, and you’ve already done that! :]

Well done! One more issue patched up! It must be time to ship by now! Oh, wait – there’s still the issue of the first type of leak that you haven’t yet addressed.

Strong Reference Cycles

Finally, you’re going to find a strong reference cycle in the Flickr Search app. As mentioned earlier, a strong reference cycle occurs when two objects hold strong references to one another, can’t be deallocated, and eat up memory. You can detect this cycle using the Allocations instrument in a different way.

Note: To follow along with this section of this tutorial, you must profile your app on a real device. Unfortunately at the time of writing there appears to be a bug when running the Allocations instrument against apps in the simulator which means that most of the classes used in this project won’t show up in Instruments.

Close Instruments, head back to Xcode, and ensure that your device is selected as the build target for the app. Choose Product\Profile once again, and select the Allocations template.

Allocations

This time round, you won’t be using generation analysis. Instead, you’ll look at the number of objects of different types that are hanging around in memory. You should already see a huge number of objects filling up the detail panel – too much to look through!

To help narrow down only the objects of interest, enter “Instruments” as a filter in the field above the Allocations Summary list. This will show only objects that feature the word “Instruments” in their type name. Because the sample app is named “InstrumentsTutorial”, the Allocations list will now only show types that are defined as part of this project. That makes things a bit easier!

Allocations Filtered

The two columns worth noting in Instruments are # Persistent and # Transient. The Persistent column keeps a count of the number of objects of each type that currently exist in memory. The Transient column shows the number of objects that have existed but have since been deallocated. Persistent objects are using up memory, transient objects have had their memory released.

You should see that there is a persistent instance of ViewController – that makes sense, because that’s the screen you’re currently looking at. There’s also the AppDelegate, and an instance of the Flickr API client.

Back to the app! Perform a search and drill into the results. Notice that a bunch of extra objects are now showing up in Instruments: the FlickrPhotos that have been created when parsing the search results, the SearchResultsViewController, and the ImageCache amongst others. The ViewController instance is still persistent, because it’s needed by its navigation controller. That’s fine.

Now tap the back button in the app. The SearchResultsViewController has now been popped off the navigation stack, so it should be deallocated. But it’s still showing a # Persistent count of 1 in the Allocations summary! Why is it still there?

Try performing another two searches and tap the back button after each one. There are now 3 SearchResultsViewControllers?! The fact that these view controllers are hanging around in memory means that something is keeping a strong reference to them. Looks like you have a strong reference cycle!

Reference Cycle

Your main clue in this situation is that not only is the SearchResultsViewController persisting, but so are all the SearchResultsCollectionViewCells. It’s likely that the reference cycle is between these two classes.

Unfortunately, at the time of writing, Instruments’ output for Swift still isn’t particularly useful in some cases. Instruments can only give you a hint here as to where the problem lies, and show you where the objects are allocated; it’s then your job to work out what the problem is.

Let’s delve into the code. Hover your mouse over InstrumentsTutorial.SearchResultsCollectionViewCell in the Category column, and click the small arrow to the right of it. This next view shows you all of the allocations of SearchResultsCollectionViewCells during the run of the app. There are quite a lot of them – one for each search result!

Cell Allocations

Change the Inspector to show the Extended Detail inspector, by clicking the third icon along at the top of the panel. This inspector shows the stack trace of the currently selected allocation. As with the earlier stack trace, the black parts are your code. Double-click the topmost black row (that begins “InstrumentsTutorial”) to see where the cell is allocated.

The cells are allocated at the top of collectionView(cellForRowAtIndexPath:). If you scan down a few lines, you’ll see this (with no help from Instruments to bring it to your attention, unfortunately!):

cell.heartToggleHandler = { isStarred in
  self.collectionView.reloadItemsAtIndexPaths([ indexPath ])
}

This is the closure that handles a tap on one of the heart buttons on the collection view cells. This is where the strong reference cycle lies, but it’s kind of hard to spot unless you’ve come across one before.

The closure cell refers to the SearchResultsViewController using self, which creates a strong reference. The closure captures self. Swift actually forces you to explicitly use the word self in closures (whereas you can usually drop it when referring to methods and properties of the current object). This helps you be more away of the fact you’re capturing it. The SearchResultsViewController also has a strong reference to the cells, via their collection view.

To break a strong reference cycle, you can define a capture list as part of the closure’s definition. A capture list can be used to declare instances that are captured by closures as being either weak or unowned:

  • Weak should be used when the captured reference might become nil in the future. If the object they refer to is deallocated, the reference becomes nil. As such, they are optional types.
  • Unowned references should be used when the closure and the object it refers to will always have the same lifetime as one another, and will be deallocated at the same time. An unowned reference can never become nil.

To fix this strong reference cycle, click the Open in Xcode button again and add a capture list to the heartToggleHandler in SearchResultsViewController.swift:

cell.heartToggleHandler = { [weak self] isStarred in
  if let strongSelf = self {
    strongSelf.collectionView.reloadItemsAtIndexPaths([ indexPath ])
  }
}

Declaring self as weak means that the SearchResultsViewController can be deallocated even though the collection view cells hold a reference to it, as they are now just weak references. And deallocating the SearchResultsViewController will deallocate its collection view, and in turn, the cells.

From within Xcode, use ⌘+I again to build and run the app in Instruments.

Look at the app again in Instruments using the Allocations instrument as you did before (remember to filter the results down to show only the classes that are part of the starter project). Perform a search, navigate into the results, and back again. You should see that the SearchResultsViewController and its cells are now deallocated when you navigate back. They show transient instances, but no persistent ones.

Cycle broken! SHIP IT! :]

Where to Go From Here?

Here’s a download of the final optimized version of the project, all thanks to Instruments.

Now that you have this knowledge under your belt, go and instrument your own code and see what interesting things appear! Also, try to make Instruments a part of your usual development workflow.

You should be running your code through Instruments relatively often, and performing a full sweep of your app before release to ensure that you’ve caught as many memory management and performance issues as possible.

Now go and make some awesome – and efficient – apps! :]

Instruments Tutorial with Swift: Getting Started is a post from: Ray Wenderlich

The post Instruments Tutorial with Swift: Getting Started appeared first on Ray Wenderlich.

RWDevCon Inspiration Talk – Opportunity by Jake Gundersen

$
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 Opportunity by Jake Gundersen I hope you enjoy!


Transcript

Part of this talk is going to involve a little bit of audience participation: I want you to think back in the last three or four months of your career. I want to ask by raise of hands who has ever felt like this:

dogAtKeyboard

Like you have no idea what you’re doing?

Or have you felt like this guy:

Attribution

Attribution: flickr.com

Like you’re right about to just fall on your face?

Or have you been jealous of somebody else’s career? Have you felt like you would like to be working on those kinds of projects or at their level?

Some of you probably said yes to some of these questions. :]

But I’m Safe Here!

On the other hand, some of you were probably thinking, “No. You know, I’m pretty good with where I am. Things are going smoothly. I’m comfortable. I’m good at what I do. Things are all good.”

Attribution:

Attribution: flickr.com

I’d like to argue today that if you’re feeling that way, if you feel like all things are all good, you’re probably playing it too safe. You’re probably not taking enough risk or pushing yourself.

There are probably opportunities for you to be doing work harder, more interesting, more difficult than you’re doing now that you just need to reach for it.

This is great quote by John A. Shedd that says:

capsize-184167_1280

“A ship in the harbor is safe, but that’s not what ships are for.”

It’s really tempting to play it safe. We get used to being good at what we do. We’re comfortable with our skill sets with the people that we’re working with, with the environment that we’re in.

In sailing there’s tons of risks involved in embarking on a new journey. Your ship could sink. You may not know anything about sailing or you might encounter some unfriendly natives.

I think there are opportunities out there for each of us that we just need to reach for. The only way to get to those opportunities is by stretching ourselves, by taking more risk. I think that we can surprise and amaze ourselves of what we’re capable of doing if we put ourselves out there.

Attribution:

Attribution: flickr.com

My Experiences

I’m going to talk a little bit about some of my experiences, my story. After school, I started out as a financial analyst at a hospital, a super secured job.

I was looking at spreadsheets all day, everyday. It wasn’t super interesting and I was in a cubicle.

I was able to take advantage of a series of opportunities. Then I was able to become a successful iOS contractor and author.

I’ll tell you a little bit about my transformation. I’m going to tell you three stories.

My First App

The first story is about opportunities that come to you. A little bit about after I graduated from school, a buddy of mine I went to school with came to me and said he wanted somebody to build him an IOS app.

I had been a life long wanna-be programmer. Maybe ten or fifteen times throughout my teenage years and early twenties, I had attempted to learn programming from books just like this one.

I got in two or three hundred pages in and I would just get bogged down; the learning curve was too steep. I get bored and I’d abandoned my attempt to become a programmer.

When my friend asked me how it was going, I said it was something I was super interested in, but it was also something I really wasn’t capable of doing. When he asked me, I was watching the Stanford iTunes course. Some of you guys may have watched it, right?

It was great but I still didn’t know what I was doing.

  • The word delegate was thrown around a lot. I had no idea what that was.
  • I couldn’t figure how to use interface builder.
  • The navigation stack was a great mystery to me.

When he asked me to do it, I almost said no but he said, “Look, Jake. Why don’t you just try it? Give yourself a month. If you can deliver something in a month, we’ll pay you. If not, you know, we’ll go find somebody else. No harm, no foul. ”

That little bit of opportunity was enough that I started having an objective and a deadline and a target, which narrowed the scope of what I was trying to do. Thus, I was able to move through it.

I found an online video that showed me how to put a table view controller navigation stack inside of a tab view controller and that unlocked the whole project and made it possible.

first app

You can see, it’s not an amazing app. It’s very simple but at the time, it was a big deal because it was the first time I’ve ever been able to complete a project and get paid for it and call myself a programmer and it was somewhat legitimate.

This was huge. It changed the way I thought about myself. It had this effect on my psyche. Suddenly, I felt like things that I’d always wanted to do that just felt too hard where now within my reach.

I was so close to saying, “no.” Had I said, “no,” I think the whole course of my life would have been different. I don’t think I’d be programming at all today. I’m very happy that I am.

That opportunity led to others.

LevineOpp

I worked with that same friend. We did two or three projects together. Most recently, we went to the White House Game Jam last year. Bigger opportunities grew out of that smaller one.

My First Tutorial

The second opportunity was the opportunity to write for the raywenderlich.com Team. I had been reading the blog for a while. I learned a lot about Cocos2d. I had a tremendous amount of respect and admiration for the work that Ray was doing and his other writers. I saw one of these (It wasn’t this one because this is 2014.) posts:

Screen Shot 2015-01-24 at 10.41.40 PM

I really wanted to write for the site but once again, I really felt like I wasn’t at that level.

I didn’t know what I was doing. I looked at the other people, Ray himself and the other people, he had writing for him, and I just said, “I’m not at that level.”

I struggled with writing at that time. I had been through school and really practiced writing but I just felt my writing skill was still pretty weak. But, I really wanted to do it. I knew that if I toggled that giant, that I would feel once again that I was capable of doing things that really impress myself. That I was kind of awesome.

I went ahead and emailed Ray. It turned out that he was looking for somebody to write a Corona tutorial and I just happened to have spent couple of months playing around with Corona. So, I wrote a Corona tutorial and I got it published:

Screen Shot 2015-01-24 at 10.16.40 PM

Having my name on a post, on a site that was read such a large audience was huge for me because it was something for which I had so much respect. The idea that you could just put your knowledge on the web and that people will flock to you and that could become your career, that blew my mind. I thought that was so cool.

That again led to another opportunities.

All of that flowed from me saying yes and again, I was right on that precipice where I was really hesitant to do it but I knew I have to push myself and I did.

My GPUImage Experience

The third opportunity is the opportunity that you create.

I had gotten into image processing through writing about Core Image for iOS 5 By Tutorials. I fell in love with it. Core Image was limited at the time because you couldn’t write custom kernels? so you’re limited to the set of filters that you had. I really wanted more.

Just shortly thereafter, Brad Larson came out with his GPUImage framework. This was exactly what I wanted. Anything you could do in a shader, you could do in GPUImage which was awesome.

gpuimage icon

I jumped in and I started learning GLSL and OpenGL. I didn’t know it before but I really wanted to be able to do this.

I got into this and instead of just learning it for myself, I started contributing filters back. I was number two or three for a little while on the list of contributors. Brad Larson was about 95% of the code and then I was about 3% but that still put me near the top.

My name was on his project. I wrote a couple of blog posts about how to write filters. So people were emailing me for help with their own GPUImage projects.

This GPUImage work that I did created this environment for myself where people were coming to me for help with this great framework. It turned in to be huge thing. Probably about half of my living today come from helping people out with GPUImage.

GPUImageOpp

The great thing about the OpenGL scale is not every iOS programmer is willing to dive in and learn OpenGL. A lot of times, other programmers will come to me and I will just do that little chunk of their app and they’ll do the rest.

Working with programmers is great.

  • They’re easy to work with.
  • I get to charge a premium rate because it’s a specialized skill.

It’s turned out to be fantastic.

Then, on top of that, at one point Apple was recruiting for their Core Image team. They contacted me and flew me out for an interview.

I would never have applied for Apple. I mean, I don’t have a CS education. I had been programming for only a few years. I did not see myself as anything like the guys I expect work there. Yet, because of this work I did with GPUImage, I got this opportunity to go talk to them and interview for a job, which was awesome.

What Would Tina Do?

All these opportunities have one main thing in common for me. That was that in all these cases I already felt like I was not qualified. I didn’t know what I was doing. They required me to get outside of my comfort zone.

These are just the few examples. You’ll find that as you push yourself, this is how you grow. As you put yourself into this situation where you don’t feel you’re equal to the task, you’ll find yourself rising up to the task.

You have to be able to walk into the unknown.

walkers-486583_1280

You have to put yourself in this jeopardy situation where you could be humiliated or you could fail. A lot of times you don’t. A lot of times you surprise yourself. Even when you do, you find that you grow.

The question is, how do you do that? There’s this book by Tina Fey called Bossypants. She talks about this rule.

Early in her career, she learned improvisation. It’s a style of comedy. In improv comedy, actors create a situation on the fly, a scenario.

The rule with improvisation is you always agree with your partner. You always say yes.

Screen Shot 2015-05-26 at 12.45.11 AM

Here’s an example. If I say, “Freeze! I have a gun.”, and you say, “Ah. That’s not a gun. That’s your finger.” Well then, the scene has come into a halt. You can’t go anywhere from there.

If instead I say, “Freeze! I have a gun,” and you say, “The gun I gave you for Christmas! You bastard!” Well now we have a scene and it’s rolling.

Just Say “Yes” To Your Life

You can apply this to your life. Instead of having this negative reaction to things that are new or unknown or intimidating, you can just go with it. Just say, “yes,”and roll with what comes to you.

For me, I had read this book right about the time that I was getting into working with Ray and that was very much on my mind. I just got to try things. I just got to do it.

There were times when an opportunity came to me and I felt like, “I’m not equal to it. I can’t do it. I’m not qualified. It’s too much work.”

Then I would remember my desire to try new things and just say, “yes.” I realized that I really should be looking specifically at the things that intimidate me because those are the things that I would most love to do. Those are the things that I find the most satisfaction from and I feel good about.

Challenge Accepted!

I’ve tried to keep that in mind.

I want you all to imagine what kinds of opportunities, what adventures you get into if you always say yes. If new opportunities come to your path, just say, “I’m gonna try this. I’m gonna do it.” I want you to think about how you might grow or how that might stretch you.

Get Out Of Your Comfort Zone

For me, I had been working in safe and stable job in a cubicle doing spreadsheets all day long. It was not very interesting. Some people like it and that’s fine, but for me, I knew I wanted to be programmer.

I was able to say yes to series of opportunities and get out of the position I was in and into a new position.

cubicleVparadise

Now, I work for myself. I get to set my own hours and I have a lot more freedom.

The work I do today, I find interesting. When I get up in the morning and decided to go about my work. For me, it was a big shift.

There was a long period in my life when I felt like, I was going to have to resign myself to the first, to the gray slide. That would be my life, then there was no escape. It was a big deal that I was able to take this opportunities and change my fate.

Little opportunities seem to grow into bigger ones.

allOpportunities

Even if the time you felt like, “I don’t really know if anything’s gonna come out of this.” That happened to me a lot especially with the GPUImage situation. I had no idea what that would turn into but I was excited about that. I thought that was cool and I wanted to work on it. It turned out to be huge.

Escape The Trap of Staying Put

If you’re feeling that everything is going great and you’re happy and you’re good at what you do, that’s great but it might be a trap.

mouse-164751_640

There might be opportunities for you out there that would cause you to grow and stretch you. That will make you feel better if you just kind of put yourself in that scary place and take advantage of it.

I want to challenge all of you to get out of your comfort zone, to always say, “yes,” and to sail your ship to exotic lands.

Note from Ray: Did you enjoy this inspiration talk? If so, sign up to our RWDevCon newsletter to be notified when RWDevCon 2016 tickets go on sale!

RWDevCon Inspiration Talk – Opportunity by Jake Gundersen is a post from: Ray Wenderlich

The post RWDevCon Inspiration Talk – Opportunity by Jake Gundersen appeared first on Ray Wenderlich.

Video Tutorial: Unity 2D Basics: Series Introduction

Video Tutorial: Unity 2D Basics Part 1: 2D Environment

How To Create an Xcode Plugin: Part 1/3

$
0
0
Customize your Xcode just the way you like it!

Customize your Xcode just the way you like it!

Update note: This tutorial has only been tested with Xcode 6.3.2 — if you’re working with another version of Xcode, your experience might not match up perfectly with this tutorial.

The “one size fits all” paradigm that Apple extends to its products can be a tough pill to swallow. Although Apple has forced its workflows onto iOS/OS X developers, it’s still possible to bend Xcode to your will through plugins!

There isn’t any official Apple documentation on how to create an Xcode plugin, but the development community has put a tremendous amount of work into some pretty useful tools to help aid developers.

From autocompletion for images, to nuking your Derived Data to a vim editor, the Xcode plugin community has pushed the boundaries of what was originally thought capable.

In this epic three-part tutorial, you’ll create an Xcode plugin to prank your co-workers, featuring none other than the best prankster in these parts — Ray himself! And although the plugins are lighthearted in nature, you’ll still learn a lot about tracing through Xcode, how to find the elements you want to modify, and how to swizzle in your own functionality!

You’ll be inspecting undocumented frameworks using your x86 assembly knowledge, code navigating skills, and LLDB skills while exploring private APIs and injecting code using method swizzling. Since there’s a lot to cover, this tutorial will move very quickly. Make sure you’re comfortable in iOS or OS X development before proceeding!

Plugin development with Swift severely complicates an already tricky topic, and the Swift debugging tools are just not up to par with Objective-C yet. For now, that means the best choice for plugin development (and this tutorial!) is Objective-C.

Getting Started

To celebrate Prank Your Co-Worker Day (aka every day!), your Xcode plugin will Rayroll your victim. Wait, what’s Rayrolling? It’s the copyright & royalty free version of Rickrolling, where you bait-and-switch your victims with content that’s different than what was expected. When you’ve completed this series, your plugin will modify Xcode so that it will:

  1. Replace Ray’s face on the Xcode alerts (i.e. Build Succeeded/Build Failed).

    Xcode_Swizzle_DispalAlert

  2. Replace Xcode’s titlebar contents with lyrics from Ray’s hit song, Never Gonna Live You Up.

    Plugin_Swizzled_Titlebar

  3. Replace all Xcode documentation requests to a Rayroll’d video.

    Plugin_Swizzle_Documentation

In this first part of the tutorial, you’ll focus on hunting down the class responsible for displaying the “Build Succeeded” alert and modify the image it displays with a good ol’ pic of Ray.

Installing the Alcatraz Plugin

Before you do anything, you’ll need to install Alcatraz. The Xcode plugin Alcatraz acts as a Xcode plugin manager; it’s from the talented developers @kattrali, @_supermarin, and @JurreTweet.

Type the following command into Terminal to install Alcatraz:

curl -fsSL https://raw.github.com/supermarin/Alcatraz/master/Scripts/install.sh | sh

Restart Xcode once the script has finished. You might see an alert warning you of the Alcatraz bundle; go ahead and click Load Bundle to continue. You do want to power-up your Xcode, right?

Xcode6.3.2

Note: If you accidentally clicked “Skip Bundle”, you can re-enable this alert by entering the following in Terminal:
defaults delete com.apple.dt.Xcode DVTPlugInManagerNonApplePlugIns-Xcode-6.3.2

You’ll see a new option in the Xcode Window menu section called Package Manager. Creating an Xcode plugin requires you to muck around with the Build Settings to launch and attach Xcode to another instance of Xcode. Fortunately, @kattrali has already done the work for you and created a plugin, which creates a template…which creates a plugin.

Open the Alcatraz plugin by navigating to Window\Package Manager. In the Alcatraz search dialog, search for Xcode Plugin. Make sure that you have the All and Templates attributes selected on the search window. Once you’ve located the Xcode Plugin Template, click the Install button on the left to install it:

XcodeAlcatrazPlugin-700x208

Once Alcatraz has downloaded the plugin, create a new project by navigating to File\New\Project…. Select the new OS X\Xcode Plugin\Xcode Plugin template option and click Next.

XcodePluginSelection-480x282

Name the Product Rayrolling, set the Organization Identifier as com.raywenderlich (this is important), and choose Objective-C for the Language.. Save the project to whatever directory you desire.

Plugin_Xcode_Setup-480x281

The Hello World Plugin Template

Build and run your new Rayroll project; you’ll see a new child instance of Xcode appear. This child instance has a new option in the Edit menu named Do Action:

XcodePluginHelloWorld

Selecting this item will launch a modal alert:

Screen Shot 2015-05-11 at 8.48.27 PM

Plugins are tagged to work with specific versions of Xcode. This means that when a new Xcode version comes out, all 3rd party plugins created by the community will fail until they add the UUID specific to that version. If this particular template doesn’t work and you don’t see the new menu action, you may need to add support for your version of Xcode.

To add this, run the following command in Terminal:

defaults read /Applications/Xcode.app/Contents/Info DVTPlugInCompatibilityUUID

This command will output a UUID for your current Xcode. Open the Info.plist of the plugin and navigate to the DVTPlugInCompatibilityUUID key to add the value to the array:

DVTCompatibilityUUIDs

Note: Throughout this tutorial, you’ll be running and making changes to an installed Xcode plugin. This will change the behavior of Xcode, and potentially make Xcode crash! If you want to disable a plugin, you’ll need to manually remove it using Terminal:

cd ~/Library/Application\ Support/Developer/Shared/Xcode/Plug-ins/
rm -r Rayrolling.xcplugin/

…and then restart Xcode.

Finding the Features to Modify

One tried and true way to get a basic grounding of what’s going on behind the scenes is to have a NSNotification observer that listens to all events fired by Xcode. By using Xcode and observing these notifications as they fire, you will be able to take a peek at the underlying classes.

Open Rayrolling.m and add the following property to the class:

@property (nonatomic, strong) NSMutableSet *notificationSet;

This NSMutableSet stores all the NSNotification names the Xcode console spits out.

Next, add the following code to initWithBundle:, after the if (self = [super init]) { line:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:nil object:nil];
 
self.notificationSet = [NSMutableSet new];

Using nil in the name parameter, indicates you want to listen for all the notifications that Xcode passes around.

Now implement handleNotification: as shown below:

- (void)handleNotification:(NSNotification *)notification {
  if (![self.notificationSet containsObject:notification.name]) {
    NSLog(@"%@, %@", notification.name, [notification.object class]);
    [self.notificationSet addObject:notification.name];
  }
}

handleNotification: checks that the notification name is in the notificationSet; if it’s not, print the notification’s name and class and add it to the set. This way, you’ll only see each notification reported once.

Next, find and replace the added action menu item declaration to update its title text:

NSMenuItem *actionMenuItem = [[NSMenuItem alloc] initWithTitle:@"Reset Logger"
 action:@selector(doMenuAction) keyEquivalent:@""];

This is a minor modification to the NSMenuItem title so you know that it will reset the NSNotification set when you click on the menu action.

Finally, replace the implementation of doMenuAction with the following:

- (void)doMenuAction {
  [self.notificationSet removeAllObjects];
}

The menu item will now reset all the notifications in the notificationSet property. This will let you examine notifications of interest with less “console noise.”

Build and run the plugin again to relaunch the child Xcode. Make sure you clearly separate the parent Xcode that is running the instance of the debugged child Xcode, because the parent will not have your most recent plugin changes incorporated until you relaunch Xcode into memory.

Play around with the child Xcode; click on buttons, open windows and explore the application while keeping an eye on the parent Xcode’s console as the notifications fire.

Finding and Inspecting the Build Status Alert

Now that you have your basic grounds for inspecting the NSNotification names triggered in Xcode, you need to turn your attention to figuring out the class associated with displaying the build alert.

Launch the Xcode plugin. In the child Xcode, open any project. Make sure you have bezel notifications enabled – in your Xcode settings, enable them for when builds succeed and fail. Again, make sure you’re changing the settings in your child Xcode instance!

rayroll-bezel

Reset the notificationSet using the Reset Logger menu item you created, then run the child Xcode project.

As the child Xcode’s build succeeds (or fails), keep an eye on the console messages. Skim through the console and see if there is anything of interest. Can you spot any notifications that look like they’re worth inspecting further? The solution is below in case you need a little help…

Solution Inside: Hunting through notifications SelectShow>

You’ll pick one of these and explore it further to see what information you can dig out of it.
What about NSWindowWillOrderOffScreenNotification? Good choice! You’ll explore that one.

Still in Rayrolled.m, navigate to handleNotification: and add a breakpoint on the first line as shown by the image and corresponding steps below:

Xcode_Add_Symbolic_Breakpoint

  1. Hover over the breakpoint, right-click the breakpoint and select Edit Breakpoint.
  2. In the condition section, paste [notification.name isEqualToString:@"NSWindowWillOrderOffScreenNotification"]
  3. In the Action Section, add po notification.object
  4. If the parent Xcode is not already running the child Xcode, launch the build, then launch a build in the child Xcode. The breakpoint will stop on the NSWindowWillOrderOffScreenNotification notification. Observe the -[notification object] printed out. This is DVTBezelAlertPanel, the first of many private classes that you’ll be exploring.

You now have a potential lead. You have a class named DVTBezelAlertPanel, and more importantly, you have an instance of this class in memory. Unfortunately, you don’t have any headers for this file to determine if this is the instance responsible for displaying the Xcode alert. Hmm.

Actually…it is possible to obtain this information. Although you don’t have the headers for this class, you do have a debugger attached to the child Xcode, and memory can tell you as good of a story as any header file could.

Note: For this tutorial series, LLDB console output is often included with console input. Any line that begins with (lldb) should be considered console input and be typed in by you. Three dots symbolize output that has been omitted from standard out in the console. If you’re overwhelmed and have too much information in the console, press ⌘ + K to remove the current content and start fresh.

While still paused in the debugger of the parent Xcode, enter the following in the parent Xcode’s LLDB Console:

(lldb) image lookup -rn DVTBezelAlertPanel
17 matches found in /Applications/Xcode.app/Contents/SharedFrameworks/DVTKit.framework/Versions/A/DVTKit: 
...

This searches for the name DVTBezelAlertPanel within Xcode, as well as in any frameworks, libraries, and plugins loaded into the Xcode process, and spits out any matching contents. Look at the listed methods. Are there any methods within the DVTBezelAlertPanel image dump that could help correlate this class to this error message? I’ve provided some help below if you need it.

Solution Inside: Interesting methods SelectShow>
Note: Be aware that the image lookup LLDB command will list methods that are implemented in memory. When applying this to a particular class, this does not take into account subclassing where other methods inherit from superclasses. That is, the lookup of this command will omit any methods only declared in superclasses provided the subclasses do not override the super method.

Without moving or stepping in the LLDB console, inspect the contentView property in LLDB with the following command:

(lldb) po [notification.object controlView]
<nil>

The console spits out nil. Darn. Maybe this is because the controlView isn’t set at this time. Time to try a different tactic.

initWithIcon:message:parentWindow:duration and initWithIcon:message:controlView:duration: looked somewhat juicy. Since you know that the DVTBezelAlertPanel instance is already alive, one of these twp method calls must have already occurred. You’ll need to attach a breakpoint to both of these methods through the LLDB console and try and trigger this class’s initialization again.

While remaining paused in the LLDB console, type the following:

(lldb) rb 'DVTBezelAlertPanel\ initWithIcon:message:'
Breakpoint 1: 2 locations.
(lldb) br l
...

This sticks a regular expression breakpoint on both of DVTBezelAlertPanel‘s initializers referenced above. Since both methods have the same starting text in their initialization, the regex breakpoint will match both items. Make sure you have a \ before the space and surround the expression in single quotes so LLDB knows how to properly parse the regex.

Resume the child application, then re-build the child project. You’ll hit the initWithIcon:message:parentWindow:duration breakpoint in the debugger.

If you didn’t hit it, make sure you added the breakpoint to the parent Xcode, with the child Xcode running a project. Xcode will break on the assembly for this method since it doesn’t have the corresponding sourcefile for it.

Now that you’ve arrived in a method for which you don’t have the source code, you’ll need a way to print out the function parameters sent to the method. This is perhaps a good time as any to talk about…ASSEMBLY! :]

AssemblyRage

A Whirlwind Detour of Assembly

When working with private APIs, you’ll need to inspect registers instead of using the debug symbols typically available to you when working with source code. Knowing how registers behave on the x86-64 architecture can be tremendously helpful.

Although not a required read, this article is a good resource for catching up on x86 Mach-0 assembly. In Part 3 of this tutorial series, you’ll rip apart a method in the disassembler to see what it’s doing, but for now, you’ll take the easy road.

It’s worth noting the following registers and how they function:

  • $rdi: This register references the self parameter passed into a method; this is the first parameter passed in.
  • $rsi: Refers to the Selector passed. This is the second parameter.
  • $rdx: The third parameter passed into a function, and the first parameter of an Objective-C method.
  • $rcx: The fourth parameter passed into a function, and the second parameter of an Objective-C method.
  • $r8: The fifth parameter passed into a function. $r9 is used for the 6th param followed by the stack frame used, if there are any more parameters required for the function call.
  • $rax: Return values are passed in this register. For example, when stepping out of –[aClass description], $rax will contain an NSString of the aClass instance’s description.
Note: There are cases where the above information is not correct. Sometimes the binary will use different registers for different types of function parameters, such as doubles using the $xmm register family. Use the above quick reference as a guide.

Applying theory in practice to a real world example, take the method below.

@interface aClass : NSObject
- (NSString *)aMethodWithMessage:(NSString *)message;
@end
 
@implementation aClass 
 
- (NSString *)aMethodWithMessage:(NSString *)message {
  return [NSString stringWithFormat:@"Hey the message is: %@", message]; 
}
 
@end

If you executed it like this:

aClass *aClassInstance = [[aClass alloc] init];
[aClassInstance aMethodWithMessage:@"Hello World"];

When compiled, the call to aMethodWithMessage: would be passed to objc_msgSend and would look roughly like this:

objc_msgSend(aClassInstance, @selector(aMethodWithMessage:), @"Hello World")

aMethodWithMessage: found in, aClass, would yield the following results in the set of registers:

Immediately upon calling aMethodWithMessage::

  • $rdi: Would contain an instance of aClass.
  • $rsi: Would contain the SEL aMethodWithMessage:, which is basically a char * (try po (SEL)$rsi in lldb).
  • $rdx: Would contain the contents of message, which will be the reference to the instance of: @"Hello World".

Immediately upon leaving the method:

  • $rax: Would contain the return value, which would be an instance of NSString. For this particular case, it would be an instance of: @"Hey the message is: Hello World".

x86 Register Dumpster Diving

Now that you’re an official assembly register wizard, it’s time to revisit DVTBezelAlertPanel‘s initWithIcon:message:parentWindow:duration:. Hopefully you haven’t moved from the break on this method. If you have, re-run the child Xcode to get there again. Remember, you’re searching for a clue that this class is the class responsible for showing Xcode’s Build Succeeded alert.

While stopped in initWithIcon:message:parentWindow:duration, type the following in LLDB:

(lldb) re re

This command is an abbreviated way of saying register read, which will print the significant registers available on your machine.

Using what you’ve learned about reading x86_64 registers, examine the register responsible for the message: parameter and the 4th objc_msgSend param. Do the contents match the expected alert string?

Solution Inside SelectShow>

Augment the $rcx register with a new string and see if the alert changes to be 100% sure:

(lldb) po [$rcx class]
__NSCFConstantString
 
(lldb) po id $a = @"Womp womp!"; 
(lldb) p/x $a 
(id) $a = 0x000061800203faa0 
(lldb) re w $rcx 0x000061800203faa0
(lldb) c

Womp_Womp_Xcode

The application then resumes. Note the augmented alert message that you changed while in the debugger. You can now safely make the assumption that this class is associated with the build alerts. Took a bit to figure it out, didn’t it?

Code Injection

You’ve found the class that you’re interested in. Now it’s time to inject code to augment DVTBezelAlertPanel‘s behavior to display a lovely Rayrolling face when an alert occurs.

Time to use method swizzling!

Since you could potentially swizzle numerous methods from different classes, it would be best to use a Category on NSObject to create a convenience method to perform setup logic.

Select File\New\File… and select the OS X\Source\Objective-C File template. Name the file MethodSwizzler and make it of file type Category and class NSObject.

Open NSObject+MethodSwizzler.m and replace its contents with the code below:

#import "NSObject+MethodSwizzler.h"
 
// 1
#import <objc/runtime.h>
 
@implementation NSObject (MethodSwizzler)
 
+ (void)swizzleWithOriginalSelector:(SEL)originalSelector swizzledSelector:(SEL) swizzledSelector isClassMethod:(BOOL)isClassMethod 
{
  Class cls = [self class];
 
  Method originalMethod;
  Method swizzledMethod;
 
  // 2
  if (isClassMethod) {
    originalMethod = class_getClassMethod(cls, originalSelector);
    swizzledMethod = class_getClassMethod(cls, swizzledSelector);
  } else { 
    originalMethod = class_getInstanceMethod(cls, originalSelector);
    swizzledMethod = class_getInstanceMethod(cls, swizzledSelector);
  }
 
  // 3
  if (!originalMethod) { 
    NSLog(@"Error: originalMethod is nil, did you spell it incorrectly? %@", originalMethod);
    return; 
  }
 
  // 4
  method_exchangeImplementations(originalMethod, swizzledMethod); 
}
@end

Taking each numbered comment in turn:

  1. This is the magical header responsible for declaring the functions used for method swizzling.
  2. isClassMethod indicates if the methods are class methods or instance methods.
  3. When you don’t have the help of the compiler to autocomplete your methods, it’s easy to misspell them. This is a check to make sure that you are declaring your SELs accurately.
  4. This is the function that will switch your implementations around.

Declare swizzleWithOriginalSelector:swizzledSelector:isClassMethod in NSObject+MethodSwizzler.h like so:

#import <Foundation/Foundation.h>
 
@interface NSObject (MethodSwizzler)
+ (void)swizzleWithOriginalSelector:(SEL)originalSelector swizzledSelector:(SEL) swizzledSelector isClassMethod:(BOOL)isClassMethod;
 
@end

Now it’s time to actually swizzle! Create another new Category called Rayrolling_DVTBezelAlertPanel which inherits from NSObject.

Replace the contents of NSObject+Rayrolling_DVTBezelAlertPanel.m with the following:

#import "NSObject+Rayrolling_DVTBezelAlertPanel.h" 
 
// 1
#import "NSObject+MethodSwizzler.h"
#import <Cocoa/Cocoa.h>
 
// 2
@interface NSObject ()
 
// 3
- (id)initWithIcon:(id)arg1 message:(id)arg2 parentWindow:(id)arg3 duration:(double)arg4;
@end
 
// 4
@implementation NSObject (Rayrolling_DVTBezelAlertPanel)
 
// 5
+ (void)load
{
  static dispatch_once_t onceToken;
 
  // 6
  dispatch_once(&onceToken, ^{
 
    // 7
    [NSClassFromString(@"DVTBezelAlertPanel") swizzleWithOriginalSelector:@selector(initWithIcon:message:parentWindow:duration:) swizzledSelector:@selector(Rayrolling_initWithIcon:message:parentWindow:duration:) isClassMethod:NO];
  });
}
 
// 8
- (id)Rayrolling_initWithIcon:(id)icon message:(id)message parentWindow:(id)window duration:(double)duration
{
  // 9
  NSLog(@"Swizzle success! %@", self);
 
  // 10
  return [self Rayrolling_initWithIcon:icon message:message parentWindow:window duration:duration];
}
 
@end

Broken down, the code is relatively straightforward:

  1. Make sure to import the method that can enable swizzling.
  2. You forward declare all the methods that you intend on using. Although this is not required, it makes the compiler play nice by autocompleting your code. In addition, this trick suppresses any warnings about undeclared methods.
  3. This is the actual private method you will be swizzling with.
  4. Since you don’t want to redeclare a private class, you’re opting for a category instead.
  5. This is the heart of the code injecting “trick”. You’ll perform the injecting in load. load is unique in that it has a “to-many relationship”. That is, multiple categories of the same class can all implement a load command and have them all execute.
  6. Since load can be called multiple times, you use dispatch_once.
  7. This uses the NSObject category method you implemented earlier. Note that you retrieve the private class dynamically at runtime using NSClassFromString.
  8. This is the replacement method for the original one. It’s good practice to use a unique namespace convention that only you could have come up with.
  9. This is a basic test to see if the swizzling worked by printing out to the console.
  10. Since you’re swizzling this method with the original one, when you call the swizzled method, it will still call the original method. This means you could add code before or after the original method is called, or even go so far as to change the parameters passed to the original function… which you’ll do in just a moment.

Congratulations! You’ve now successfully injected code into a private method of a private class! Build the parent Xcode, and then use the build of the child Xcode to see the added console message which was swizzled in.

Now it’s time to replace all alert images with the Rayrolling face. Download the lovely image created by our resident image swizzler Crispy from here and add the image into the Xcode project. Make sure to select Copy Items if Needed.

Navigate back to Rayrolling_initWithIcon:message:parentWindow:duration and change its content to the following:

- (id)Rayrolling_initWithIcon:(id)arg1 message:(id)arg2 parentWindow:(id)arg3 duration:(double)arg4 
{
  if (arg1) {  
    NSBundle *bundle = [NSBundle bundleWithIdentifier:@"com.raywenderlich.Rayrolling"];
    NSImage *newImage = [bundle imageForResource:@"IDEAlertBezel_Generic_Rayrolling.pdf"];
    return [self Rayrolling_initWithIcon:newImage message:arg2 parentWindow:arg3 duration:arg4];
  }
  return [self Rayrolling_initWithIcon:arg1 message:arg2 parentWindow:arg3 duration:arg4];
}

This method now checks that an image was passed to the original method, and replaces it with the Rayrolling image. Note that you had to use the +[NSBundle bundleWithIdentifier:] to load the image because it’s not contained in your mainBundle.

Build and run the project; quit out of all instances Xcodes and restart fresh.

Xcode_Alert_Closeup

Beautiful! :]

Toggling and Persisting the Rayroll

You’re designing this plugin to be annoying; no doubt you’d like to toggle it on and off as you work on it, while having your selection persist across the various instances of Xcode using NSUserDefaults.

Navigate to Rayrolling.h and add the following property to the header file:

+ (BOOL)isEnabled;

Now go to Rayrolling.m and add the following methods:

+ (BOOL)isEnabled {
  return [[NSUserDefaults standardUserDefaults] boolForKey:@"com.raywenderlich.Rayrolling.shouldbeEnable"];
}
 
+ (void)setIsEnabled:(BOOL)shouldBeEnabled {
  [[NSUserDefaults standardUserDefaults] setBool:shouldBeEnabled forKey:@"com.raywenderlich.Rayrolling.shouldbeEnable"];
}

You have the logic to persist your selection; now you need to enable a toggle in the GUI.

Back in Rayrolling.m, modify -(void)doMenuAction to look like the following:

- (void)doMenuAction:(NSMenuItem *)menuItem {
  [Rayrolling setIsEnabled:![Rayrolling isEnabled]];
  menuItem.title = [Rayrolling isEnabled] ? @"Disable Rayrolling" : @"Enable Rayrolling"; 
}

This will simply toggle the boolean to either enable or disable Rayrolling.

Finally, change the menu setup code in didApplicationFinishLaunchingNotification: to look like the following:

NSMenuItem *menuItem = [[NSApp mainMenu] itemWithTitle:@"Edit"];
if (menuItem) {
  [[menuItem submenu] addItem:[NSMenuItem separatorItem]];
  NSString *title = [Rayrolling isEnabled] ? @"Disable Rayrolling" : @"Enable Rayrolling";
  NSMenuItem *actionMenuItem = [[NSMenuItem alloc] initWithTitle:title action:@selector(doMenuAction:) keyEquivalent:@""];
  [actionMenuItem setTarget:self];
  [[menuItem submenu] addItem:actionMenuItem];
}

You now have an NSMenuItem which will persist across Xcode launches and retain the setting to to enable or disable the logic.

Navigate back to NSObject+Rayrolling_DVTBezelAlertPanel.m, and add the following import:

#import "Rayrolling.h"

Finally, open Rayrolling_initWithIcon:message:parentWindow:duration: and replace this line:

if (arg1) {

…with:

if ([Rayrolling isEnabled] && arg1) {

Build and run the program so the changes propagate to the plugin.

Boom! You now have a plugin which modifies the Xcode alert and can be toggled on and off. Pretty nice for a day’s work, eh?

Where to Go From Here?

You can download the completed Rayrolling project from this part of the tutorial.

You’ve made a ton of progress — but there’s still a lot more to do! In part 2, you’ll learn the basics of Dtrace and explore some advanced LLDB features to look into running processes such as Xcode.

If you want to get ahead, there’s some homework to do before you get to part 3, where you’ll see a lot of assembly code. Make sure you start learning now and have a decent understanding of x86_64 assembly by checking out Part I and Part II of Mike Ash’s series on disassembling assembly. These two articles will greatly aid in what’s to come.

Good luck and have fun exploring! If you had any comments or questions from this tutorial, feel free to join the forum discussion below!

How To Create an Xcode Plugin: Part 1/3 is a post from: Ray Wenderlich

The post How To Create an Xcode Plugin: Part 1/3 appeared first on Ray Wenderlich.

How To Create an Xcode Plugin: Part 2/3

$
0
0
Dtrace your way through Xcode for fun and profit!

Dtrace your way through Xcode for fun and profit!

Update note: This tutorial has only been tested with Xcode 6.3.2 — if you’re working with another version of Xcode, your experience might not match up perfectly with this tutorial.

Welcome to Part 2 of this three-part tutorial series on custom Xcode plugins! In Part 1 of this series, you were treated to a glimpse of Xcode’s underlying classes through NSNotification properties and injected code into the private class DVTBezelAlertPanel. In addition, you added a NSMenuItem to the menu to persist your preference of enabling Rayrolling in Xcode.

In this part, you’ll continue to build out the Rayrolling plugin you started in Part 1 — if you didn’t work through the first part of the tutorial, or just want to start afresh, you can download the finished project from the first part here. You’ll take a deep dive into the tools available for you to explore Xcode and, with your newfound knowledge, modify Xcode’s title bar so it showcases the lyrics of Ray’s very own hit song Never Gonna Live You Up. :]

Plugin_Swizzled_Titlebar

Getting Started

Open Xcode and Terminal and position your windows on the desktop so you can see both of them at the same time:

View_Organization

Since you’ve graduated from plugin n00b to ¡L33T P1|_|gin m4$Ter!, you’ll use LLDB via Terminal for your Xcode explorations; you no longer need to attach Xcode to an new instance of Xcode to see how things work under the hood.

LLDB’s BFF, Dtrace

One of the best tools for exploring Xcode is Dtrace, which is a wickedly awesome debugging tool and the workhorse behind Instruments. It’s an incredibly useful tool — provided you know how to wield it.

First, a “Hello World” tour of Dtrace is in order. You’ll create a script that will keep a running count of all the classes that begin with IDE and increment the count each time you call a class or instance method for that particular class. Dtrace will then dump this data when you exit the script.

Launch Xcode, then type the following into a fresh tab in Terminal:

sudo dtrace -n 'objc$target:IDE*::entry { @[probemod] = count(); }'  -p `pgrep -xo Xcode`

Although you won’t see any output at first, Dtrace is silently generating a trace of all method calls. Head back to Xcode and play around with it a bit; open some files and click on a few items. Then navigate back to Terminal and press Control + C to terminate the script. The contents of the data will be dumped out into Terminal:

Dtrace_Hello_World

Pretty cool, eh? :] There’s quite a bit you can do with Dtrace, but this tutorial won’t cover the full scope of what you can do. Instead, a quick anatomy of a Dtrace program will help get you started:

Dtrace_breakdown_v2

  • Probe Description: Consists of a provider, module, function, and name separated by colons. Omitting any of these items will cause the Probe Description to include all matches. You can use the * or ? operators for pattern matching.
    • Provider: The group that contains the set of classes and functions, such as profile, fbt, or io. For this particular tutorial, you’ll primarily use the objc provider to hook into Objective-C method calls.
    • Module: In Objective-C, this section is where you specify the class name you wish to observe.
    • Function: The part of the probe description that can specify the function name that you wish to observe.
    • Name: Although there are different names available based upon your Provider selection, you will only use entry or return, which will match a probe description for the start or the end of a function.
    • Note that you use the $target keyword to match the process ID. You specify the target through the p or c option flags

  • Predicate: An optional expression to evaluate if the action is a candidate for execution. Think of it as the content of an if block.
  • Action: The action to perform. This could be as simple as printing something to the console, or performing more advanced functions.

Much like the LLDB command image lookup -rn {Regex Query}, you can use Dtrace to dump classes and methods in a particular process using the -l flag.

To see a quick example of this, launch Safari, then type the following in Terminal:

sudo dtrace -ln 'objc$target::-*ecret*:entry' -p `pgrep -xn Safari`

The above Dtrace script prints out all the instance methods that have the string ecret contained in a method name. You supply the entry probe description name as all methods have an entry and return, so you’re basically omitting duplicates for your search query.

Note: If you want to learn more about Dtrace, check out this excellent article from the Big Nerd Ranch Folks as well as this Dtrace book. Dtrace is a complex tool, so don’t be too frustrated if you don’t understand everything about it in this quick introduction.

Now that you’ve covered the basics of Dtrace, it’s time to use it to hunt down NSViews of interest. Since there are a ton of views in Xcode, you’d quickly be overwhelmed using LLDB trying to figure out which view is which. Even with LLDB’s breakpoint conditions, debugging something this common in an application can be an ugly process.

Fortunately, being smart with Dtrace will help you immensely. You’ll use Dtrace to hunt down the NSViews that make up Xcode’s titlebar. But how would you do that?

Here’s one way: when a mouse stops moving or clicks down on an NSView, hitTest: fires, which returns the deepest subview within that point. You’ll use Dtrace along with this method to determine which NSView you should use to explore the potential superview and subviews.

Run the following command in Terminal:

sudo dtrace -qn 'objc$target:NSView:-hitTest?:return /arg1 != 0/ { printf("UIView: 0x%x\n", arg1);  }' -p `pgrep -xo Xcode`

Once the script is running, make sure Xcode is the first responder by clicking somewhere within its window. Move your cursor around the Xcode window; as soon as you stop moving your mouse, Dtrace spits out a memory address multiple times. This is because the hitTest: method is fired on multiple NSViews in the view hierarchy.

Navigate to the Xcode title bar and click on the titlebar. Select the most recent address that appeared in Terminal and copy it to your clipboard.

Open a new tab in Terminal, launch LLDB, attach it to Xcode, then print the address you copied over from Dtrace like so:

> lldb
(lldb) pro attach -n Xcode
... 
(lldb) po {The Address you copied from dtrace}
...

You’ll see some output similar to the following:

Dtrace_hitTest_2

Note: Right now, Xcode is now paused via LLDB in Terminal. You can pause Xcode to start the debugger at any time by typing process interrupt or just pro i. In addition, you can resume Xcode at any time by typing continue or just c. Make sure you are ALWAYS aware of the state of LLDB when playing with Xcode, because you might think Xcode is being unresponsive when it’s simply paused in the debugger.

Depending on the spot you clicked in Xcode, you’ll hit one of one of several views. Explore the superview or the subviews of the memory address until you reach IDEActivityView.

Once you find the reference of IDEActivityView, make sure that this NSView is actually the one you want.

Type the following In LLDB:

(lldb) po [{IDEActivityView Address} setHidden:YES]
...
(lldb) c
...

The Xcode title view is now hidden, which shows that this is the the view you want to maninpulate.

Use LLDB to unhide this view:

(lldb) pro i
(lldb) po [{IDEActivityView Address} setHidden:NO]
(lldb) c

Here’s the flow in LLDB, for reference:

LLDB_setHidden

Based on past experience, you know that the contents of this title view changes when you build or stop running a particular program. You can observe this functionality with Dtrace. The IDEActivity prefix is a pretty unique naming convention; you can observe all classes that begin with IDEActivity to see all related things happening behind the scenes.

Back in Terminal, stop the Dtrace program by pressing Control + C and then paste and execute the following Dtrace script into Terminal:

sudo dtrace -qn 'objc$target:IDEActivity*::entry  { printf("%c[%s %s]\n", probefunc[0], probemod, (string)&probefunc[1]); @num[probemod] = count(); }' -p `pgrep -xn Xcode`

This prints out every called method whose classname begins with IDEActivity. Once you exit this program, it will also print the count of how often a particular class’s methods were called.

Start up your Dtrace program, build and run a project in Xcode, then stop the project. Note that the text changes in the title view, then stop the Dtrace program and view the results:

Dtrace_IDEActivity

Look over the information carefully; the solution to how IDEActivityView and friends operate is right there in the console output, but it’s a lot of information to plow through, isn’t it?

Fortunately, you can selectively limit the information displayed to you. Browse through the classes and see if there are any that you can selectively explore. Perhaps IDEActivityReport* would be a good candidate, since it knocks out several classes that look related.

Augment the Dtrace script so it now looks like this:

sudo dtrace -qn 'objc$target:IDEActivityReport*::entry  { printf("%c[%s %s]\n", probefunc[0], probemod, (string)&probefunc[1]); @num[probemod] = count(); }' -p `pgrep -xn Xcode`

Go through the motion of running and stopping Xcode while keeping a close eye on the console. Stop the Dtrace script once you’ve stopped Xcode. Are there any classes that look like they could be candidates for further exploration?

IDEActivityReportStringSegment looks interesting. Narrow your script to focus only on this class; take note of the probemod to probefunc change:

sudo dtrace -qn 'objc$target:IDEActivityReportStringSegment::entry  { printf("%c[%s %s]\n", probefunc[0], probemod, (string)&probefunc[1]); @num[probefunc] = count(); }' -p `pgrep -xn Xcode`

Go through the build, run Xcode, stop Xcode, stop Dtrace motions once again and look at the count of the methods executed by class instances of IDEActivityReportStringSegment. It seems that initWithString:priority:frontSeparator:backSeparator: and initWithString:priority: look like good items to explore.

Open up a fresh LLDB session and run the following:

(lldb) pro attach -n Xcode
(lldb) rb 'IDEActivityReportStringSegment\ initWithString'
Breakpoint 9: 2 locations.
(lldb) br command add
Enter your debugger command(s).  Type 'DONE' to end.
> po NSLog(@"customidentifier %s %@", $rsi, $rdx) 
> c 
> DONE
(lldb) c

Here you create a custom command that executes whenever you call any method that begins with initWithString and belongs to the IDEActivityReportStringSegment class. This custom command prints the Selector method and the contents of self, which is the instance of IDEActivityReportStringSegment, to the console.

In addition, you tagged the NSLog statement to contain the word customidentifier so you can easily hunt it down in the system console.

Go to the system console now and create a grep‘d tail searching for customidentifier. Create a new Terminal tab using ⌘ + t and type the following:

tail -f /var/log/system.log | grep customidentifier

Build and run in Xcode in order to populate the IDEActivityReportStringSegment changes. This prints out all the messages you added in your custom LLDB command hook:

LLDB_String_Hunting

Comparing the output from the console to the output from Xcode’s titlebar view shows that these are the items you are in fact looking for! :]

Time to Swizzle

Create a new Objective-C Category. Specify the Class as NSObject and name the category Rayrolling IDEActivityReportStringSegment

Add the following code to NSObject+Rayrolling_IDEActivityReportStringSegment.m:

#import "NSObject+Rayrolling_IDEActivityReportStringSegment.h"
#import "NSObject+MethodSwizzler.h"
#import "Rayrolling.h"
 
@interface NSObject ()
 
// 1
- (id)initWithString:(id)arg1 priority:(double)arg2 frontSeparator:(id)arg3 backSeparator:(id)arg4;
@end
 
@implementation NSObject (Rayrolling_IDEActivityReportStringSegment)
 
// 2
+ (void)load
{
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    [NSClassFromString(@"IDEActivityReportStringSegment") swizzleWithOriginalSelector:@selector(initWithString:priority:frontSeparator:backSeparator:) swizzledSelector:@selector(Rayrolling_initWithString:priority:frontSeparator:backSeparator:) isClassMethod:NO];
  });
}
 
- (id)Rayrolling_initWithString:(NSString *)string priority:(double)priority frontSeparator:(id)frontSeparator backSeparator:(id)backSeparator
{
 
  // 3
  static NSArray *lyrics;
 
  // 4
  static NSInteger index = 0;
  static dispatch_once_t onceToken;
 
  // 5
  dispatch_once(&onceToken, ^{
    lyrics = @[@"Never gonna live you up.",
               @"Never gonna set you down."];
 
 
  });
 
  // 6
  index = index >= lyrics.count -1 ? 0 : index + 1;
 
  // 7
  if  ([Rayrolling isEnabled]) {
    return [self Rayrolling_initWithString:lyrics[index] priority:priority frontSeparator:frontSeparator backSeparator:backSeparator];
  }
  return [self Rayrolling_initWithString:string priority:priority frontSeparator:frontSeparator backSeparator:backSeparator];
}
 
@end

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

  1. You need to forward declare the private class initializer initWithString:priority:frontSeparator:backSeparator:, otherwise the compiler will be cranky.
  2. load is used to swizzle the private method with the one that will follow below.
  3. Since you’re using a category to swap this method, instance variables are tricky to create in a category. You can add instance variables to existing classes using associated objects, but that’s a whole tutorial unto itself. Therefore, you use a static NSArray to keep the object around once the method has finished.
  4. You use the same static trick to help index survive method calls as well.
  5. Use dispatch_once to initialize the lyrics NSArray.
  6. Increment index and reset it if it gets out of bounds
  7. Check if the plugin is enabled. If so, augment the string parameter; otherwise, use the default string parameter.

As you can see, using the right tools for the job helps you quickly hunt down items of interest. However, there’s always more than one way to find what you’re looking for — and you’ll discover how to also find what you’re looking for through heap analysis.

Revisiting IDEActivityView Through The Heap

It’s time for you to explore Xcode’s IDEActivityView and IDEActivityReportStringSegment again, but you’ll do it in a slightly different fashion.

Until now, you’ve only explored from the top down, where you find a Class, then somehow find its instance(s) in memory, then explore the contents of those properties. It would be ideal to start from the reverse direction and go up the reference chain to find the objects that point to it.

Fortunately, Xcode ships with some nifty Python scripts that allow you to do just that.

Kill any existing LLDB and Dtrace sessions in Terminal and restart Xcode. Start a fresh Xcode and LLDB session. In LLDB perform the usual Xcode-attaching dance and add the following new command script:

(lldb) pro at -n Xcode 
(lldb) command script import lldb.macosx.heap
"malloc_info", "ptr_refs", "cstr_refs", and "objc_refs" commands have been installed, use the "--help" options on these commands for detailed help.

This script loads several incredibly useful functions in the LLDB process.

  • malloc_info: Displays detailed information about the current heap object. Incredibly useful in combination with the MallocStackLogging environment variable.
  • ptr_refs: Given an address in heap memory, this will find other objects that point to this in memory.
  • cstr_refs: Given a char *, finds the occurrences of it in memory.
  • objc_refs: Finds the instances of a particular class in memory.

You’ll look at the easiest to understand one first: objc_refs.

In LLDB, find all the instances of IDEActivityView with the following script:

(lldb) objc_refs -o IDEActivityView
Searching for all instances of classes or subclasses of "IDEActivityView" (isa=0x10fffe650)
0x00007faaee9cbf30: malloc(   304) -> 0x7faaee9cbf30 IDEActivityView.DVTLayerHostingView.NSView.NSResponder.NSObject.isa
<IDEActivityView: 0x7faaee9cbf30>

This prints out all instances of IDEActivityView. The -o option prints the object, and thus the object’s description method)

With one simple command you’ve found the instances in memory that belong to this type of object. This trick also works for subclasses whose superclass you want to find.

Using the memory address spat out by objc_refs, you can explore the instance of IDEActivityView instance variables like so:

(lldb) malloc_info -t 0x7faaee9cbf30
0x00007faaee9cbf30: malloc(   304) -> 0x7faaee9cbf30 IDEActivityView.DVTLayerHostingView.NSView.NSResponder.NSObject.isa (IDEActivityView) *addr = {
  DVTLayerHostingView = {
    NSView = {
      NSResponder = {
...

But wait — that’s not all! You can even get the reference to all the other objects pointing to a particular memory address:

(lldb) ptr_refs  0x7faaee9cbf30
0x00007faaeed9a308: malloc(    16) -> 0x7faaeed9a300 + 8     
0x00007faaeedb4148: malloc(   176) -> 0x7faaeedb4140 + 8      IDEActivityViewBackgroundButton.NSButton.NSControl.NSView.NSResponder._nextResponder
0x00007faaeedb4190: malloc(   176) -> 0x7faaeedb4140 + 80     IDEActivityViewBackgroundButton.NSButton.NSControl._aux.NSObject.isa
0x00007faaeedb4928: malloc(   160) -> 0x7faaeedb4920 + 8      NSView.NSResponder._nextResponder
...
Note: These commands, combined with your im loo -rn {classmethod regex} queries, can help you quickly find and explore instances of classes live in memory. Just make sure that you always pause LLDB first before you try these functions, or else they won’t work!

You can even take it a step further — there is a cool environment variable named MallocStackLogging that takes a backtrace of the stack whenever you instantiate an object. Although many items can point to an object, this can help you figure out who the “ultimate owner” of an object is.

While LLDB is still attached to Xcode, you will kill the Xcode process and relaunch it with the MallocStackLogging environment variable via LLDB:

(lldb) pro kill 
Process 65196 exited with status = 9 (0x00000009)
(lldb) pro launch -v MallocStackLogging=1 -n
Process 67920 launched: '/Applications/Xcode.app/Contents/MacOS/Xcode' (x86_64)
Note: If you are lazy and are constantly killing LLDB/Xcode sessions, launchctl might prove to be an easier way of launching this environment variable:
launchctl setenv MallocStackLogging 1

This sets MallocStackLogging to true for every process created by launchd here on out. Be sure to remove this when you are done if you do go this route with the following command:

launchctl unsetenv MallocStackLogging

To test this all out, make sure the Xcode editor does not have Rayrolling enabled under the Edit menu as below:

Enable_RayRolling

Now, with any project having source code open in Xcode, build and run the project. While the project is actively running, you will see the IDEActivityView (just pretend you don’t know it’s called that for the moment) change its contents as the build completes and runs.

Pause the execution of the program and reload the heap functions if needed with the following:

(lldb) pro i 
(lldb) command script import lldb.macosx.heap
"malloc_info", "ptr_refs", "cstr_refs", and "objc_refs" commands have been installed, use the "--help" options on these commands for detailed help.
Note: If constantly retyping these commands is annoying to you, check out how to set up command aliases in the ~/.lldbinit file. The contents of this file will be called each time you create an instance of LLDB.

Now use the cstr_ref function with the string contents of the Xcode title bar. For example, if the project name was Rayrolling, your title bar would have something like Running Rayrolling : Rayrolling:

(lldb) cstr_ref "Running Rayrolling : Rayrolling" 
0x0000000118cb21d0: malloc(    32) -> 0x118cb21d0
0x000000012079ae21: malloc(    48) -> 0x12079ae10 + 17     __NSCFString1 bytes after __NSCFString
0x00000001207a3bb3: malloc(    64) -> 0x1207a3b90 + 35     __NSCFString19 bytes after __NSCFString
0x00000001223834d1: malloc(    48) -> 0x1223834c0 + 17     __NSCFString1 bytes after __NSCFString
0x000000011f9126a1: malloc(    48) -> 0x11f912690 + 17     __NSCFString1 bytes after __NSCFString

As you can see, the majority of the references are NSString references. You can’t do much with this information by itself, so you will need to figure out how these items were created. Fortunately with MallocStackLogging, this is super easy!

(lldb) cstr_ref "Running Rayrolling : Rayrolling"  -s

This prints out the stack frame whenever this particular char * is created.

Go through all the stack trace instances. Since these are in memory, the number of memory addresses as well as the address location will be different on your computer depending on how you’ve interacted with Xcode.

By reading through the stack traces, you’ll gain some insight into the grouping of classes that are responsible for this area of Xcode.

For example, depending on when you launched this LLDB query you might see classes such as IDEActivityScrollingTextLayer, IDERunOperation or IDEActivityView, etc.

You can also use the ptr_ref on the output of cstr_ref to see what items are retaining the strings.

Miscellaneous Random Exploration Tricks

Finding the correct API in Xcode is tricky, since you’re trying to filter thousands upon thousands of classes and methods.

Using smart lldb regular expressions can greatly aid in finding the item you’re looking for. Sometimes the best place to get a good footing from anywhere in code is to use a Singleton. See if there are any singletons that exist in Xcode that are worth checking out.

While LLDB is paused and attached to Xcode, run the following:

(lldb) i loo -rn "\+\[IDE.*\ shared"

This will look up all class names beginning with “IDE” having a class method that begins with “shared”.

An attractive alternative could be:

(lldb) i loo -rn "\+\[[A-Za-z]*\ [A-Za-z]*\]"

This will print all the class methods with no arguments.

As you saw earlier, you can hunt down classes easily using this Python script given their name. Another popular tool for finding classes is a tool called class-dump; it can be downloaded here. It’s an attractive alternative to the im loo -rn {regex} LLDB command, as it produces much cleaner “header-like” output.

The only downside to this tool is that you have to limit your selection to specific frameworks or plugins, while the image lookup command will look everywhere in all the frameworks & plugins found in Xcode.

Where to Go From Here?

Here’s the completed Rayrolling project from Part 2.

In this article you’ve learned the basics of Dtrace and have explored some advanced LLDB functions available to you.

If you want to learn more about Dtrace, you can read another excellent article about it at obcj.io and get the official documentation on Dtrace here.

In part 3 of this tutorial, you’ll focus on breaking down assembly, and you’ll learn about a neat tool named Cycript.

As always, if you have questions or comments on this tutorial, feel free to join the forum discussion below!

How To Create an Xcode Plugin: Part 2/3 is a post from: Ray Wenderlich

The post How To Create an Xcode Plugin: Part 2/3 appeared first on Ray Wenderlich.

Video Tutorial: Unity 2D Basics Part 2: Sprites


How To Create an Xcode Plugin: Part 3/3

$
0
0
Who needs documentation when Ray will sing to you instead?

Who needs documentation when Ray will sing to you instead?

Update note: This tutorial has only been tested with Xcode 6.3.2 — if you’re working with another version of Xcode, your experience might not match up perfectly with this tutorial.

Welcome to the third and final part in this tutorial series on creating an Xcode Plugin. In the second part of this tutorial, you explored Xcode with LLDB and Dtrace while showcasing Ray’s hit song, Never Gonna Live You Up. In this tutorial, you’ll finish up your Rayrolling pranks by swapping any documentation URL requests for a YouTube link which Rayrolls the victim:

Plugin_Swizzle_Documentation

You’ll make use of the Cycript tool to dig into the x86_64 assembly behind Xcode to determine how to bend Xcode to your will. While this tutorial will walk you through each piece of assembly code, reading Part I and Part II of Mike Ash’s series on x86_64 assembly will definitely help you get the most out of this tutorial.

You’ll continue with the same Rayrolling project from before; if you didn’t work through Part 2, or just want a fresh start, you can download the finished Rayrolling Project from Part 2 here.

Getting Started

Cycript is a tool is authored by @saurik of Cydia fame, which lets you explore and modify code on iOS or OS X using a hybrid of Javascript and Objective-C. You can explore Xcode’s contents in memory while making your plugin development life considerably easier.

Download Cycript here and extract it to a convenient location.

Navigate to the Cycript.lib subdirectory and copy all of the dylibs to /usr/lib/. Copy the cycript binary found in the same directory of the dylibs to /usr/local/bin.

Open the Rayrolling project and navigate to Rayrolling.m. Add the following import header to the top of the file:

#import <dlfcn.h>

Now, add the following code to the beginning of pluginDidLoad::

// 1
void *handle = dlopen("/usr/lib/libcycript.dylib", RTLD_NOW); 
 
// 2
void (*listenServer)(short) = dlsym(handle, "CYListenServer");
 
// 3
(*listenServer)(54321);

Taking each numbered comment in turn:

  1. Although the Cycript zip contains a Framework, you’re using the dynamic library directly instead. dlopen opens the dynamic library given by the char *. You specify to load the contents immediately with RTLD_NOW.
  2. Using dlsym, you create a function pointer to a method you’ll need to start the Cycript server.
  3. Finally, you call CYListenServer and specify that it broadcast itself on a specific port using C’s good ‘ol function pointers.

Build and run the Xcode plugin to generate and install it. Once the child Xcode appears, stop and quit all running Xcodes and relaunch. With a new instance of Xcode in memory, head to Terminal and type the following:

cycript -r 127.0.0.1:54321
cy#

This launches Cycript and listens to the IP address (localhost) for broadcasts on port 54321. To exit Cycript, type Ctrl-D.

If you attached Cycript without issue, you’ll see the cy# prompt. Cycript will launch and attach itself to Xcode. Cycript’s “Javascript-y” syntax makes debugging incredibly easy with its built-in tab autocompletion.

Want to see all the instance variables for a particular class? Just prepend * to your query and it will print out all instance variables for a particular instance:

cy# *NSApplication.sharedApplication.delegate
...

This is much like the malloc_info -t {heap address}you saw in the previous tutorial. The output is presented as instance variables instead of properties; you access these instance variables like so:

cy# NSApplication.sharedApplication.delegate->_sourceControlUIHandler

You also dump the contents of the _sourceControlUIHandler by using the same technique.

Note: If you want to see what else you can do with Cycript, check out iPhoneDevWiki’s Cycript page for some useful tricks. Be sure to read up on printMethods(); it’s incredibly useful.

Much like the heap LLDB script you explored in the previous tutorial, Cycript also has a command called choose, which hunts down all the instances of a particular class in memory:

cy# choose(NSViewController)
...
cy# choose(NSViewController)[0]
#"<IDELicenseAgreementViewController: 0x7faa3d244410>"
cy# var ivc = _ 
#"<IDELicenseAgreementViewController: 0x7faa3d244410>"
cy# *ivc
{isa:IDELicenseAgreementViewController,_nextResponder:null,_nibName:@"IDELicenseAgreementViewController",_nibBundle:#"NSBundle </Applications/Xcode.app/Contents/Frameworks/IDEKit.framework> (loaded)",_representedObject:null,_title:null,view:null,_topLevelObjects:null,_editors:null,_autounbinder:null,_designNibBundleIdentifier:null,__privateData:#"<_NSViewControllerPrivateData: 0x7faa3fd17370>",_viewIsAppearing:0,_delayViewDidAppear:0,_isContentViewController:0,_reserved:0,_licenseAgreementHelper:#"<DVTLicenseAgreementHelper: 0x7faa3d249610>",_agreementStatus:0,_licenseAgreement:null,_licenseAgreementTextView:null,_foregroundContentView:null,_licenseOnly:1,_licenseSubtitle:null}

This sets the contents of the Javascript ivc variable to be the first NSViewController returned in the choose(NSViewController) array.

However, there’s something very special about Saurik’s implementation of choose. Unlike objc_ref, which you learned about in the previous tutorial, choose returns an actual NSArray (or Javascript array!) of all the objects that it found in the heap. This means that you can run complex filters on any array of objects to determine how you want to filter them!

For example, try the follwing in Cycript:

cy# choose(NSTextView)
...
cy# choose(NSTextView).filter(function(object) { return  [[object string] containsString:@"Copyright"]  })

Using a mashup of Objective-C and Javascript, you can find all the NSTextView instances on the heap and filter them for only the ones with the word “Copyright” in the string property.

This feature will prove invaluable in the section to come.

Hunting For Documentation

With Cycript as your brand new best friend, you’ll hunt down all the NSViewControllers that belong to a specific window.

In Xcode, select Window\Documentation and API Reference.

Try and figure out how to filter out all the NSViewControllers that belong to this particular window using Cycript. The solution is below if you need a bit of help.

Solution Inside: NSViewController Search SelectShow>

This filters the NSViewController array down considerably to a size that you can navigate on your own.

Use the familiar technique of hiding and showing NSViewController views to explore which NSViewControllers are where:

cy# var vcs = _ 
...
cy# vcs[0].view.hidden = true 
true 
cy# vcs[0].view.hidden = false 
false

Views automatically update when you modify them in Cycript; you don’t have to resume or pause execution in the debugger. You’ll wonder how you went this long without this feature! :]

By going through the NSViewController array in a systematic fashion, you can build a mental picture of what each NSViewController is responsible for by toggling the NSView‘s hidden property. I’ve done this for you, and here’s a visualization of Xcode’s Documentation window:

Xcode_Documentation_Window

Looking at the above image, it looks like IDEDocWebViewContentViewController might be a good place to start snooping to see what you can modify.

In Cycript:

cy# choose(IDEDocWebViewContentViewController)
[#"<IDEDocWebViewContentViewController: 0x7faa42269aa0 representing: (null)>"]
cy# choose(IDEDocWebViewContentViewController)[0]
#"<IDEDocWebViewContentViewController: 0x7faa42269aa0 representing: (null)>"
cy# var wvc = _ 
#"<IDEDocWebViewContentViewController: 0x7faa42269aa0 representing: (null)>"
cy# *wvc 
...

Wading though the instance variables of IDEDocWebViewContentViewController, there’s an interesting one called _webView. You can try to find a property equivalent to access this instance variable:

cy# wvc.webView
#"<WebView: 0x7faa41b80e50>"

Now, where is it located on the screen?

cy# wvc.webView.hidden = true 
cy# wvc.webView.hidden = false

IDE_Doc_Hidding_view

Aha — webView is responsible for the detailed documentation section in the lower right. You’ve found the NSViewController and the class of interest to start figuring out where to perform the Rayrolling!

Cycript Swizzling

You found the class that will perform your Rayroll, but you need to figure out how the class works. Cocoa’s WebView has many methods, so you need to find out which ones Xcode uses behind the scenes.

Perusing the the documentation for WebView indicates that WebFrame performs much of the network interaction with URLs. That would be a good place to start looking.

Perhaps a quick Dtrace script will do the trick. After all, you only care about what the WebView‘s WebFrame is doing, not what it’s interacting with.

Open a new session in Terminal that does not have Cycript or LLDB. From there, type the following:

sudo dtrace -n 'objc$target:WebFrame::entry { @[probefunc] = count() }' -p `pgrep -xo Xcode`

With this script running, click around the documentation, and search for something like NSView. Stop the Dtrace script and look through the results.

It should be pretty obvious that WebView‘s WebFrame performs loadRequest: when fetching new data.

You’re now one step closer to pulling this off. You’ve found the view controller, the class of interest, and the method of interest. Instead of the usual code, swizzle, build cycle, you can use Cycript to dynamically swizzle this method without having to restart Xcode at all. That way you can see if this trick works, without all the implementation overhead in case it fails.

Back in Cycript, hunt down loadRequest: and assign it to a global Javascript variable:

cy# original_WebFrame_method = WebFrame.messages['loadRequest:']
0x11f4141e0

Now paste the following contents in Cycript:

function swizzled_loadRequest(request) { 
 var swizzledURL = [new NSURL initWithString:@"https://www.youtube.com/watch?v=ce-_0opZzh0"];
 var swizzledRequest = [new NSURLRequest initWithURL: swizzledURL];
 original_WebFrame_method.call(this, swizzledRequest); 
}

This is the Javascript equivalent function for a swizzled loadRequest:. You throw out the original request and make a new request to the lovely Rayrolling Video.

Now swap the methods:

WebFrame.messages['loadRequest:'] = swizzled_loadRequest

Be very careful that there are no syntax errors in your swizzled function. The smallest typo will cause Xcode to crash. Which, come to think of it, is pretty much par for the course for Xcode. :]

ragecomic2

Try searching for something like NSObject in the documentation and press Enter.

But wait… instead of opening up the YouTube page in the Xcode documentation’s WebView, Xcode decided to dump you to your default browser and open it from there. This is clearly unacceptable — Xcode must bend to your will, not the other way around! :]

You’ll need to figure out what class is preventing the WebView from doing this and correct its behavior.

Since you will be viewing assembly, it would be best to see the code execution path when actually testing against the failed YouTube URL. Now that you’ve done the initial testing with Cycript swizzling, it’s time to implement it “for real” in your plugin.

Create a new WebFrame Category and name it Rayrolling WebFrame.

In WebFrame+Rayrolling_WebFrame.h, add the following header to the top so you can access this class correctly:

#import <WebKit/WebKit.h>

Now open WebView+Rayrolling_WebFrame.m and replace its contents with the following:

#import "WebFrame+Rayrolling_WebFrame.h"
#import "NSObject+MethodSwizzler.h" 
#import "Rayrolling.h"
 
@implementation WebFrame (Rayrolling_WebFrame)
 
+ (void)load {
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{ 
    [self swizzleWithOriginalSelector:@selector(loadRequest:) swizzledSelector:@selector(Rayrolling_loadRequest:) isClassMethod:NO];
  });
}
 
- (void)Rayrolling_loadRequest:(NSURLRequest *)request {
  if ([Rayrolling isEnabled]) {
    NSURL *url = [NSURL URLWithString:@"https://www.youtube.com/watch?v=ce-_0opZzh0"];
    NSURLRequest *rickrollingRequest = [NSURLRequest requestWithURL:url];
    [self Rayrolling_loadRequest:rickrollingRequest];
  } else {
    [self Rayrolling_loadRequest:request];
  }
}
@end

Build and run this to update the plugin, then quit and relaunch Xcode so the updated contents are loaded into memory.

Wading Through Assembly

Typically, when either an iOS or OS X application launches another application in this sort of manner, there are a very small set of APIs that could be the culprit. One very common one is openURL:.

Fire up a new tab in the Terminal, launch LLDB, and attach it to Xcode. From there, set a breakpoint on any class that has this particular method:

lldb
(lldb) pro at -n Xcode 
...
(lldb) rb openURL: 
...
(lldb) c

Go back to the Documentation window and try searching for a new item, say, NSString. Immediately upon hitting Enter in the Documentation Window, LLDB breaks on -[IDEWorkspace openURL:]. Bingo!

Just for giggles, make sure this is the correct URL:

(lldb) po $rdx 
https://www.youtube.com/watch?v=ce-_0opZzh0

Good. So now you need to see how it was called:

(lldb) bt 5
* thread #1: tid = 0x2ea1d, 0x00007fff88b529bf AppKit`-[NSWorkspace openURL:], queue = 'com.apple.main-thread', stop reason = breakpoint 1.6
  * frame #0: 0x00007fff88b529bf AppKit`-[NSWorkspace openURL:]
    frame #1: 0x0000000119f5ab47 IDEDocViewer`-[IDEDocWebViewContentViewController haveWorkspaceOpenOrRevealURL:] + 577
    frame #2: 0x0000000119f5a5e1 IDEDocViewer`-[IDEDocWebViewContentViewController webView:decidePolicyForNavigationAction:request:frame:decisionListener:] + 607
    frame #3: 0x000000011d19cbd2 Rickrolling`-[NSViewController(self=0x00007fa3d75b3f20, _cmd=0x00007fff89c18f65, webView=0x00007fa3d75c46c0, actionInformation=0x00007fa3dadf5f40, request=0x00007fa3d2dae450, frame=0x00007fa3d73cbee0, listener=0x00007fa3dceee600) Rr_swzl_webView:decidePolicyForNavigationAction:request:frame:decisionListener:] + 274 at NSViewController+IDEDocWebViewContentViewController_Swizzler.m:35
    frame #4: 0x00007fff86b49ebc CoreFoundation`__invoking___ + 140

Looking at frame #2, it seems that this would be the method which makes the decision to launch it internally in the Documentation window or to hand it off to the default browser.

Doing a search on this method indicates that webView:decidePolicyForNavigationAction:request:frame:decisionListener: is defined in the WebPolicyDelegate protocol.

According to the Apple documentation on this protocol, the decisionListener implements WebPolicyDecisionListener which means, based upon some internal logic, you will call [listener ignore] if you don’t want to not load the content at all, [listener download] if you want to download the content, or [listener use] if you want to open the URL right in the WebView.

There’s no other way around it. You need to see what’s happening inside this method. Back to the magical land of assembly you thought you escaped in the first tutorial! :]

Note: If you aren’t fully caffeinated yet and want to skip the disassembly analysis, skip ahead to the final reconstructed method implementation.

In LLDB:

(lldb) di -n '-[IDEDocWebViewContentViewController webView:decidePolicyForNavigationAction:request:frame:decisionListener:]'

This dumps out a fair bit of assembly. It’s OK — don’t assume the fetal position and huddle in the corner. You’ll go through this assembly section by section and you’ll see that it’s not that bad.

Note: You’ll notice that the addresses are different on your workstation — this is to be expected.
0x114da2382 <+0>:   pushq  %rbp
0x114da2383 <+1>:   movq   %rsp, %rbp
0x114da2386 <+4>:   pushq  %r15
0x114da2388 <+6>:   pushq  %r14
0x114da238a <+8>:   pushq  %r13
0x114da238c <+10>:  pushq  %r12
0x114da238e <+12>:  pushq  %rbx                     ; // 1
0x114da238f <+13>:  subq   $0x58, %rsp
0x114da2393 <+17>:  movq   %r8, %r12
0x114da2396 <+20>:  movq   %rcx, %r13
0x114da2399 <+23>:  movq   %rdi, -0x58(%rbp)
0x114da239d <+27>:  movq   0x10(%rbp), %r15
0x114da23a1 <+31>:  movq   %rdi, -0x30(%rbp)         ; // 2 
0x114da23a5 <+35>:  movq   %rsi, -0x38(%rbp)
0x114da23a9 <+39>:  movq   0x61f20(%rip), %r14       ; (void *)0x00007fff95678050: objc_retain
0x114da23b0 <+46>:  movq   %rdx, %rdi
0x114da23b3 <+49>:  callq  *%r14
0x114da23b6 <+52>:  movq   %rax, -0x40(%rbp)
0x114da23ba <+56>:  movq   %r13, %rdi
0x114da23bd <+59>:  callq  *%r14
0x114da23c0 <+62>:  movq   %rax, -0x48(%rbp)
0x114da23c4 <+66>:  movq   %r12, %rdi
0x114da23c7 <+69>:  callq  *%r14
0x114da23ca <+72>:  movq   %rax, %rbx               ; // 3 
0x114da23cd <+75>:  movq   %rbx, -0x50(%rbp)
0x114da23d1 <+79>:  movq   %r15, %rdi
0x114da23d4 <+82>:  callq  *%r14
0x114da23d7 <+85>:  movq   %rax, %r14                ; // 4

Take a deep breath; here’s what all that means:

  1. After this instruction, all the scratchspace registers are now pushed. The pushq operand saves the state of the register so it can be popq‘d at a later time when leaving the function.
  2. The $rdi register, which holds the WebPolicyDecisionListener (aka the IDEDocWebViewContentViewController instance) is set to an address that is -0x30 below the address of $rbp. You can access it in LLDB lke so: x/gx '$rbp - 0x30'. The address spat out will be the address which you can then po in LLDB.
  3. Here’s the fun part of assembly: navigating which register stores what, and where. The contents of the return register $rax are copied to $rbx. $rax was set by the retain call in $r14 with an object passed in by $r12. $r12 was set by $r8. As you learned earlier, $r8 is the 3rd parameter passed into a function (not including the “self” $rdi register parameter nor the $rsi Selector register). Looking at the documentation again for this method implies that as of right now, $rbx should contain the NSURLRequest instance.
  4. Yep, the assembly is still performing the setup. As you can see, $r14 is passed the retain Selector for memory management, so the assembly is simply going through and retaining the items so they don’t disappear and cause a crash.

Ok…that wasn’t so bad. Onto the next section:

0x114da23da <+88>:  movq   0x7fc17(%rip), %rsi     ; "URL"
0x114da23e1 <+95>:  movq   0x61ed8(%rip), %r12     ; (void *)0x00007fff956700c0: objc_msgSend
0x114da23e8 <+102>: movq   %rbx, %rdi              ; // 1 
0x114da23eb <+105>: callq  *%r12
0x114da23ee <+108>: movq   %rax, %rdi
0x114da23f1 <+111>: callq  0x114de6bee             ; symbol stub for: objc_retainAutoreleasedReturnValue
0x114da23f6 <+116>: movq   %rax, %r15
0x114da23f9 <+119>: movq   0x7fb28(%rip), %rsi     ; "absoluteString"
0x114da2400 <+126>: movq   %r15, %rdi
0x114da2403 <+129>: callq  *%r12
0x114da2406 <+132>: movq   %rax, %rdi
0x114da2409 <+135>: callq  0x114de6bee             ; symbol stub for: objc_retainAutoreleasedReturnValue
0x114da240e <+140>: movq   %rax, %rbx
0x114da2411 <+143>: movq   0x7fde8(%rip), %rsi     ; "isEqualToString:" // 2 
0x114da2418 <+150>: leaq   0x641a1(%rip), %rdx     ; @"about:blank"
0x114da241f <+157>: movq   %rbx, %rdi
0x114da2422 <+160>: callq  *%r12
0x114da2425 <+163>: movb   %al, %r12b              ; // 3 
0x114da2428 <+166>: movq   0x61e99(%rip), %r13     ; (void *)0x00007fff95678440: objc_release
0x114da242f <+173>: movq   %rbx, %rdi
0x114da2432 <+176>: callq  *%r13
0x114da2435 <+179>: movq   %r15, %rdi
0x114da2438 <+182>: callq  *%r13
0x114da243b <+185>: testb  %r12b, %r12b            ; // 4 
0x114da243e <+188>: je     0x114da246e             ; <+236> // 5
  1. Remember that $rbx contains the NUSRLRequest at this point.
  2. This section is easy; just by looking at the disassembly’s comments, you can tell that the URL is being compared to @"about:blank"
  3. The result of isEqualToString: is now passed from $al to $r12b. $al is a register only 8 bits long. It wouldn’t make sense to store a BOOL value in 64 bits.
  4. The testb instruction compares the destination with the source operand. If the value in $r12b is a 1, then the ZF register flag will be a 0.
  5. Based upon the ZF register this instruction jumps to 0x119f5a46e if the value is 1. Another way to summarize the last two operands: if the value is not equal to @"about:blank", then jump to 0x119f5a46e
  6. .

You’re starting to see the method come together! So far you have the following:

- (void)webView:(WebView *)webView
decidePolicyForNavigationAction:(NSDictionary *)actionInformation
        request:(NSURLRequest *)request
          frame:(WebFrame *)frame
decisionListener:(id<WebPolicyDecisionListener>)listener
{
  if ([[[request URL] absoluteString] isEqualToString:@"about:blank"]) {
    // TODO 
  } else {
    // jump to 0x119f5a46e
  }
}

Onto the next section:

0x114da2440 <+190>: movq   0x7fdc1(%rip), %rsi     ; "ignore"
0x114da2447 <+197>: movq   %r14, %rdi
0x114da244a <+200>: callq  *0x61e70(%rip)          ; (void *)0x00007fff956700c0: objc_msgSend // 1 
0x114da2450 <+206>: movq   -0x40(%rbp), %r13
0x114da2454 <+210>: movq   -0x48(%rbp), %rax
0x114da2458 <+214>: movq   -0x50(%rbp), %r15
0x114da245c <+218>: movq   %r14, %r12
0x114da245f <+221>: movq   %rax, %r14
0x114da2462 <+224>: movq   0x61e5f(%rip), %rbx     ; (void *)0x00007fff95678440: objc_release
0x114da2469 <+231>: jmp    0x114da2621             ; <+671> // 2 
0x114da246e <+236>: movq   %r14, -0x60(%rbp)
0x114da2472 <+240>: movq   0x7fd9f(%rip), %rsi     ; "_allowURLRequest:webView:" // 3 
0x114da2479 <+247>: movq   -0x58(%rbp), %r15
0x114da247d <+251>: movq   %r15, %rdi
0x114da2480 <+254>: movq   -0x50(%rbp), %r14
0x114da2484 <+258>: movq   %r14, %rdx
0x114da2487 <+261>: movq   -0x40(%rbp), %rbx
0x114da248b <+265>: movq   %rbx, %rcx
0x114da248e <+268>: callq  *0x61e2c(%rip)          ; (void *)0x00007fff956700c0: objc_msgSend // 4
0x114da2494 <+274>: testb  %al, %al  				       ; // 5
0x114da2496 <+276>: movq   %rbx, %r13
0x114da2499 <+279>: je     0x114da25a4             ; <+546> // 6
  1. It looks like ignore is called on the listener. This happens if the URL absoluteString is equal to @"about:blank".
  2. If absoluteString is equal to @"about:blank", there’s some further stack movement followed by a jump to some address further down.
  3. This is a new interesting Selector of IDEDocWebViewContentViewController. Disassembling this class is an exercise left to the reader. :] To get started in LLDB: di -n '-[IDEDocWebViewContentViewController _allowURLRequest:webView:]'.
  4. _allowURLRequest:webView: is now being called.
  5. This tests whether _allowURLRequest:webView: returned 1 or 0
  6. The code jumps if ZF is set to 1. That is, if _allowURLRequest:webView: returns false, the jump instruction will be executed.

You can now build out your pseudo-code a little bit further.

- (void)webView:(WebView *)webView
decidePolicyForNavigationAction:(NSDictionary *)actionInformation
        request:(NSURLRequest *)request
          frame:(WebFrame *)frame
decisionListener:(id<WebPolicyDecisionListener>)listener
{
  if ([[[request URL] absoluteString] isEqualToString:@"about:blank"]) {
    [listener ignore];
    // Do some stack cleanup logic
    // 0x114da2469 <+231>: jmp    0x114da2621      
 
  } else if ([self _allowURLRequest:request webView:webView]) {
 
  } else {
  	// 0x114da2499 <+279>: je     0x114da25a4               ; <+546>
  }
}

On to the final section — you’re almost there!

ragecomic

0x114da249f <+285>: movq   %r14, %r13
0x114da24a2 <+288>: movq   0x61d87(%rip), %rax     ; (void *)0x00007fff788d7800: WebActionModifierFlagsKey  						    ; 
0x114da24a9 <+295>: movq   (%rax), %rdx				     ; // 1 
0x114da24ac <+298>: movq   0x7f5dd(%rip), %rsi     ; "objectForKey:"
0x114da24b3 <+305>: movq   -0x48(%rbp), %rdi       ; // 2 
0x114da24b7 <+309>: movq   0x61e02(%rip), %r12     ; (void *)0x00007fff956700c0: objc_msgSend
0x114da24be <+316>: callq  *%r12
0x114da24c1 <+319>: movq   %rax, %rdi
0x114da24c4 <+322>: callq  0x114de6bee             ; symbol stub for: objc_retainAutoreleasedReturnValue
0x114da24c9 <+327>: movq   %rax, %rbx
0x114da24cc <+330>: movq   0x7fd4d(%rip), %rsi     ; "unsignedIntegerValue" // 3
0x114da24d3 <+337>: movq   %rbx, %rdi
0x114da24d6 <+340>: callq  *%r12
0x114da24d9 <+343>: movq   %rax, %r14
0x114da24dc <+346>: movq   %rbx, %rdi
0x114da24df <+349>: callq  *0x61de3(%rip)          ; (void *)0x00007fff95678440: objc_release
0x114da24e5 <+355>: testl  $0x100000, %r14d        ; // 4
0x114da24ec <+362>: je     0x114da25fb             ; <+633> // 5

And here’s the location where the above instruction was jumping to…

0x114da25fb <+633>: movq   0x7fc26(%rip), %rsi     ; "use" // 6 
0x114da2602 <+640>: movq   -0x60(%rbp), %r12
0x114da2606 <+644>: movq   %r12, %rdi
0x114da2609 <+647>: callq  *0x61cb1(%rip)          ; (void *)0x00007fff956700c0: objc_msgSend
0x114da260f <+653>: movq   %r13, %r15
0x114da2612 <+656>: movq   0x61caf(%rip), %rbx     ; (void *)0x00007fff95678440: objc_release
0x114da2619 <+663>: movq   -0x40(%rbp), %r13
0x114da261d <+667>: movq   -0x48(%rbp), %r14
0x114da2621 <+671>: movq   %r12, %rdi
  1. The WebActionModifierFlagsKey is loaded into $rdx.
  2. The ‘$rbp – 0x40′ address contained the navigationAction NSDictionary parameter. It’s loaded into the “self” register for objc_msgSend.
  3. The result seems to be sending unsignedIntegerValue to another object, probably an NSNumber.
  4. This tests unsignedIntegerValue against 0x100000. This is likely some internal int or enum hidden by the compiler.
  5. If the value is not equal to 0x100000, then jump to the specified address.
  6. Following the address jump, if the value is not equal to 0x100000, you will finally see logic that uses the use command.

Here’s what the final reconstructed method looks like now:

- (void)webView:(WebView *)webView
decidePolicyForNavigationAction:(NSDictionary *)actionInformation
        request:(NSURLRequest *)request
          frame:(WebFrame *)frame
decisionListener:(id<WebPolicyDecisionListener>)listener
{
  if ([[[request URL] absoluteString] isEqualToString:@"about:blank"]) {
    [listener ignore];
    // Do some stack cleanup logic
    // 0x114da2469 <+231>: jmp    0x114da2621      
  } else if ([self _allowURLRequest:request webView:webView]) {
    if ([[actionInformation[WebActionModifierFlagsKey] unsignedIntegerValue] != 0x100000) {
      [listener use];
    } else {
      // Unexplored
    }
  } else {
    // Unexplored
  }
}

As long as _allowsURLRequest:webView returns YES and the WebActionModifierFlags doesn’t equal 0x100000, then this video should load!

It appears you need to force _allowsURLRequest:webView to always return YES. The $rax register is responsible for this.

Note: Advanced users of LLDB would suggest using thread return 1 in LLDB; however, using this trick with breakpoint commands will cause Xcode to crash. As a result, you’ll instead break on the return of this function call and modify the $al register to return 1 instead of 0

You can search for the code yourself, but since you’re a champ for working through all that assembly inspection, I’ll just give it to you: it’s found in the 274th offset in the disassembly dump. Search for it using ⌘ + F. Dump the assembly again and take note of the address:

(lldb) b 0x1173a1494
Breakpoint 11: where = IDEDocViewer`-[IDEDocWebViewContentViewController webView:decidePolicyForNavigationAction:request:frame:decisionListener:] + 274, address = 0x00000001173a1494
(lldb) br command add
Enter your debugger command(s).  Type 'DONE' to end.
> reg write $al 1 
> c 
> DONE
(lldb) c
error: Process is running.  Use 'process interrupt' to pause execution.

Now open the Documentation window and force a new loadRequest: call by searching for a new item in the title search bar:

LLDB_Doc_Command

Wahoooo! You’ve found the secret!

So what did you learn, other than assembly looks nothing like Objective-C? :] By wading through the assembly, you’ve figured out a couple of ways to augment this particular code:

  1. You could augment _allURLRequest:webView: to execute and then return YES.
  2. You could augment webView:decidePolicyForNavigationAction:request:frame:decisionListener: to just call decision [listener use]; and return.

The best way to guide your decision is to ask: How do you think the Xcode engineers will augment these APIs in future? _allURLRequest:webView: is private and could change. On the other hand, webView:decidePolicyForNavigationAction:request:frame:decisionListener: comes from the WebPolicyDecisionListener, which is a public API so it’s unlikely to change.

The choice should be obvious: you’ll augment webView:decidePolicyForNavigationAction:request:frame:decisionListener: to always execute [listener use] then return when Rayrolling is enabled.

Implementing the Helpful Payroll

Create a new NSObject Category and name it Rayrolling IDEDocWebViewContentViewController. By now, this process shouldn’t be surprising.

Open NSObject+Rayrolling_IDEDocWebViewContentViewController.m and replace the file’s contents with the following:

#import "NSObject+Rayrolling_IDEDocWebViewContentViewController.h"
#import "NSObject+MethodSwizzler.h"
#import "Rayrolling.h"
#import <WebKit/WebKit.h>
 
@implementation NSObject (Rayrolling_IDEDocWebViewContentViewController)
 
+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(setup) name:NSApplicationDidFinishLaunchingNotification object:nil];
    });
}
 
+ (void)setup {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [NSClassFromString(@"IDEDocWebViewContentViewController") swizzleWithOriginalSelector:@selector(webView:decidePolicyForNavigationAction:request:frame:decisionListener:) swizzledSelector:@selector(Rayrolling_webView:decidePolicyForNavigationAction:request:frame:decisionListener:) isClassMethod:NO];
}
 
- (void)Rayrolling_webView:(WebView *)webView
decidePolicyForNavigationAction:(NSDictionary *)actionInformation
                   request:(NSURLRequest *)request
                     frame:(WebFrame *)frame
          decisionListener:(id<WebPolicyDecisionListener>)listener
{
    if ([Rayrolling isEnabled]) {
        [listener use];
    } else {
        [self Rayrolling_webView:webView decidePolicyForNavigationAction:actionInformation request:request frame:frame decisionListener:listener];
    }
}
 
@end

Note that this version of load doesn’t swizzle as usual, but instead listens for NSApplicationDidFinishLaunchingNotification. Xcode 6.3 loads plugins during applicationWillFinishLaunching:, which means that IDEDocWebViewContentViewController is not loaded by the time this code is executed.

IDEDocWebViewContentViewController is unique in that you are modifying a component from a plugin as illustrated by the location of where the binary resides on your computer (/Applications/Xcode.app/Contents/PlugIns/IDEDocViewer.ideplugin/Contents/MacOS/IDEDocViewer:). This is different compared to other private classes you augmented as they are loaded in as frameworks.

Typically plugins are used to modify or complement existing code so it makes sense for them to be loaded at a later time. As a result, you are listening for when the application did become active and then modifying the class after it has loaded.

Now run this program to create a fresh plugin, then quit and relaunch Xcode. Navigate to the documentation and look up some class documentation; you’ll be greeted by a chorus of beautiful voices singing about WWDC.

Achievement unlocked: Rayrolling like a boss! :]

Where to Go From Here?

You can download the final project from this tutorial series here.

You’ve completed your Rayrolling plugin! On the journey, you’ve learned some pretty cool things about LLDB tricks, scripts, Dtrace, Cycript, and assembly.

But the journey isn’t over. The Xcode Plugin community is a very welcoming one; feel free to create a new plugin and add it to Alcatraz. Someone else out there will definitely appreciate your work, even if it’s the smallest of modifications.

The workflow and tricks you’ve learned in this series will be completely different compared to the workflow of someone else who is attempting to solve the same problem. So go forth, explore and have fun!

Do you have any cool tips or tricks for exploring Xcode, or do you have any questions or comments on this tutorial series? Feel free to join the discussion below!

How To Create an Xcode Plugin: Part 3/3 is a post from: Ray Wenderlich

The post How To Create an Xcode Plugin: Part 3/3 appeared first on Ray Wenderlich.

RWDevCon Inspiration Talk – Possible by Tammy Coron

$
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 – Possible by Tammy Coron – I hope you enjoy!


Transcript

When I was younger, my mother used to say to me that nothing is impossible. She would say that the impossible just takes a little longer.

At the time, I was positive her words were meant to encourage me and to make me feel better about myself. After all, watching your child deal with failure after failure, something I was quite good at, is difficult to say the least.

mother

Having two children of my own now, I can honestly say that watching your child struggle, or any child for that matter, is one of the most painful things a parent can witness. Of course, I didn’t understand that then, but now I understand it only all too well.

As parents, we want our children to succeed. We want them to have the confidence in themselves to keep trying and to keep reaching out to make their dreams a reality.

Like my mother did for me, I now do for my two boys. Of course when I do they look at me kind of funny and they wonder the same thing that I did when my mom told me about the impossible, “Is she nuts? Doesn’t she get it? There are lots of things that are impossible.”

Alice: "This is impossible." Mad Hatter: "Only if you believe it is."

Alice: “This is impossible.”
Mad Hatter: “Only if you believe it is.”

What’s Possible?

Let’s step back for a minute and clear something up. What does the word impossible mean? In the dictionary it reads, “Not able to occur, exist or be done.”

It’s pretty hard to misinterpret that, right? If this is what impossible means, then why would my mother lead me to believe otherwise? Was she setting me up for failure? Doesn’t she realize that things are impossible? I’m pretty sure she was setting me up for failure.

Actually she wasn’t. It wasn’t until later that I realized what she meant. For years she drilled that same message into my head.

drilling

Time and time again, especially when I was at my wits end with one thing or another, she would say, “The impossible just takes a little longer. The impossible just takes a little longer.”

Honestly at the time, it was more frustrating than encouraging, but because I love my mom I would patiently listen. I would thank her and then I would go back and try and figure out how to do exactly what it was I was trying to do.

Oddly enough, in a roundabout sort of way (that’s a shameless plug for my podcast Roundabout by the way) her method of encouragement worked. I didn’t give up. I never gave up.

To this day, I still don’t give up. It’s like what Rocky says, “It ain’t about how hard you hit; it’s about how hard you can get hit and keep moving.”

Rocky

When you stop to think about it, her message and now my message to you is not about the impossible taking longer. It really isn’t. In fact, it has nothing to do with the impossible.

What it boils down to is what is possible. What am I truly capable of accomplishing?

How Does Success Begin?

When you give up, things that are possible never happen. They get replaced with failures. They become impossible.

Think about this: What would have happened if Orville and Wilbur Wright believed everyone else around them? After all, everyone knows it’s impossible for man to fly.

plane
Here’s the problem. We are inundated with success stories. Now don’t get me wrong, this is a good thing. Unfortunately, we don’t always hear all of the story, especially the beginning.

It’s difficult to imagine that even the most successful people started somewhere. Take for example this guy, Steve Jobs. He wasn’t born into the Apple world. He made it through trial and error. He had many failures along the way.

In fact, he was even kicked out of his own company, but instead of giving up he went back and figured things out. He learned how to do things right, how to make the impossible possible.

Attribution: wikipedia.org

Attribution: wikipedia.org

Of course we all know how the rest of the story goes. If he had given up, none of us would be sitting here today.

Almost all success stories started with a failure at some point. It’s this failure part of the story that’s missing within the folklore of success. When we hear these stories, we have a very distorted view of the formula for success.

Did you ever wonder how many failures times rejections divided by blood, sweat and tears equals success?

equationForSuccess

Yeah, me too, but it’s math so we’re going to skip it. :]

Sadly there are too many people who give up. When it gets too hard, we’re tempted to quit.

That’s because most of us have no point of reference for the failure part of the story. We see folks around us rise to the top and wonder why it’s not happening for us. Remember, we usually come in at the end of the story.

successAtEnd

Do you honestly think J.K. Rowling came out of the womb holding the Harry Potter manuscript? Thankfully for her mom, she didn’t.

Was Harry Potter an instant success? No. Not even close. In fact the manuscript was submitted to twelve different publishing houses and each one of them rejected it. It wasn’t until a year later that Bloomsbury Publishing decided to publish it and then later Scholastic Corporation.

Writing a Children’s Book

I actually have a similar story to this, granted I am certainly no J.K. Rowling. In 2006, I wanted to write a children’s book.

I had no prior experience with it; I just knew this was something I wanted to do. Sounds impossible, right?

When I talked with my mother about it, she did what I expected she would do. She told me to go for it because, well, like she says, nothing is impossible. The impossible just takes a little longer. It’s the little longer part that most of us trip over.

The first order of business was to learn everything I could about the publishing industry. I bought books on printing, books on layout and design, books on marketing, books on illustration, books on books about books about publishing. If it existed, I either bought it or borrowed it.

books

Eventually I had everything I needed. I had the book written and illustrated, and it was ready for print. Now I just needed a printer, and believe it or not that was the hard part.

My first few attempts at securing a printer went horribly wrong. After dealing with a dozen or more companies, I was ready to give up. Some printers were well beyond my budget, others create such horrible samples that even if they printed it for me for free I would have passed.

After a few weeks of banging my head against the proverbial wall, and in some cases the real wall, I was at my wits end. I kept hearing that message in my head, “The impossible just takes a little longer. The impossible just takes a little longer. ”

A little longer? If I wait any longer I’m going to be a hundred years old.

oldLady

At that point, I had two choices:

  1. Give up.
  2. Keep going!

I opted to keep going, partly because this was something I wanted and partly because my mom scares the heck out of me. I didn’t want to disappoint her by giving up too quickly, and I am happy to report that I didn’t give up.

After many frustrating situations, I finally found the perfect printer and I successfully launched my first children’s book (another shameless plug – Happy Birthday Puppy):

puppy

The feeling of accomplishment that comes along with doing something that seems impossible is incredible.

Some of the most challenging things in life can also provide the best reward, but that’s how life is. It continuously throws us challenges with seemingly impossible odds. The fortunate side effect is that we grow and learn along the way.

Fighting Fires

You may not know this about me, but I used to be a firefighter. Yeah, I know, it seems impossible, right? It’s true.

TammyTruck

When I told people what I planned to do to join the fire department, some responded with negativity and skepticism. They said I couldn’t do it. They said I was too small, too weak, and a girl. Like I didn’t know I was a girl!

I ignored them, and despite an endless stream of cautionary commentary from what seemed like a countless amount of individuals, I decided to join the fire department anyway.

I walked into the firehouse and requested an application. I remember the guy who handed it to me. He was a bit of a jerk.

jerk

When he gave it to me he was sort of laughing and said something under his breath along the lines of, “Good luck with getting any help with that. No one wants a girl around here.” Later I would discover he was wrong.

After completing my physical, I submitted my application to the lieutenant. He understood that I didn’t have any experience. He also understood, after I confessed, that I was afraid of fire.

Afraid of fire?! Can you imagine that, a firefighter afraid of fire?

He wasn’t worried. He just smiled, he said, “It’s okay, we’ll help you.” Then he gave me this gigantic fire suit, it’s called turnout gear.

turnoutGear

He showed me how to put it on. He said step into your boots and then pull it up over yourself. His name was Mike. He was an awesome guy, and he helped me out a lot.

Oh and that other man, the one who was laughing at me; guess what? He was nowhere to be found.

For the first few weeks on calls. I was nothing more than a “go for” girl. Go for this, go for that.

They needed to make sure I was serious about this before investing any resources or money into me. A lot of times people join the fire department and then they quit after a few weeks.

I was not one of those people. Once they realized I wasn’t going anywhere, they sent me to the fire academy where I spent a grueling and exhausting twelve weeks.

"For the next twelve weeks, you're mine!"

“For the next twelve weeks, you’re mine!”

We trained hard. We took part in drills with real fire, like the same fire I told Mike I was afraid of, that fire.

We were taught about a tiny little device that would alert our crew if we had a problem and hopefully help them locate us. This tiny little device is what could save your life, and we trained for that.

tinyDevice

If you hear one go off, find it immediately and then get out of the building. As you might imagine, this is pretty darn stressful and it feels damn near impossible.

Somewhere around the fifth week I had an unexpected medical problem, one that required surgery. The trouble here is once you start the twelve weeks you have to finish all twelve weeks without missing a day. If you miss one day, you’re out.

You have to go back to the next session and start over from the beginning, and I didn’t want to do that. My doctor on the other hand, that’s exactly what he wanted me to do. He said, “You need to take it easy until you’re healed. You can’t go back. You need to relax.”

Obviously he didn’t know with whom he was dealing. There was no way I was going to let that get in my way. I had the surgery on a Friday, I returned to the academy on Monday making sure not to miss any time.

I pushed through the pain. I stayed motivated. At times, it felt impossible, but I kept going and I didn’t give up. I just kept pushing myself and pushing myself and pushing myself right into graduation.

graduation

Was it worth it? Absolutely. Was it hard? You bet.

Remember, things that are worth having aren’t always easy to get. If all things were easily achieved, then what’s the reward. What happens to our sense of accomplishment if everything is just handed to us?

Don’t get me wrong, it’s nice to have the occasional dog bone thrown your way, but here’s the thing, if you don’t work for something, then what’s the point?

Did you notice I didn’t say, “If you don’t work hard for something”? Working hard isn’t always necessary. Sometimes work is just work. It’s time, it’s energy and thought, but not necessarily hard.

Ten Thousand Hours

How many of you have heard of the ten thousand hour rule?

outliers

The ten thousand hour rule was popularized by Malcolm Gladwell in 2008 in his book Outliers, and it goes something like this. In order to become world-class in any field, ten thousand hours of dedicated time and deliberate practice is needed.

To illustrate his point, Malcolm cited a number of different examples from Bill Gates to The Beetles. He also wrote that “ten thousand hours is the magic number of greatness.” The magic number of greatness. What exactly did he mean by that?

I believe he meant exactly what my mom has been telling me all these years, that the impossible just takes a little longer. Apparently my mom, the jokester, left out the ten thousand hours part.

All kidding aside, when Malcolm talks about this rule he doesn’t mean that working ten thousand hours at something will guarantee you a table at the greats.

kingQueen

You won’t suddenly be crowned the master in your chosen field. Not at all.

He means that natural ability requires a huge investment of time in order to be manifested. Now he says this rule does not apply to sports; I disagree with him, but then again, I disagree with a lot of people about a lot of things. Just ask my mom.

I think that if you want something bad enough and you’re dedicated to doing the work that it takes to get it, then there is no reason you can’t manifest it. I know there is a lot of people who will disagree with me on that and fight me tooth and nail, but call me an optimist, I believe, I truly believe that anything is possible.

iOS Development: Definitely Possible

Let me give you an example in my own life. When I first started in IOS development, not many people were in the game yet. In fact, at the time I don’t even think that we called it IOS development. I believe we refer to it as iPhone development.

We didn’t have a lot of APIs and it didn’t take too much to get familiar with all of them, but it still took a little time to learn about them.

Nowadays of course things are way different:

  • Apple is constantly adding new settings.
  • There are hundreds of APIs.
  • Even a new language, let’s not forget that!

Do you think this information will magically appear within your brain? No. It’s going to take dedicated time and deliberate practice if you wish to learn about them, and that’s why we’re here. Like everyone in this room, at one time or another I had zero experience with IOS development.

Yes, that's me!

Yes, that’s me!

Crazy as it sounds, I wasn’t born knowing how to do this. I had no clue how to use UITableView. I couldn’t tell a delegate from a protocol, and I had absolutely no idea why I was synthesizing everything.

Like you, I had to learn. In fact, I’m still learning. Thanks to this excellent IOS community that we’re all apart of, we don’t have to be isolated while we’re doing it. We can help one another and remind each other about the possibilities.

It should be noted that we can also smack each other around when one of us talks about things being impossible, and I would encourage you to hit them harder when they complain about how long it’s taking to finish an app. You’ve all been warned.

That formula for success, what is it?

equationForSuccess

Well there isn’t one. Actually I should say there isn’t just one. There are many and they’re all unique.

It’s up to you to create your own formula. I’m going to give you a hint at what you need to do that. You need:

  • The passion to get it done.
  • The dedication or the time required to get it done.
  • And this is probably the most important, the understanding that nothing is impossible.

Make Your Impossible Possible

Look, I won’t lie. Despite being at this since nearly the start of IOS development, there are times when things seem impossible, especially now that we have this new language, a language that none of us has ever seen before.

It’s swift, our new mountain and we can climb it together.

mountain

While we’re climbing it, it’s important not to give up. Keep at it. Know that we’re all here to cheer you on and help you along the way.

Take your time. Enjoy the process.

Whatever you do, don’t beat yourself up. Save your energy for the guy complaining about things being impossible.

Because remember, absolutely nothing is impossible. The impossible just takes a little longer.

Note from Ray: Did you enjoy this inspiration talk? If so, sign up to our RWDevCon newsletter to be notified when RWDevCon 2016 tickets go on sale!

RWDevCon Inspiration Talk – Possible by Tammy Coron is a post from: Ray Wenderlich

The post RWDevCon Inspiration Talk – Possible by Tammy Coron appeared first on Ray Wenderlich.

Video Tutorial: Unity 2D Basics Part 3: Animation

Video Tutorial: Unity 2D Basics Part 4: Physics

WWDC 2015 Initial Impressions

$
0
0
Myself, Greg, and Marin in San Fran!

Myself, Greg, and Marin in San Fran!

I wasn’t lucky enough to get a WWDC ticket this year, but I’m still in San Francisco so I can hang out with fellow iOS developers and attend AltConf.

I’ve been having a great time so far, following and discussing all the exciting news with everyone here!

Although I haven’t had time to go through all the docs and samples yet, I thought it might be useful to post some of my initial impressions of the goodies in store for us this year.

Feel free to post any of your own thoughts, or anything I may have missed!

Swift Updates

The most exciting change for me was something that affects all Swift developers – the release of Swift 2.0, and that Apple will be making Swift open source later this year!

Greg will be posting a detailed roundup of what’s new in Swift 2.0 in a few days, but here’s three changes that especially stood out for me:

1) Error Handling

There’s an entirely new way to handle methods that return errors. The days of NSError are gone; there’s now a new system that looks somewhat similar to exception handling. One of the advantages of this system is that it makes it harder to accidentally ignore errors in your code.

Here’s a quick example that shows how this works:

let beers = 2
let sessions = 2
let hoursOfSleep = 4
 
enum WWDCAttendeeError: ErrorType {
  case TooExcited
  case TooTired
  case TooDrunk
}
 
func attendSession() throws {
  guard sessions < 3 else {
    throw WWDCAttendeeError.TooExcited
  }
  guard hoursOfSleep > 2 else {
    throw WWDCAttendeeError.TooTired
  }
  guard beers < 3 else {
    throw WWDCAttendeeError.TooDrunk
  }
  print("Great session!")
}
 
do {
  try attendSession()
} catch WWDCAttendeeError.TooExcited {
  print("Too excited!")
} catch WWDCAttendeeError.TooTired {
  print("Too tired!")
} catch WWDCAttendeeError.TooDrunk {
  print("Too drunk!")
}

I consider myself as exhibiting all three of these errors right now ;]

We’ll go into more details about this in future articles, but I definitely consider this one of the biggest changes to Swift, and something we’ll all need to get used to.

2) Protocol Extensions

With protocol extensions, you can actually add new method and property implementations to any class that implements a protocol. For example, this would add a new method knockKnock() to any class that implements Equatable, such as Int:

extension Equatable {
  func knockKnock() -> String {
    return "Who's there?"
  }
}
 
let a = 1
print(a.knockKnock())

With protocol extensions you can also add default implementations of methods to protocols too. I think this will turn out to be handy!

3) Labels

Just when you thought the days of GOTO were gone… labels return! ;]

Labels provide a way for you to break execution of an inner loop out to a higher level condition or loop, for instance:

outer: for i in 1...10 {
  for j in 1...20 {
    print("\(i), \(j)")
    if j == 5 {
      break outer
    }
  }
}

This will only print out (1, 1) to (1, 5), and then terminate. There have been a few cases where I could see this making code a bit cleaner.

And More…

There are a bunch of other changes too – stay tuned for Greg’s article for more details!

WatchKit Updates

Apple Watch developers around the world rejoice – we can now write native apps for watchOS 2!

When I first heard this, I was worried that it would make everything we’ve learned with WatchKit obsolete. However, according to what I can tell from the watchOS 2 Transition Guide, this is actually not the case.

Instead, it seems like you still make WatchKit apps the same way – you still create WKInterfaceControllers, you still use the same kind of controls and layout system – but now the code now runs on the watch, instead of on your phone.

This has a number of repercussions:

  • Better performance: Since code is running natively on the watch your apps should perform better. I haven’t tested this yet though – if anyone has let me know your findings!
  • More device access: You now have programmatic access to the digital crown, microphone on the device, health sensor data, accelerometer, and more – these will enable new kinds of apps.
  • New connectivity: Now that your WatchKit app is running on the watch itself, you can no longer use shared container for files – if you want to share files, you either need to use the new Watch Connectivity framework, or re-architect your code to have both the iPhone app and watch pull data over the network from a shared server.

Mic Pringle will be writing an article with more details on these changes. And before anyone asks – yes, we are planning a second edition of WatchKit by Tutorials! :]

iOS 9 Updates

There were a number of important changes in iOS 9 this year – not as many as previous years, but still a bunch of things you’ll want to be aware of. Here are my top three:

1) Multitasking Enhancements on iPad

One of the first things Apple demonstrated in the Keynote was that you can now run two apps at once on iPad, side-by-side in a split view.

If your app is using Auto Layout and Adaptive Layout correctly, for the most part this should just work. It basically means that sometimes your view controllers may have compact width size class on iPad, such as when it’s displayed on the right hand side of the split view. Also, if the split view is extended to 50% then both sides are compact width.

There are a few edge cases to keep in mind though, covered in the Slide Over and Split View Quick Start guide.

2) Search APIs

Another pretty cool new feature is that you can now make activities and documents within your app searchable by Spotlight using some new APIs.

You can also make special links on your site that when tapped by a user (and they have your app installed) will launch your app at a specific view in your UI flow, similar to Facebook’s App Links.

I expect we’ll see a lot of developers wanting to take advantage of this.

3) Other Cool Changes

I ran a quick poll on Twitter to see what else folks were the most excited about, and here’s some of the top winners:

  • Testing Improvements: Rather than write your UI testing in Javascript, Xcode now has a feature that allows you to record your interactions with your app and automatically generate the test code for you! It also has a nice code coverage feature that will highlight the parts of your code that are covered by unit tests.
  • CloudKit JS Library: One common complaint about CloudKit was that if you used it, you couldn’t make a web app that accessed the same data. That is no longer the case with the new CloudKit JS library!
  • App Thinning: Apps have become bloated over the years with @1x, @2x, and now even @3x images, multiple binaries, and so on. App Thinning makes it so only the files that are needed to run on the device are included – and most of this happens automatically. There is also a new system that allows you to store some of your apps resources on the App Store and download them on demand to further reduce binary size – see the On Demand Resources Guide.
  • Contacts/ContactsUI: The ancient AddressBook API has finally been rewritten in an Object-Oriented fashion. Hip hip hooray!

iOS Games Changes

Surprisingly, one of the biggest sets of changes this year were related to iOS and OS X games!

The most exciting change for me was a brand new framework called GameplayKit. This contains a number of really cool and helpful things for game development:

  • Entity/Component Support: The “easiest” thing to do when you get started with SpriteKit is to use inheritance for your game objects, but this can lead to problems as your game gets more complicated. It’s better to move to an entity/component system, but getting this working can be time consuming and tricky. With the new Entity/Component System support in GameplayKit, this will be much easier for developers to migrate to in the future.
  • State Machines: Almost every game needs a state machine, and GameplayKit provides a robust implementation to build upon. I look forward to replacing my bare bones state machines with these!
  • AI Support: GameplayKit also provides algorithms to more easily develop AI in your games, such as a Minmax algorithm, pathfinding, rule systems, and more. I can’t wait to dig into some of this stuff!

I never would have imagined we’d get a framework like this, and I think this puts a whole new level of games within the reach of the beginner game developer.

In addition to this, there also appears to be some nice improvements to the Sprite Kit editor that reminds me of Adobe Flash – I look forward to checking that out more!

Where To Go From Here?

That’s my 2c of the highlights of this year’s goodies as it relates to iOS and watchOS developers. We’ll be posting a bunch more articles, tutorials, books, and video tutorials about this in the coming weeks :]

I’m curious to hear what you thought about everything – what are you most excited about?

And please don’t say Apple Music! ;]

WWDC 2015 Initial Impressions is a post from: Ray Wenderlich

The post WWDC 2015 Initial Impressions appeared first on Ray Wenderlich.

WWDC 2015 with Nate Cook – Podcast S04 E04

$
0
0
Mic, Jake, and Nate Cook from NSHipster discuss WWDC 2015!

Mic, Jake, and Nate Cook from NSHipster discuss WWDC 2015!

Nate Cook from NSHipster joins Mic and Jake to talk about all the latest news from WWDC 2015!

[Subscribe in iTunes] [RSS Feed]

Our Sponsor

  • Instabug is the easiest way for users and testers to report bugs and send feedback directly from within your app. Sign up today at instabug.com for a free account!

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

Links

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 next season. Feel free to drop a comment here, or email us anytime at podcast@raywenderlich.com.

WWDC 2015 with Nate Cook – Podcast S04 E04 is a post from: Ray Wenderlich

The post WWDC 2015 with Nate Cook – Podcast S04 E04 appeared first on Ray Wenderlich.

Video Tutorial: Unity 2D Basics Part 5: Screen Sizes


WatchKit for watchOS 2: Initial Impressions

$
0
0
WatchKit for watchOS 2

WatchKit for WatchOS 2

Like Ray, I was unable to attend WWDC this year, but I’ve still been having an amazing time watching the videos, reading the docs, and discussing all the news with Jake, Nate, and the folks on the Tutorial Team.

As you may know from the podcast, I am a huge Apple Watch fan, so I was particularly excited about all of the goodies in watchOS 2.

I’ve been spending the last few days looking over the Apple Watch docs, so thought you might enjoy a quick overview of what’s new.

Please post any of your own thoughts in the comments below, and feel free to highlight anything I’ve missed!

Architecture

Wait, did he just say native?

Wait, did he just say native?

Perhaps one of the biggest changes to WatchKit with this release is that you can now build native watch apps.

Unlike the previous version of watch apps where the interface ran on your watch but the code was executed on your iPhone, with watchOS 2 both reside and execute on the watch itself.

This has some very positive side-effects, such as making your apps launch quicker, and be far more responsive since there’s no longer a round-trip to your phone over Bluetooth LE with every interaction.

This move to native apps does also have some implications that you need to be aware of:

  • openParentApplication(_:reply:) has been removed from the SDK. But don’t panic, as it’s been replaced by the much richer Watch Connectivity framework. More on this shortly.
  • Sharing files using shared app groups is no longer an option. Again, you can use the new Watch Connectivity framework to facilitate this, but Apple has also provided network access for native apps in watchOS 2. So, if you were using app groups to share data pulled down from the internet, you can now do this directly on the watch using good ol’ NSURLSession.
  • iCloud isn’t available on the Watch.

Watch Connectivity

With the Watch Connectivity framework you can pass files and data back and forth between the watch and its paired iPhone. If both apps are running in the foreground, then the communication is live, otherwise it happens in the background so that the data or file is available when the receiving app is launched.

The main player in this new framework is WCSession, which handles all the communication between the two devices. You don’t create instances of this class yourself, but instead use the defaultSession singleton object.

To get up and running you simply assign an object that conforms to the WCSessionDelegate protocol to the session’s delegate property, and call activateSession(). If you plan on making frequent use of Watch Connectivity then I highly recommend you do this setup as early in your apps lifecycle as you can.

Once you have your session configured and activated, you can use any of the following methods to transfer your data and files:

  • updateApplicationContext(_:error) is used to transfer a dictionary of data to the counterpart app. This won’t always happen immediately, but will happen before the counterpart app wakes up so that the data is available at launch. The counterpart receives the dictionary via it’s session delegate’s session(_:didReceiveUpdate:) method.
  • sendMessageData(_:replyHandler:errorHandler:) is used to transfer data to the counterpart app immediately. Calls to this method are queued up and delivered in the same order in which you send them. If you’re sending data from the watch to the iOS app, then the app is woken up in the background if it’s not already running. If you’re sending data in the other direction and the watch app isn’t running then the error handler is called. The counterpart receives the data via it’s session delegate’s session(_:didReceiveMessageData:replyHandler:) method.
  • transferFile(_:metadata:) is used to transfer files, such as images, in the background. This behaves in the same way as the previous method, waking the iOS app up if it’s not running, or calling the error handler if the watch app isn’t running. The corresponding delegate method you need to implement to receive the file is session(_:didReceiveFile:).

There are numerous other methods provided by the framework, so I highly recommend you check out the reference.

See, didn’t I tell you not to worry about losing openParentApplication(_:reply:). :]

Other WatchKit Highlights

I’ve gone into detail on two of the biggest changes in this release of WatchKit, but there were several other highlights that I think are worthy of a mention.

Animation

While WatchKit still includes its original approach to animation, cycling through a pre-generated series of images, WKInterfaceController now provides support for basic animations that are more akin to iOS, via the new animateWithDuration(_:animations:). This takes a duration and a block, and animates any changes made to interface objects within that block over the provided duration. For example:

animateWithDuration(1) { () -> Void in 
  self.label.setHorizontalAlignment(.Left)
  self.label.setAlpha(0)
}

You can animate changes to the following properties of WKInterfaceObject:

  • alpha
  • width and height
  • vertical and horizontal alignment
  • background color
  • layout group insets
Note: Animations aren’t supported in glances or custom notifications, and any changes you make in the animation block will be applied immediately without animations.

I realise this may seem a little rudimentary since there’s no way to provide a timing curve, or know when the animation is complete, but I’m sure you’ll agree that it’s definitely a step in the right direction, and I’m hoping Apple will build on this in future seeds.

More Access To The Hardware

WatchKit for watchOS 2 provides access to much of the devices hardware and sensors, including the Digital Crown, Taptic Engine, heart rate sensor, accelerometer, and microphone.

This opens up a whole new world of functionality for your apps, such as being able to accurately monitor the heart rate of a user of your fitness app as they work out, or use the Taptic Engine to provide a more immersive gameplay experience. I honestly can’t wait to see what you all come up with! :]

New Interface Objects

With this release of WatchKit Apple has shipped a brand new interface object: WKInterfacePicker. This presents a scrollable list of items, which you interact with via the Digital Crown.

The items in the picker can be text, images, or a mix of the two. When the user selects an item, WatchKit calls the picker’s action method passing the index of that item.

A picker can be displayed using one of three different styles:

  • List: this displays the items as a vertically stacked list;
  • Stacked: this displays the items like a stack of cards that animate in from the bottom of the picker as the Digital Crown is turned;
  • Image Sequence: this displays a single image from a sequence of images.

It’s also worth pointing out that a single interface controller can include multiple pickers.

And speaking of interface controllers, WKInterfaceController now exposes a method that allows you to present alerts and action sheets.

Calling presentAlertControllerWithTitle(_:message:preferredStyle:actions:) presents an alert or action sheet over the current interface controller, depending on the style you pass as the preferredStyle parameter. The actions parameter is probably the most interesting of the four, as this takes an array of instances of WKAlertAction, which themselves provide a block to execute when the corresponding button is tapped by the user. It’s also worth noting that you’re responsible for dismissing the alert or action sheet within these blocks.

One More Thing…

On the previous episode of the podcast, when Jake and I were discussing what we’d like to see announced at WWDC, one thing we both agreed would be a great addition to the Apple Watch was custom complications, which you can think of as little widgets you can install on clock faces. Well I guess Tim and co. must be regular listeners, as we asked and they delivered!

That’s right, you can now build custom complications for your watch app and have your data appear right on the user’s chosen watch face.

Custom complications are built around the concept of families, with each family providing one or more template classes that you subclass to implement your own complication. There are currently five families of complication:

  • Modular: there are small and large variants of this family, and they can be seen on the MODULAR watch face.
  • Circular: there is on a small variant of this family, and it can be seen on the SIMPLE watch face.
  • Utilitarian: like Modular, there are small and large variants of this family, and they can be seen on the UTILITY watch face.

See this guide for a more visual representation if you don’t have an Apple Watch or are unfamiliar with the available watch faces, and check out the Providing Custom Complications section of the watchOS 2 Transition Guide for more details on building custom complications.

Custom complications are probably the highlight of this WatchKit release for me, and I can’t wait to dive into the APIs and start building my own complications!

Where To Go From Here?

Overall, I’m pretty excited by all the new features in watchOS 2, and I look forward to working on the second edition of WatchKit by Tutorials with the Tutorial Team in the coming months.

Do keep in mind that this is only the first seed of WatchKit for watchOS 2, and as Apple releases future seeds it’s likely even more new features and APIs will be added, along with the things I’ve covered here changing or even being replaced with something even better – it’s happened before, it’ll happen again! :]

I’m curious to hear what your initial impressions on this WatchKit release are – please add your thoughts in the comments below.

WatchKit for watchOS 2: Initial Impressions is a post from: Ray Wenderlich

The post WatchKit for watchOS 2: Initial Impressions appeared first on Ray Wenderlich.

Video Tutorial: What’s New in Swift 2 Part 1: Error Handling

raywenderlich.com Video Tutorials Out of Beta!

$
0
0

We’ve been making video tutorials on this site for a little over a year now – and today I am happy to announce that we are now officially out of beta!

The quickest way to explain it is via this video:


I thought you guys might have some questions about the details, so here’s some Q&A for you.

Q&A

I already have a subscription. Will my price go up?

If you already have a subscription, your price will not increase; your beta discount will continue as long as you keep your subscription active.

What would cause me to lose the beta discount rate?

If you ever cancel your subscription, you will lose the beta discount rate. When you re-subscribe, your subscription will be at the normal rate.

When will the beta discount end?

The beta discount will end sometime this Friday, July 3 – so if you’ve been thinking of subscribing and want to lock in the beta rate, now’s your last chance!

What’s coming up in the next few months?

Here’s the plan:

  • New APIs: We’re working on a bunch of videos on new APIs announced in WWDC, such as Swift 2, iOS 9, and watchOS 2. For example, check out our new What’s New in Swift 2 video tutorial series!
  • iOS 9 Updates: After iOS 9 gets out of beta, we’ll be updating a lot of our current series to iOS 9 .
  • New video tutorials: As usual, we will also be checking the subscriber-only forums for suggestions from readers for new series to do next, so keep your suggestions coming!

Where To Go From Here?

I’d like to end by thanking everyone who has subscribed to our video tutorials one last time; you’re really helping us grow and improve as a site and we’re incredibly grateful for your support.

We hope you enjoy our video tutorials, and thanks again! :]

raywenderlich.com Video Tutorials Out of Beta! is a post from: Ray Wenderlich

The post raywenderlich.com Video Tutorials Out of Beta! appeared first on Ray Wenderlich.

Physics Joints in Unity 2D

$
0
0

Screen Shot 2015-05-26 at 2.10.57 PMThe cross-platform game engine Unity has powerful support for creating 2D and 3D games. It’s a great choice for aspiring game developers, since it works for most mobile, desktop and console platforms, and even better, it’s free to use for lower-revenue developers and studios.

One of the key components of Unity are physics joints, which let you create various connections between objects in Unity. Using joints, you can describe a connection between two objects, which means you can simulate the physics of almost any multi-part object you can think of, including doors, sliding platforms, chains or even wrecking balls! :]

This tutorial will focus on using joints in Unity 2D, although Unity supports joints in its 3D engine as well.

Note: If you don’t have much experience with Unity, you’d do well to work through the Getting Started with Unity and What’s new in Unity 5 articles on this site.

Getting Started

First, ensure you have the latest version of Unity, which you can download here. This tutorial was using version 5.0.2f1. If you are using another version of the 5.x branch, chances are, this will work fine.

Next, download the 2D_Joints_Starter. Unzip it and open the 2d_Joints_Starter project in Unity. The Demo scene should open automatically, but if not, you can open it from the project’s Scene folder.

The scene should look as follows:

joints_at_launch

This scene contains various objects with physics components, much like you might find in any game. However, none of these shapes are connected by joints. Throughout this tutorial, you’ll get to try out each of Unity’s 2D joint types to see how they work.

Play the scene; you’ll see some of the objects immediately fall to earth due to the effects of gravity:

joints_initial_run

Note: While the labels in this scene are in fixed positions, the movement of the objects is based on the size of your Game view. For best results, put your Game view in Free Aspect mode and adjust its size in the Unity GUI until the objects and labels appear similar to the above image.

It’s time to get these objects working together with joints!

Distance Joint 2D

The first joint you’ll add – the Distance Joint 2D – has a very basic goal: to keep two objects separated by a constant distance. You’ll test this out on the red square and blue hexagon in the upper left of the scene.

Select Hexagon_Djoint in the Hierarchy and add a Distance Joint 2D Component to it, as shown below:

04

As you can see in the following image, this new component has several parameters that you can adjust to produce the best result for your game:

05

Fear not — you’ll soon learn what all these these parameters do and how you can adjust them.

You’ll notice that once you have the component attached to the Hexagon that a green line extends from the Hexagon to the center of the screen. This is the origin point (0,0).

Screen Shot 2015-05-20 at 5.34.41 PM

Run the scene, keeping your eye on the Hexagon.

distance-gif

Right away, you’ll notice that the Hexagon flies across the screen until it stops near the origin point, then begins to rock back and forth on the joint. The rocking behavior is the actual joint behavior, but what’s the deal with the initial jolt of energy? This is actual expected behavior and you’ll learn about it soon.

Turn your attention back the component in the Inspector. The Distance Joint 2D’s first parameter is Collide Connected. This determines whether or not the two objects connected by the joint can collide with each other. In this case, you don’t want this to happen, so leave it unchecked.

The second parameter is Connected Rigid Body. While one end of the distance joint always remains connected to the object that contains the component, you can use this field to pass a reference to an object for the other end of the joint’s connection. If you leave this field empty, Unity will simply connect the other end of the joint to a fixed point in the scene.

You want to connect Hexagon_Djoint to Square_Djoint in this case, so drag Square_Djoint to the Connected Rigid Body field:

06

With the connection set up and Hexagon_Djoint still selected, you should now see the two objects connected by the joint in the Scene view as follows:

distance_joint_connected

The next parameter is Anchor, which indicates where the end point of the joint attaches to the GameObject as specified in the object’s local coordinate space. In the Scene view, with Hexagon_Djoint selected, you can see the anchor point as an unfilled blue circle centered over Hexagon_Djoint in the image above In this case, leaving the value at (0, 0) is fine.

Note: The unfilled blue circle representing the joint’s first anchor point may appear filled if you currently have the Transform tool selected in the Scene view. Likewise, you will see a white square if you have the Scale tool selected. In either case, moving the anchor away from (0, 0) will show that it is indeed an unfilled circle.

The Connected Anchor parameter specifies the anchor point of the other end of the joint. If the Connected Rigid Body field is empty, this value is in the scene’s coordinate system. However, when Connected Rigid Body is set, as it is now, the Connected Anchor coordinates refer to the connected rigid body’s local coordinate space. This anchor point appears in the above image as a solid blue circle centered over Square_joint. Once again, you can leave this value at (0, 0).

The fifth parameter of the Distance Joint 2D is the one that bears its namesake: Distance. The name says it all: this parameter indicates the distance to maintain between both objects.

Back in the Scene view, you can see a small green line intersecting the line connecting the two objects; you can see this in the image below.

distance_joint_connected

This line indicates the distance enforced by the joint. When you run the scene, the joint will move Hexagon_Djoint so that the Anchor you defined is at the point where the small line. As you increase or decrease, the line will correspondingly move up or down.

distance-property

To give you a bit more room to see the joint in action, set Distance to 2, as shown below:

08

The last parameter is Max Distance Only. If enabled, the joint will only enforce a maximum distance, meaning that the objects can get closer to each other, but never further away than the value specified in the Distance field. In this example, you want the distance to be fixed, so leave this parameter disabled.

Run the scene and you should see that the hexagon attached to the square no longer falls from the scene:

09

While that’s sort of helpful, joints really only shine when one or more of their connections are moving. The project contains a helpful script that lets you drag objects with your mouse. Select Square_Djoint in the Hierarchy and drag Movement from the Scripts folder to the Inspector, as demonstrated below:

10

Run the scene; drag Square_Djoint around with your mouse to see your joint in action:

11

While you can see your joint working, you can’t actually see your joint. Sure, the Scene view shows a green line connecting the two objects, but the Game view doesn’t.

To get a better understanding of what’s happening, the project includes a script that renders a line between two objects at runtime. To visualize the joint, select Square_Djoint in the Hierarchy and drag Line from the Scripts folder to the Inspector:

12

Next, tell the Line script where to draw by dragging Square_Djoint and Hexagon_Djoint to Game Object 1 and Game Object 2 in the Inspector, as shown below:

13

Play your scene; you’ll see a line connecting the two objects:

14

Note: The Line script draws a line between the positions of two GameObjects. It doesn’t actually use the joint’s data, and as such, will not faithfully reproduce some joint settings. For example, if your distance joint does not specify a Connected Rigid Body, or if the anchors are not at (0, 0), then the line displayed will not properly visualize the joint’s location.

You’ll notice that no matter where you move the Square_Djoint, the Hexagon_Djoint will always be a certain distance from it. Run your scene again, only this time check the Max Distance Only property of the Distance Joint 2D. This will only enforce the max distance of the joint, allowing the two objects to pass through each other. Now when you you move the Square_Djoint, you’ll see a different behavior.

max-distance

Now that you’ve covered the Distance joint, the next logical step is to investigate Springs.

Spring Joint 2D

The Spring Joint 2D works in a similar way to distance joints. However, while distance joints enforce a fixed distance, spring joints apply tension to a connection, causing objects to bounce as if connected by, well, a spring! :]

To see how they work, select Hexagon_Sjoint in the Hierarchy and add a Spring Joint 2D component to it like so:

15

As you can see, this new component has several parameters that you can adjust:

16

Spring Joint 2D has several fields in common with Distance Joint 2D: Enable Collision, Connected Rigid Body, Anchor and Connected Anchor all work exactly the same way for springs as they do for distance joints, so there’s no need to re-explain these.

Before covering the other fields, first connect Square_Sjoint to the spring by dragging it from the Hierarchy tab and dropping it over the Connected Rigid Body field:

sjoint

Just like Distance Joint 2D, Spring Joint 2D contains a Distance field that specifies the distance the spring should try to maintain between the two objects. However, while distance joints strictly enforce this distance, spring joints bounce back and forth around this distance, gradually coming to a stop at the specified value.

Set Distance to 2:

18

The Damping Ratio specifies the degree of suppression for the spring oscillation. In other words, it determines how quickly the objects connected by the spring will come to a rest. Its value ranges from 0 to 1, with 0 being the slowest and 1 being the fastest. You’ll want to play around with this value to get the best result in your games, but for now, leave it at 0 to get a very bouncy spring.

Frequency indicates the frequency at which the spring oscillates in cycles per second; in other words, the number of times the spring bounces each second. This value should be higher than zero, where zero means the spring starts out at rest. Lower values produce stretchier springs and higher values produce tighter ones.

Frequency and Damping Ratio work together to produce the spring’s final behavior. You’ll usually need to tweak each of these quite a bit to get the perfect result for your game.

Once again, you’ll add mouse interaction and a line renderer to help see how this joint works. Add the Movement and Line scripts to Square_Sjoint. Make sure to set Game Object 1 and Game Object 2 references on the Line (Script) component to Square_Sjoint and Hexagon_Sjoint:

19

Play your scene; drag Square_Sjoint around the scene and give your spring a good workout:

20

Play around with the different values in both the Frequency and the Dampening values to get an idea of how the spring moves.

While the distance and spring joints are similar to each other, the next one — Hinge Joint — is quite different.

Hinge Joint 2D

The Hinge Joint 2D is slightly different from the last two. This specific joint lets a GameObject with a Rigidbody rotate around a fixed point. The joint calculates the correct rotation for the object when a force affects the object’s Rigidbody, meaning no additional script or code is needed. As you’ll soon see, hinge joints provide several configuration options so you can create various moving bodies such as doors, weight-triggered trap doors, water wheels and more.

In this example, you’ll make Square_Hjoint (which is actually a rectangle) rotate when you put some weight on it.

Select the Square_Hjoint and add a Hinge Joint 2D component to it:

21

This component contains quite a few new fields, along with some old favorites:

22

Once again, there’s Collide Connected, Connected Rigidbody, Anchor and Connected Anchor. These fields all work the same way as before.

This time, leave the Connected Ridigbody field empty to connect the joint to a point in space. Recall that when Connected Rigidbody is empty, the Connected Anchor coordinates are in the scene’s coordinate system. That means the default coordinates (0, 0) aren’t correct in this case.

Instead, place the anchor on the center of the rectangle by changing the Connected Anchor‘s X and Y values to -3.5 and -3.2, respectively:

23

The next parameters are specific to Hinge Joint 2D. Checking Use Motor makes the physics engine apply a constant force to rotate the joint in an effort to reach the specified speed. I say “in an effort”, because the Rigidbody might have other forces acting on it that speed up or slow down the rotation.

You specify the motor’s target speed in the Motor Speed field as a value in degrees per second. The motor will try to maintain this speed by applying torque to the joint. You can specify the maximum torque the motor may apply using the Maximum Motor Force field. The higher this value, the more the motor will resist external forces that might try to stop the rotation.

The Use Limits enables or disables rotation limits, which restricts the joint’s rotation between the specified Lower Angle and Upper Angle values.

In this example, you don’t want the platform to spin around in circles, so enable Use Limits and set Lower Angle to -245 and Upper Angle to 0.5:

limit_hinge_angles

The Scene view shows the extents of the joint’s rotation:

hinge_joint_in_scene

The balls in the scene already respond to gravity and re-spawn at their original position when they fall from the scene, as demonstrated below:

25

Play your scene; drag one of the balls and drop it over the Square_Hjoint to see how the platform rotates:

26

Try the same thing with the different balls in the scene; notice how bigger balls increase the speed of rotation. That’s because the three balls in the scene were each created with a different mass — this demonstrates how the hinge rotates differently based on the force applied.

To see the motor in action, select the Square_Hjoint in the Hierarchy and in the Inspector, check the Use Motor checkbox. Next set the Motor Speed to 500 and uncheck Use Limits.

Run your game. Now you’ll get movement without needing to anything. Congratulations! You defied physics and created a perpetual motion machine!

hinge

Uncheck Use Motor and check Use Limits for the rest of this tutorial.

Now that your platform spins, you’ll add a slider joint to create some more physics-based interaction.

Slider Joint 2D

Slider joints restrict an object’s movement along a line in space. In this section, you will use the hinge joint you just created to start another object moving along a slider joint.

Select Hexagon_Sljoint in the Hierarchy and add a Slider Joint 2D component to it:

27

The fields available in the Slider Joint 2D component are similar to those you saw in the hinge joint, but with a few semantic changes. Because slider joints deal in linear, rather than angular, motion, Motor Speed is measured in units per second. Likewise, instead of angle limits, you can specify translation limits. Translation limits work the same way as angle limits, except they specify the distance the Rigidbody can be from the Connected Anchor point:

28

Leave Connected Rigidbody empty and set Connected Anchor‘s X value to 4.3 and its Y value to -4.7:

29

You can see the path described by the joint in the Scene view as shown below:

slider_joint_scene

The one completely new field you see is Angle; this sets the angle between the Anchor point and the Connected Anchor point. The GameObject with the slider joint will reposition itself at runtime to match this angle.

Set the Angle to -45. You’ll notice a small green line in the scene view will replicate that angle.

Screen Shot 2015-05-25 at 2.29.55 PM

Now, run your game. You’ll see that instead the joint is now positioned at a forty five degree angle.

Screen Shot 2015-05-25 at 2.31.57 PM

Since you want Hexagon_Sljoint to move to the right of where it starts in the scene, set the Angle back to 0.

In order to see the joint’s path at runtime, add the Line script to Hexagon_Sljoint, set its Game Object 1 field to Hexagon_Sljoint and its Game Object 2 field to Square:

30

Play your scene; drop some balls on the hinged platform from the previous section. The platform should spin and bump into Hexagon_Sljoint, which will then slide along the path defined by the joint. The hexagon will move at different speeds depending on how fast you make the platform spin:

31

While you can make rotating objects with hinge joints, you’ll want to use a wheel joint to simulate things such as the wheels on a car.

Wheel Joint 2D

Wheel Joint 2d is the final joint you’ll explore in this tutorial; it simulates a rolling wheel you can connect to another object, complete with a suspension spring to provide some “give” between the wheel and its other anchor point.

This joint exists primarily to simulate the wheels of vehicles. However, in this example you’ll keep it simple and just use it to create a rotating platform.

Add a Wheel Joint 2D component to the Square_WJoint:

32

Most of this component’s fields should look familiar. One difference is that you shouldn’t leave Connected Rigid Body unset; Unity won’t complain if you do, but the wheel joint won’t do anything in that case.

33

To anchor your platform in the scene, set Connected Rigid Body to Hexagon_WJoint:

34

The Suspension section is unique to wheel joints. It includes three fields: Damping Ratio, Frequency and Angle. The first two work just like they did in Spring Joint 2D, while Angle works as it did in Slider Joint 2D.

These three properties work together to describe a spring that keeps the wheel separate from its anchor vehicle and oriented in a specific direction.

Play the scene; drop one of the balls over Square_Wjoint, near the center of the platform. You should see the platform move down and bounce back up along with its spinning motion — the end result of the Suspension settings:

35

To see the Wheel Joint really in action, create a new Scene by selecting File \ New Scene.

From the Sprites folder, drag a square into the Scene view. Set the Transform position to: (-3.6, -7.72, 0). Set the Scale to (14.43, 6.50, 1).

Click the Add Component button and give it a Box Collider 2D component. Set the Size to X: 2.29, Y: 2.31

Screen Shot 2015-05-25 at 5.37.16 PM

Give it the name: Ground. It should look like the following:

Screen Shot 2015-05-25 at 4.14.17 PM

Create a new Empty GameObject. Call it Car. Set the position to: (6.4,1.13,0).

Screen Shot 2015-05-25 at 4.32.42 PM

From the Sprite folder, drag the Car sprite from the Sprites folder and into the Car GameObject. Give it the name: Body. Set the transform to be: (0, 0, 0)

Screen Shot 2015-05-25 at 4.28.40 PM

From the Sprite folder, drag the Wheel sprite from the Sprites folder and into the Car GameObject.Do the same for both the wheels, positioning them in the empty wheel wells. Call them: FrontWheel and BackWheel.

Screen Shot 2015-05-25 at 4.33.45 PM

Next, add Rigidbody 2D components on the Body, Front Wheel, and BackWheel. With your Rigidbodies in place, add a Circle Collider 2D to the FrontWheel and BackWheel. Add a Polygon Collider 2D to the Body.

When you select the Car GameObject, your colliders will look like the following:

Screen Shot 2015-05-25 at 4.39.24 PM

Next, select the Body in the Inspector, and click the Edit Collider button.

Screen Shot 2015-05-25 at 4.46.16 PM

Drag the polygon collider around the wheel wells so that the wheels won’t collider with them.

car-collider

Select the Body in the Inspector. Add a Wheel Joint 2D to it. In the Connected Rigid Body property, add the FrontWheel. In the Anchor property, set X:-0.98 Y:-0.78. Check the Use Motor checkbox and set the Motor Speed to 500.

Screen Shot 2015-05-25 at 5.27.59 PM

With the Body still selected. Add another Wheel Joint 2D to it. In the Connected Rigid Body property, add the BackWheel. In the Anchor property, set X:1.15 Y:-0.84. Check the Use Motor checkbox and set the Motor Speed to 500.

Screen Shot 2015-05-25 at 5.30.09 PM

With your engine ready to go, play your scene. You’ll see your car take a ride!

car-driving

Where to Go From Here?

You can download a copy of the completed project here.

We hope you enjoyed this tutorial about 2D joints! If you’d like to learn more about Unity’s 2D joints, we suggest you check out the following resources:

If you have any comments or questions on this tutorial, feel free to join the discussion in the forums below!

Physics Joints in Unity 2D is a post from: Ray Wenderlich

The post Physics Joints in Unity 2D appeared first on Ray Wenderlich.

Using Core Data in iOS with RubyMotion

$
0
0
Learn how to use Core Data with Ruby Motion!

Learn how to use Core Data with Ruby Motion!

If you’re looking to add persistence to your iOS or OS X app, Core Data is great choice — and implementing it in RubyMotion is surprisingly simple.

In this tutorial, you’ll use Core Data to add persistence to the Pomotion timer I showed you in how to make in my RubyMotion Tutorial for Beginners series.

If you have a good understanding of RubyMotion, feel free to download the complete code from the GitHub repository and start from there.

Otherwise, I’d suggest working through those two tutorials before starting this one.

You’ll need the following to get the most out of this RubyMotion tutorial:

  • Experience developing for iOS in Objective-C
  • Basic understanding of Ruby
  • Basic knowledge of CSS
  • Basic experience using Terminal

Prior experience with Core Data or ActiveRecord would also be a huge plus, but neither is essential.

Getting Started

First, make sure you have the final project from the previous tutorial series or grab it from GitHub.

Open Terminal, switch to the root directory of the application, and make sure the app builds successfully by running the following command:

rake device_name="iPhone 4s"
Note: RubyMotion 3 includes a new option device_name for the rake command that lets you specify which device simulator the app will run on. I prefer to use the iPhone 4s simulator because it’s smaller and I can see everything on the screen.

If your screen looks like this, great — If it doesn’t, make sure you’ve followed the installation instructions and completed all of the steps in the previous Pomotion tutorials.

Your starting point app should look like this.

Your starting point app should look like this.

Once you have Pomotion running, you’re ready to begin.

Dependency Updates: If it has been a while since you last used RubyMotion, you may need to update some of your gems. Specifically, you may need to update the bundler gem. You can do so by running the following command in Terminal: gem update bundler.

Additionally, you may see an error something like Bundler::GemNotFound: Couldn’t find sass-3.4.2 in any of the sources. If you encounter this issue, you can explicitly install Sass v3.4.2 with the following: gem install sass -v 3.4.2

Adding the Tasks Button

You’re going to add a tasks list to the Pomotion app. Think of this as a user’s daily TODO list where users add and remove tasks, as well as select a task to work on.

Users access the tasks list by tapping a button in the navigation bar. So, you’ll start by adding that button.

Using your favorite text editor, open app/controllers/main_view_controller.rb and add the following lines under the timer_button method definition.

def tasks_button
  @tasks_button ||= UIBarButtonItem.alloc.initWithImage(tasks_image, 
    style: UIBarButtonItemStylePlain, target: self, action: nil)
end
 
def tasks_image
  @tasks_image ||= UIImage.imageNamed('todo.png')
end

Here you’ve defined two properties on the MainViewController class: a UIBarButtonItem named tasks_button, and a UIImage named tasks_image.

Before you run these changes, you’ll need to add the image file referenced in the tasks_image method above to your app’s resources.

Download this file and save it to your application’s resources directory as todo.png.

Still in app/controllers/main_view_controller.rb, add this method below the tasks_image method:

def viewDidLoad
  super
  self.title = "Pomotion"
  self.navigationItem.rightBarButtonItem = tasks_button
end

This adds the tasks_button to MainViewController’s navigation bar. Build and run your app the same way you did the last time to see the changes:

rake device_name="iPhone 4s"

Main Screen with blue tasks button

Looking good so far! However, the color scheme for this app is red, white and green. That blue tint on the tasks_button is a bit clashy, don’t you think? Good thing you can change that!

You might remember from the previous Pomotion tutorial that Pomotion uses PixateFreestyle to add CSS styles to your app’s views. This means that you’ll find style definition in a CSS file named resources/default.css.

Open resources/default.css and add the following line to the navigation-bar selector:

-ios-tint-color: white;

This changes the tint color of the navigation bar to white. To learn more, check out the Pixate reference.

Save the file then build and run the app again with rake device_name="iPhone 4s". The tasks button should now have a white tint instead of blue.

Main screen with white tasks button

Wasn’t that easy? :]

Try tapping the tasks_button. Nada. Why isn’t it responding? Oh, because you haven’t defined an action to be called when it’s tapped.

Adding the Tasks List Screen

In Terminal, create a new file in the app/controllers directory named tasks_view_controller.rb:

touch app/controllers/tasks_view_controller.rb

Open the file in your text editor.

Declare TasksViewController as a subclass of UITableViewController like the following:

class TasksViewController < UITableViewController
 
end

Save the file, and open main_view_controller.rb and add the following just after timer_button_tapped:.

def tasks_button_tapped(sender)
  tasks_controller = TasksViewController.alloc.initWithNibName(nil, bundle: nil)
  navigationController.pushViewController(tasks_controller, animated: true)  
end

This displays the tasks list when the user taps the tasks_button.

Now wire up this method to the action: parameter in tasks_button with this:

def tasks_button
  @tasks_button ||= UIBarButtonItem.alloc.initWithImage(tasks_image, 
    style: UIBarButtonItemStylePlain, target: self, action: 'tasks_button_tapped:')
end

Build and run again to launch the app in the simulator

rake device_name="iPhone 4s"

This time, when you tap the tasks_button you should see an empty table view that looks like this:

Pomotion tasks list with no tasks

Now you’re making progress! The UI is mostly configured and now it’s time to drill down into the inner workings and make it actually do something more than look pretty.

Populating the Tasks List with Real Data

Installing CDQ

Here comes the fun part…

To use Core Data in your app, you’ll be using the Core Data Query gem (or cdq, for short). cdq makes it really easy to get started with Core Data in RubyMotion with just a few lines of code.

I showed you how to install gems to your project in RubyMotion Tutorial for Beginners: Part 1, but you can read the Pixate Freestyle section if you need a refresher.

Open your Gemfile and add the following line:

gem 'cdq'

Then make sure it’s installed by running this command in Terminal:

$ bundle install

Now that cdq is installed, run the following command in Terminal to complete the installation:

cdq init

The cdq init command does a couple of things, and it’s quite important that you understand them both.

First, it creates an initial schema file named 0001_initial.rb in a new directory named schemas. These schema files are where you define and manage your application’s database structure.

Each time you need to make a change to one of the tables, you create a new schema file that reflects how the new database should look. As long as the versions are not too different from each other, Core Data automatically migrates your database and updates the structure without you having to do anything else.

The second thing cdq init does is that it adds another line to the bottom of your Rakefile, like this:

task :"build:simulator" => :"schema:build"

In short, this makes sure that each time you build the app to run in the simulator, the rake schema:build command also runs to keep the schema up to date.

This is extremely helpful, but there’s a potential pitfall: If you’re deploying to an iOS device instead of the simulator, this command doesn’t run automatically — you’ll have to run it manually from Terminal by running:

rake "schema:build"

Good to know!

Now, open app/app_delegate.rb and include CDQ by adding the following line just below AppDelegate:

  include CDQ

And finally, add the following line to the start of application:didFinishLaunchingWithOptions

  cdq.setup

And that’s it for the installation. Next up is setting up your first data model.

Creating a Data Model

Open schemas/0001_initial.rb in your text editor, and you’ll see some example code that’s been commented out. Delete that and add the following in its place:

schema "0001 initial" do
 
  entity "Task" do
    string :name, optional: false
  end
 
end

This code defines a simple entity named Task. A Task has a name (defined as a string), which is required for a Task record to be valid (it’s not optional).

There’s one more step to finish adding your Task model, and that’s to create a class for it in your application. In your text editor, create a file named task.rb in the app/models directory and define Task like so:

class Task < CDQManagedObject
 
end

The CDQManagedObject superclass is provided by CDQ, and it provides some extra methods for querying and saving data to your database.

Build and run the app in the simulator so you can try out CDQ in the console:

rake device_name="iPhone 4s"

Still in Terminal, run the following command once the app launches:

(main)> Task.count

It should return the number of Tasks currently in the database (which is currently 0):

(main)> Task.count
=> 0

Create a new Task by typing the following:

Task.create(name: "My first task")

The output should look similar to this:

(main)> Task.create(name: "My first task")
=> <Task: 0x11750b10> (entity: Task; id: 0x1174d940 <x-coredata:///Task/t2FA02CA9-05AF-4BD5-BAEB-B46F21637D0C2> ; data: {
   name = "My first task";
})

Now when you call Task.count, you should see it return 1.

(main)> Task.count
=> 1

Quit the simulator (by pressing ctrl + c), and then build and run the app once again.

rake device_name="iPhone 4s"

Fetch the number of Tasks once again by running Task.count, it should return 1.

(main)> Task.count
=> 0

…it should, but it didn’t! What happened?!

Be the Boss of cdq

CDQ won’t commit any data to the database unless you tell it to, and you do that by calling cdq.save in your code. This is an important gotcha to keep in mind.

Your application will not persist data unless you call this method. This is a deliberate feature of cdq; by only making commits to the database when you’ve defined all of the changes to be committed, you’ll improve the memory usage and performance of your app.

It’s easy to forget about this extra step – especially if you’re coming to iOS from Ruby on Rails.

So start again from the top by create a new Task:

(main)> Task.create(name: "This is my first task")
=> <Task: 0xb49aec0> (entity: Task; id: 0xb49aef0 <x-coredata:///Task/t41D7C6A6-806D-4490-90A6-19F1E61ED6C12> ; data: {
    name = "This is my first task";
})

But this time, run the following command afterwards:

(main)> Task.save
=> true

Now quit your application and then re-launch. Call Task.count, and you’ll see it returns 1.

(main)> Task.count
=> 1

CDQ Helper Methods

CDQ offers a few other helpful methods to save and retrieve persisted data. Run the following commands in the console to see their results.

Fetch the first row:

(main)> Task.first
=> <Task: 0xb49aec0> (entity: Task; id: 0xb47a830 <x-coredata://B0AEB5CD-2B77-43BA-B78B-93BA98325BA0/Task/p1> ; data: {
    name = "This is my first task";
})

Check if there are any records:

(main)> Task.any?
=> true

Find rows that match given constraints:

(main)> Task.where(name: "This is my first task").any?
=> true    
 
(main)> Task.where(name: "This is my second task").any?
=> false

Delete a row:

(main)> Task.first.destroy
=> #<NSManagedObjectContext:0xad53ed0>

And most importantly, commit changes to the database:

(main)> Task.save
=> true

You’ll use these methods again soon — when you complete the tasks list feature.

Loading Tasks from the Database

The Tasks screen should show each of today’s Tasks that are in the database. First, though, you should prepare for the initial condition when there are no tasks.

Add the following implementation In tasks_view_controller.rb:

class TasksViewController < UITableViewController  
  # 1
  # = UITableViewDelegate =
 
  def tableView(table_view, heightForRowAtIndexPath: index_path)
    todays_tasks.any? ? 75.0 : tableView.frame.size.height
  end
 
  # 2
  # = UITableViewDataSource =
 
  def tableView(table_view, cellForRowAtIndexPath: index_path)
    table_view.dequeueReusableCellWithIdentifier(EmptyCell.name)
  end
 
  # 3
  def tableView(table_view, numberOfRowsInSection: section)
    [1, todays_tasks.count].max
  end
 
  # 4
  private
 
  def todays_tasks
    Task.all
  end
 
end

Most of this code should seem pretty familiar to you by now, except for the last method, but I’ll walk you through each of them.

  1. First, you define tableView:heightForRowAtIndexPath from the UITableViewDelegate delegate. If there are any tasks in the database, then the height of each cell should be 75 points, otherwise, a cell’s height should be the entire height of the UITableView.
  2. Next, in tableView:cellForRowAtIndexPath: you return an instance of EmptyCell — you’ll define this class in a moment.
  3. The tableView:numberOfRowsInSection: method should return 1 if there are no tasks in the database, or the number of tasks if there are any. This ensures that if the list of tasks is empty, the app still displays one cell.
  4. Finally, todays_tasks is a helper method that loads all of the tasks from the database.

    Although you could easily just call Task.all throughout the various methods in TasksViewController, it’s good practice to define a method like this to access each of the objects or collections you load from the database.

    Having this single point of access is much DRY-er (Don’t Repeat Yourself), and it means you only have to change the code once if you need to add extra constraints later.

Now add this:

def viewDidLoad
  super
  tableView.registerClass(EmptyCell, forCellReuseIdentifier: EmptyCell.name)
end

You’ve just registered the EmptyCell view class with TasksViewController‘s tableView by defining viewDidLoad.

Before you build the app again, you’ll also need to create the actual class for the empty table view cell, so create a new file in the app/views directory named empty_cell.rb, like this:

touch app/views/empty_cell.rb

Now add this…

class EmptyCell < UITableViewCell
 
end

to define the EmptyCell class as a subclass of UITableViewCell.

Build and run the app in your simulator once again with this command:

rake device_name="iPhone 4s"

Now when you tap the tasks button, you’ll see a screen like this

Pomotion tasks controller with large empty cell

If you see multiple cells or an error message, make sure that you’ve deleted all of the Tasks from the database by calling Task.destroy_all followed by Task.save in the app console.

Wouldn’t this be more user friendly if it had a title? Of course it would. In tasks_view_controller.rb, update the viewDidLoad method like so:

def viewDidLoad
  super
  self.title = "Tasks"
  tableView.registerClass(EmptyCell, forCellReuseIdentifier: EmptyCell.name)
end

This time, when you build and run the app you should see the title Tasks in the navigation bar on the tasks screen.

Now you need to give the users a means of adding new tasks to the list. First, create an “Add” button with the following method:

def add_button
  @add_button ||= UIBarButtonItem.alloc.
    initWithBarButtonSystemItem(UIBarButtonSystemItemAdd, target: self, action: nil)
end

Then, add the following line at the bottom of viewDidLoad:

navigationItem.rightBarButtonItem = add_button

This, of course, adds the button to the right of your navigation bar. Build and run the app again, and you’ll see a new + button that makes it possible to add new tasks.

Pomotion - Tasks list with "+" button

Most users will understand that the plus button is how you add tasks, but just to be on the safe side leave a hint that helps the user see how to add tasks.

To do this, simply add a message to the empty cell that tells the user how to add a task. Add the following method to empty_cell.rb:

def initWithStyle(style, reuseIdentifier: reuseIdentifier)
  super.tap do
    self.styleClass = 'empty_cell'
    textLabel.text = "Click '+' to add your first task"
  end
end

Of course, the label needs a little styling before it’s complete, otherwise, it’ll be ugly. So, add the following CSS rules to resources/default.css

.empty_cell label {
  top: 200px;  
  left: 0;  
  width: 320px;
  height: 30px;
  font-size: 18px;
  color: #AAAAAA;
  text-align: center;
}

Build and run the app again with rake device_name="iPhone 4s". The tasks screen should now look like this:

Tasks screen with empty cell plus prompt styled

Looking good!

Creating New Tasks

Okay, so far you’ve got the framework mostly there, but the only way to add tasks is a tad complex for the average user.

So, in tasks_view_controller.rb add a UIAlertView property under add_button to prompt the user to enter the new task’s name:

def task_alert_view
  @task_alert_view ||= UIAlertView.alloc.initWithTitle("Add A Task", 
    message: "Insert the name of the task below",
    delegate: self, cancelButtonTitle: "Add", otherButtonTitles: nil).tap do |alert|
      alert.alertViewStyle = UIAlertViewStylePlainTextInput
  end
end

By setting the alertViewStyle property to UIAlertViewStylePlainTextInput, you make it so the alert view contains a text field that the user can populate and submit.

All you need to do now is define an action to show this alert view, so add the following method:

def add_button_tapped(sender)
  task_alert_view.show
end

Then, update the action: parameter in add_button to call add_button_tapped::

def add_button
  @add_button ||= UIBarButtonItem.alloc.
    initWithBarButtonSystemItem(UIBarButtonSystemItemAdd, target: self, action: 'add_button_tapped:')
end

Before this will work as expected, you’ll have to implement the UIAlertViewDelegate method alertView:clickedButtonAtIndex in TasksViewController.

Add the following at the bottom of the implementation:

# = UIAlertViewDelegate =
 
def alertView(alert_view, clickedButtonAtIndex: index_path)
  text_field = alert_view.textFieldAtIndex(0)
  if !text_field.text.to_s.empty?
    create_new_task(name: text_field.text)
    tableView.reloadData      
    text_field.text = ''
  end
end
 
private
 
def create_new_task(attributes)
  Task.create(attributes)
  Task.save
end

This method first assigns the text field from the alert view to an instance variable and checks if it’s text property has a value.

If it does, the controller creates a new Task record by calling create_new_task, a private method that creates a new record and commits the changes to the database.

Then, you reload the tableView to show the newly added task in the list, and reset the text_field’s text property back to an empty string.

Build and run the app once again, and add a new task to the tasks list:

Tasks screen with new task alert

But what happens when you add a task? Where does it go?

The tasks in your database won’t display on screen yet, because the tableView cells haven’t been configured to display them. To do that, create a new file in app/views named task_cell.rb.

touch app/views/task_cell.rb

Just like EmptyCell, TaskCell should be a subclass of UITableViewCell. Open task_cell.rb and add the following:

class TaskCell < UITableViewCell
 
end

And also add the following lines to TaskCell

def initWithStyle(style, reuseIdentifier: reuseIdentifier)
  super.tap do
    self.styleClass = 'task_cell'
  end
end
 
def configure_for_task(task)
  textLabel.text = task.name
end
 
def prepareForReuse
  super
  textLabel.text = ''
end

Here you redefine initWithStyle:reuseIdentifier and set a styleClass for the cell, just like you did in EmptyCell. configure_for_task lets you set the value of the cell’s textLabel from TasksViewController.

prepareForReuse should be familiar to you. In this case, you’re setting the text property of the textLabel inherited from UITableViewCell back to an empty string, so the cell may be reused again by the table view. In this case, it’s not strictly necessary, although it’s always good practice.

Go back to tasks_view_controller.rb and tell your tableView about TaskCell the same way you did with the EmptyCell class, by updating viewDidLoad to the following:

def viewDidLoad
  super
  tableView.registerClass(EmptyCell, forCellReuseIdentifier: EmptyCell.name)
  tableView.registerClass(TaskCell,  forCellReuseIdentifier: TaskCell.name)
  navigationItem.rightBarButtonItem = add_button
end

Finally, update tableView:cellForRowAtIndexPath: to return a TaskCell if there are tasks present.

def tableView(table_view, cellForRowAtIndexPath: index_path)
  if todays_tasks.any?
    task = todays_tasks[index_path.row]
    table_view.dequeueReusableCellWithIdentifier(TaskCell.name).tap do |cell|
      cell.configure_for_task(task)
    end
  else
    table_view.dequeueReusableCellWithIdentifier(EmptyCell.name)
  end
end

Build and run the app again. Now the task list will update with new tasks as you add them.

 Tasks list populated with a couple of tasks

Things are really coming together.
Celebrate all the tasks!

Selecting the Current Task

So as of now, the app functions, but there’s always more you can do to kick it up a notch. In this case, you could display the name of the current task on the timer screen. That would certainly help the user stay focused on the current task.

To get this working, you’ll first need to add a column to the tasks table to identify which task is the current one. Update the table by defining the new schema in the schemas directory.

Create a new file named 0002_add_current_to_tasks.rb

touch schemas/0002_add_current_to_tasks.rb

Edit this file in your text editor so it looks like this:

schema "0002 add current to tasks" do
  entity "Task" do
    string :name, optional: false
    boolean :current, default: false, optional: false
  end
end

This file is very similar to the previous schema file you created.

In fact, there are only two differences: The name of the schema 0002 add current to tasks and the additional line where the current column is defined. In this case, it’s a boolean column with a default value of false, which must be set for the Task record to be valid.

That’s all you need to do!

The next time you run rake device_name="iPhone 4s" your app should automatically update the tasks table to match the new schema version.

Add a label to the main screen to display the name of the current task. In main_view.rb add this new property:

  def task_name_label
    @task_name_label ||= UILabel.alloc.initWithFrame(CGRectZero).tap do |label|
      label.styleClass = 'task_name_label'
      label.text = "n/a"
    end
  end

Again, nothing too crazy here. task_name_label returns a UILabel where text is pre-populated with n/a (not available, as there may not be a current task set when the screen is loaded). The label is given a style class task_name_label, so that you can easily define how it looks using CSS.

Update initWithFrame to add the task_name_label as a subview:

def initWithFrame(frame)
  super.tap do 
    self.styleId = 'main_view'
    addSubview(timer_label)
    addSubview(timer_button)
    addSubview(task_name_label)
  end
end

Then you need to open resources/default.css and add some new CSS:

.task_name_label {
  top: 400px;
  left: 60px;
  width: 200px;
  height: 30px;
  font-size: 16px;
  color: #333333;
  text-align: center;
}

Build and run the app once again:

rake device_name="iPhone 4s"

Now you should see a label with n/a showing underneath the main timer:

Main screen with current task name label

The text for this label needs to be populated with the name of the current task whenever this screen displays. That way, it’ll update when the current task changes.

In your text editor, open app/models/task.rb and add the following class methods:

# 1
def self.current=(task)  	
  self.current.current = false if self.current
  # 2
  task.current = true
  # 3
  self.save
  # 4
  @current = task
end
 
# 5  
def self.current
  @current ||= where(current: true).first
end
 
# 6
def self.reset_current
  @current = nil
end

Let’s review this section by section:

  1. Task::current= is a setter method that sets the current Task. First, it checks for any existing current tasks and sets their current property to false.
  2. This sets current on the given task to true.
  3. This saves the changes — remember, CDQ won’t commit any changes to the database unless you call the save method.
  4. Finally, Task::current= sets an instance variable to store the new current Task.
  5. Task::current returns the value of the @current instance variable if it’s set. If not, it queries the database to find the first Task where the current column is set to true, and then it returns that.
  6. Lastly, Task::reset_current sets the value of the @current back to nil, ensuring that the new current task reloads the next time Task::current is called.

Go back to the tasks_view_controller.rb and implement the UITableViewDelegate method tableView:didSelectRowAtIndexPath, just beneath tableView:heightForRowAtIndexPath:

def tableView(table_view, didSelectRowAtIndexPath: index_path)
  Task.current = Task.all[index_path.row]
  navigationController.popViewControllerAnimated(true)
end

This block makes it so that when a user taps on a task cell in the tasks screen, it sets the current task, updates that record in the database, and then the app navigates back to the main screen.

There’s one small problem here: Currently the user could select the EmptyCell. You’ll prevent it from being selected by implementing the following:

def tableView(table_view, shouldHighlightRowAtIndexPath: index_path)
  todays_tasks.any?
end

Give this a try; build and run the app in the simulator.

rake device_name="iPhone 4s"

You won’t see any change on the screen yet, and that’s because you still need to add that. But if you type the following in Terminal while the simulator is running, you should see that it’s working behind the scenes.

(main)> Task.current
=> <Task: 0xb6a9a60> (entity: Task; id: 0xb63bfa0 <x-coredata://B0AEB5CD-2B77-43BA-B78B-93BA98325BA0/Task/p5> ; data: {
    current = 1;
    name = "Write RubyMotion tutorial";
})

Updating the label to show the new task is really simple. In main_view_controller.rb define a wrapper method that returns the task_name_label for the MainView. Add this just below tasks_image:

def task_name_label
  view.task_name_label
end

Then, insert this private method at the bottom of the MainViewController implementation:

def set_task_name_label_from_current_task
  if Task.current
    task_name_label_text = Task.current.name
  else
    task_name_label_text = "n/a"
  end
  task_name_label.text = task_name_label_text
end

Finally, implement viewDidAppear: for MainViewController and call set_task_name_label_from_current_task inside there. Remember to call super inside this method first with this:

def viewDidAppear(animated)
  super
  set_task_name_label_from_current_task
end

Build and run the app once again to see your changes take effect. This time, when you select a new task, the task_name_label updates with the name of your chosen task.

Main screen with task name label populated

Editing the Tasks List

You’re almost done; there’s just one more thing to add, and this feature is complete!

The user should also be able to remove tasks from the list once they’re complete. After all, there’s nothing more satisfying than cleaning up your TODO list once your work is complete.

Add this by implementing the UITableViewDelegate methods: tableView:canEditRowAtIndexPath: and tableView:commitEditingStyle:forRowAtIndexPath: in tasks_view_controller.rb like so:

# 1
def tableView(table_view, canEditRowAtIndexPath: index_path)
  todays_tasks.any?
end  
 
# 2
def tableView(table_view, commitEditingStyle:editing_style, forRowAtIndexPath: index_path)
  case editing_style
  when UITableViewCellEditingStyleDelete
    delete_task_at_index(index_path.row)
    if todays_tasks.any?
      tableView.deleteRowsAtIndexPaths([index_path], 
          withRowAnimation: UITableViewRowAnimationFade)
    else
      tableView.reloadRowsAtIndexPaths([index_path], 
          withRowAnimation: UITableViewRowAnimationFade)      
    end
  end
end

What’s going on here?

  1. tableView:canEditRowAtIndexPath: simply returns true if there are Tasks available to tell the controller that the tasks may be edited.
  2. tableView:commitEditingStyle:forRowAtIndexPath is more involved, and I’ll talk you through it:
  • First, it checks the value of editing_style. Here you’re only dealing with the value UITableViewCellEditingStyleDelete. If that’s the case, the task is deleted by calling delete_task_at_index (it’s not defined yet).
  • If there are still other tasks in the database, then this row is deleted from the table view with a nice UITableViewRowAnimationFade animation, otherwise, the table reloads to show one EmptyCell with a UITableViewRowAnimationFade animation.

Now define delete_task_at_index at the bottom of TasksViewController, just before the closing end:

def delete_task_at_index(index)
  task = todays_tasks[index]
  task.destroy
  Task.save
  Task.reset_current
end

This private method fetches the task to be destroyed by its index in todays_tasks, marks it for deletion from the database, and then commits the changes to the database. The last line calls the reset_current method you defined in Task to clear the current task.

Build and run your app one more time and try adding and removing some tasks

rake device_name="iPhone 4s"

Tasks screen with deleted task

Where To Go From Here?

That’s it. You’ve successfully implemented Core Data with your RubyMotion app. Hopefully you found it refreshingly straightforward.

Of course, there’s a lot more you can achieve with Core Data and RubyMotion than what you’ve covered here. I recommend you check out the fully documented source code, as well as CDQ’s README and documentation.

I’d love to hear about how you’ve implemented Core Data with RubyMotion, anything you discover while you work through this tutorial and any questions that bubble up as you play around around. Leave your notes, comments and questions below!

Using Core Data in iOS with RubyMotion is a post from: Ray Wenderlich

The post Using Core Data in iOS with RubyMotion appeared first on Ray Wenderlich.

Viewing all 4370 articles
Browse latest View live


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