NSLog alternatives for better logging with shipping apps

24 June 2014

Shipping apps with NSLog statements is generally a bad idea. Not only can a continuous stream of logging cause your application to run much slower, but it can also eat away at the device storage rather quickly if your app is an NSLog abuser. Fortunately, there are a few viable alternatives to using the good 'ole NSLog function.

Using DLog()

Try as you might, you won't find DLog() anywhere in the Objective-C documentation. That's because this is a custom function that can be defined in your Prefix.pch file to do selective logging.

By adding the following method to your Prefix.pch file, you'll be selectively logging using NSLog only if your project is in a debug state. Once you've switch over to release, then your app will no longer log the output to the console.

#ifdef DEBUG
    #define DLog(...) NSLog(@"%s(%p) %@", __PRETTY_FUNCTION__, self, [NSString stringWithFormat:__VA_ARGS__])
#endif


To use this code, anywhere that you'd normally use an NSLog() statement, simply use DLog() instead. It'll take the exact same arguments, but the output is conditional on your app being a Debug build.

The great thing about using this over NSLog is that you can also provide additional information to the console for debugging purposes. For instance, here, we're using __PRETTY_FUNCTION__ to provide a method signature for the method block that initiated the call to the DLog function.

What about Swift?

With modern project architectures in Swift, Apple decided to no longer include Prefix.pch files. Because of this, the above method will not work with Swift architecture.

Fortunately, there is a great open source library that can handle this functionality for us in Swift. The project is called XCGLogger and it's provided by Dave Wood at Cerebral Gardens.

To use this project, you'll add the following to your Swift AppDelegate file:

import XCGLogger //Import the source

...

let log = XCGLogger.defaultInstance() //declare a global constant

application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) {

...

log.setup(logLevel: .Debug, showLogLevel: true, showFileNames: true, showLineNumbers: true, writeToFile: nil)

}

Once you've gotten the log.setup() configured inside of the applicationDidFinishLaunchingWithOptions callback, then you can begin to log anywhere in your application by using one of the following 5 methods in XCGLogger:

log.verbose("A verbose message, usually useful when working on a specific problem")
log.debug("A debug message")
log.info("An info message, probably useful to power users looking in console.app")
log.error("An error occurred, but it's recoverable, just info about what happened")
log.severe("A severe error occurred, we are likely about to crash now")



Cory Bohon is an indie iOS and Mac developer at Cocoa App and MartianCraft. Follow this article's author, Cory Bohon on Twitter.

Measuring Code Complexity

13 March 2014

In the world of programming, keeping an eye on code complexity is important because it not only means that the code will be more maintainable, but will also generally be less buggy. Verbose code code can be more complex than needed, and that code can often lead to code that contains more bugs than cleanly written code with minimum complexity. In this post, we'll talk about what it means to measure code complexity using a system known as cyclomatic complexity, and will see how to write code that has very little complexity but can still get the job done.

To be clear: We're not talking about writing code that works efficiently or in a timely manner. Measuring code complexity is not a replacement for using Big O notation to measure the efficiency of functions and methods, for instance; however, writing non-complex code will often lead to code that runs more efficiently and has fewer errors and other issues.

What is Cyclomatic Complexity?

Software is needlessly complex, because as humans, we tend to write code that is both overly complex and verbose. A human brain can typically hold 7 ± 2 things before we begin to forget information, which is why we often times write very verbose code.

The thing to remember is that the number of lines of code is not a metric for measuring complexity: Complexity is a measurement of decisions, rather than the length of the code.

Cyclomatic complexity helps to measure code complexity through the use of decisions to give developers a better understanding of how complex the code through a metric that is easy to measure and compare.

Why use cyclomatic complexity?

Cyclomatic complexity is a really powerful metric for your code. It makes your code better in three ways:

1. It predicts the likelihood of defects.

When your methods and functions are really small, you don't need as many unit tests, and the likihood of defects in smaller code is more rare.

2. It makes unit testing easier

The metric that measuring cyclomatic complexity gives you is the minimum number of test cases that you should have for your methods.

3. It gives you a number

This is probably the most important aspect of measuring code complexity: You have a numerical metric that tells you exactly how complex your code is, and you can use this number to ensure that your code is less complex.

Measuring Cyclomatic Complexity

We've already said that cyclomatic complexity is the measurement of decisions in your code. But, what is a decision?

A decision is any of the following items in your code:

Cyclomatic complexity is defined by the following function:

Cyclomatic Complexity = Number of Decisions + 1

When measuring complexity, the count is measured from the start of a method or function through until the end of a method or function. Each method will have it's own complexity count.

What is a good cyclomatic complexity count?

When measuring cyclomatic complexity, you should always aim to have code that is limited to a complexity of 10.

Code that is more complex than 10 usually has the issues that we're trying to avoid when using cyclomatic complexity, namely: defects.

How can I reduce complexity?

There are at least three ways that you can reduce the complexity of your code:

  1. Break complex functions into smaller pieces
  2. Improve the structural quality of your code
  3. Many IDEs, including Xcode, have built-in Refactor commands that let you Extract code into individual methods (see Xcode | Edit | Refactor | Extract).

If you find yourself writing code that has a complexity greater than 10, then you should be splitting your code into multiple, smaller methods to make the code more readable and less complex.

Cory Bohon is an indie iOS and Mac developer at Cocoa App and MartianCraft. Follow this article's author, Cory Bohon on Twitter.

Tips and Resources for beginning iOS Development

03 February 2014

iOS and Mac development have become very popular over the past few years as the hardware that runs the apps has gained much attraction. With the flood of iOS developers coming into the ecosystem, some may wonder, "Where do I begin?"

While there are a lot of resources now available to newer iOS developers, in this post, I wanted to sift through and deliver only the best tips and resources for new devs.

Tips

There is no secret sauce that makes a great iOS developer, but developing on a platform with such a great history and attention to detail does require some things. First is that you must pay just as much attention to your apps as Apple does in the OS. Don't ship apps with known bugs, compiler warnings, or ship an application that uses code copied from online. While your users will never see the underlying code of your application, they will feel the effects of the quality of code you write, so ensuring that your code is top-notch will help you in the long run figure out issues and get fixes out when things break.

While you are first learning the ropes of iOS development, don't put your "learning" apps on the App Store. The App Store is already littered with these apps, and putting yours up there only leads to more confusion for customers. The App Store is a professional marketplace, where professionals go to put their software goods for sale. If you don't have the time or the resources it takes to support an application with good customer service, updates, and a quality app, then you should wait until you have something better. Building apps can be a good learning exercise, however, and TestFlight and HockeyApp are two tools that can help you deliver your apps to testers and friends without the need to distribute your app through the App Store.

While you are planning and building out your application, think about the user experience and interface a lot. Tweak, try things out, and above all, design something that avoids complexity. If you look at all of the top selling apps, they are the ones that have removed complexity, and distilled down the application idea into its most simplistic form possible while still maintaining a good range of functionality. There's a fine line begin being simple and being useless, and it's up to you to find that line and stay on the useful side.

In order to do iOS and OS X development justice, you'll want to avoid the multi-platform compilers and dive straight into Objective-C. It's a language that's super-easy to pick up on if you come from a C/C++ background. Using multi-platform toolkits usually causes more headaches than it's worth, plus, these toolkits usually don't support the latest and great frameworks from Apple and often run slower than natively built applications.

Resources

For beginners, there are a lot of resources available to you. When I first started developing, there was only the Apple Developer documentation to head to for help, but now there's a wide myriad of sites, books, and forums where you can get help or learn new ideas. Here's a list of my favorite resources for beginners.

Documentation

The Apple Developer documentation site should always be your first stop when trying to figure out how to do something in iOS or OS X. This well curated site provides a vast amount of information to you in a developer-friendly format. Bookmark this site, it will become your friend along your path to becoming an iOS developer.

Books

There are a few books that I cannot recommend enough when it comes to learning Objective-C, iOS, and OS X development, as well as the various technologies encompassing the Apple developer ecosystem. Here are the ones that I couldn't live without if I had to start over fresh learning to develop for these platforms:

  1. Objective-C Programming: The Big Nerd Ranch Guide Currently in it's second edition, this book provides an unrivaled introduction to the Objective-C programming language (the language that powers iOS and OS X).

  2. iOS Programming: The Big Nerd Ranch Guide (4th Edition) The Big Nerd Ranch guides are an invaluable resources for new developers, and this book, currently in it's 4th iteration covers all of the topics in iOS that you need to learn in order to get started with the platform.

  3. iOS Components and Frameworks: Understanding the Advanced Features of the iOS SDK If you're looking to learn all of the ins and outs of the iOS frameworks and various components that make the platform the best to develop for, then you'll want to check out this book. It covers all of the various tech inside of iOS that can make your apps tick better. Plus, this book is updated for iOS 7 and Xcode 5.

  4. Core Data: Data Storage and Management for iOS, OS X, and iCloud If you spend any amount of time with iOS development, then chances are you'll run into Core Data. It's the best way to persist data in your application. Don't go off and learn another abstraction on top of Core Data, instead, stick with the Core Data native libraries and learn all about them with this book.

Blogs

  1. NSHipster One of my favorite blogs to read is NSHipster. It covers the hidden tidbits related iOS and Mac development that you can sometimes forget about. Mattt does and excellent job writing about these various ends and packages them very nicely in this well-received blog.

  2. ObjDev (just a little shameless plug)

  3. Ray Wenderlich This blog provides a lot (and I mean a lot) of tutorials on various aspects of iOS development. Written by various folks with varying backgrounds, it provides interesting insights into the latest developer technologies in iOS.

Forums

  1. Apple Developer Forums The Apple Developer forums is a place for registered developers only to talk about iOS and OS X development. When there is a beta version of iOS or OS X, it's the only sanctioned place to discuss embargoed information.

  2. StackOverflow StackOverflow is an invaluable resources for a modern-day developer who is just getting started. Search the site and if your question is already answered, then post a question and someone in the iOS or OS X development community can assist with your burning question.

These are just a few of the great resources available to developers. If you have another resource that I didn't mention here, let me know by tweeting @ObjDev.

Cory Bohon is an indie iOS and Mac developer at Cocoa App and Empirical Development. Follow this article's author, Cory Bohon on Twitter.

Xcode Bots

20 January 2014

With Xcode 5 and Mavericks Server, Apple introduce a fully integrated build server that works with Xcode 5 projects to automatically create iOS and Mac builds. This means that you can have a bot automatically create a build for you whenever you push to a special remote repository branch. This week, we'll take a look at how to create an Xcode Bot to do your bidding.

Adding Repos to the Server

Xcode can automatically determine your repository settings and add them as a bot, but I've had much better luck working directly with the Server app on Mavericks (especially if you connect to your remotes via SSH) and adding the remote repositories there (unless your repository is hosted by your OS X Server installation, then the process is a bit easier).

Image showing the New Repository creation process

To add your repo, open the Server app and navigate to Xcode > Repositories. Here, click the Add button at the bottom of the Repository listing table, and then enter your repository information in the view that appears. Xcode Bots can connect to Subversion or Git repos, including ones that might be hosted locally on your server.

Once you've added the remote repository, it will appear in the list of remotes, and we can begin creating the Bot.

Creating the Bot

Now that we've created the link to the remote repository, we can create the bot and the rules around it to start the build. To do this, log into [YourServerAddress]/xcode.

Here, you will see a list of your Xcode bots. Click the Add button in the upper, right-hand corner to begin the Bot creation process.

Image showing the first step of Bot Creation

On the first screen, you'll need to select the Repository from the drop-down menu that we just set up on the server. Next, enter the branch that should trigger the build (we usually use "master"), then enter the Xcode Project file location in the repo, and finally specify the build scheme and name of the bot.

Image showing the second step of Bot Creation

On the second screen, you'll be able to set some additional options. In the "Schedule" drop-down, select "Poll for new commits" will cause the server to automatically build on new commits. Under the Actions section, set the actions that should run when building; and, then specify whether or not you'd like to Clean intermediate files between builds.

Image showing the third step of Bot Creation

On the third screen, Select which platforms you'd like to test against (if you're running tests). If your app is built for iOS, you can select between connected devices or simulators.

Image showing the fourth step of Bot Creation

On the final screen, you can set email addresses that will get pinged whenever the integration completes or fails.

Starting an Integration

After completing the setup, the integration will automatically begin, but you can also start a manual integration by clicking the "Integrate" button in the upper right-hand corner of the Bot screen.

Troubleshooting

Sometimes your Xcode Schemes may not be shared and visible to your bots. If that's the case, then open your Xcode project inside of Xcode and click Product > Create Bot.

Image showing the bot creation in Xcode

In the Bot creation dialog, then select the Scheme you wish to share, followed by checking the "Share Scheme" checkbox. Make sure that your proper server appears in the drop-down and enter the exact same Name for the Bot that you chose during the web setup. When done, click Next, then confirm the defaults on the next pages.

After your scheme has been shared, then commit your changes and push to your remote. This extra process will create a bot automatically; but, you can delete the Xcode created bot once the Shared Scheme has been pushed.

Note: If you do not have the proper code signing certificates and provisioning profiles installed on the server, then you may get code signing errors. You can fix these these by installing the certificates and profiles onto your Mavericks server.

More Information

For more information about working with Xcode Bots on Mavericks Server and in Xcode 5, check out the documentation provided by Apple.

Cory Bohon is an indie iOS and Mac developer at Cocoa App and Empirical Development. Follow this article's author, Cory Bohon on Twitter.

Collection Operators

13 January 2014

We've all been there: You need to get the average of a group of objects. What do we typically do? That's right, we start with a for loop, iterating through all of the objects, performing the calculation that we need. There is a better way, however, and it'll change the way you look at this mundane task forever in Objective-C.

It's called KVC (Key-Value Coding) Collection Operators, and while other languages have had similar operators (specifically Ruby) built in since it's inception, these functions will prove invaluable and replace many lines of code that you would normally write. There are three different types of Collection Operators that handle different tasks: Simple operators (handle math and other frequently needed tasks such as averaging, counting, and summing), Object operators (unioning objects), and Array and Set operators.

In this post, we'll take a look at using the Simple operators to do routine tasks with collections of objects, but the Apple documentation on this topic delves into much greater detail if you're interested.

Here's the sample object that we'll be working with

@interface Produce : NSObject
@property NSString *name;
@property double price;
@property int quantity;
@end


Now, if we wanted to get the sum of the quantity of all the produce objects, then we'd typically do something like this:

int sumOfProduceQuantity = 0;
for (Produce *produce in produceList) {
    sumOfProduceQuantity += produce.quantity;
}


That would, by all leaps of the imagination, consistently gather the sum of the produce quantity, but what if we wanted to simplify this code?

NSNumber *number = [produceList valueForKeyPath:@"@sum.quantity"];


Yes, it's that simple to sum all of the objects in our NSArray called produceList containing our Produce objects.

In the valueForKeyPath NSString call, use the "@" to signify that you want to perform an operation on a particular value in the collection. Here, we specify "@sum" to signify that we wish to sum a value. Then, we follow the operator with a dot and the property on our object that we wish to perform the operation on. Pretty nifty, huh?

The other Simple operators are:

Apple has a complete guide on the developer site focused on using Collection Operators in your own code. They delve into more functionality, including the Object operators and Array and Set Operator.

Cory Bohon is an indie iOS and Mac developer at Cocoa App and Empirical Development. Follow this article's author, Cory Bohon on Twitter.

Block Syntax in Objective-C 2.0

05 January 2014

Blocks are everywhere since their implementation in Objective-C 2.0. More and more frameworks, and even our own class and framework implementations are taking advantage of these great ways of passing code around in various forms.

If you're asking what a block is, then I suggest taking a look at the Blocks Programming Topics documentation that Apple provides on their site.

This post should help serve as a reference as to the syntax that is used when dealing with blocks in various forms you may encounter while developing Objective-C based applications on both the Mac and iOS. Without further ado, here are the ways that blocks can be used in your own code.

Using Blocks as Local Variables

returnType (^blockName)(parameterTypes) = ^returnType(parameters) {...};

Using Blocks as a Property

@property (nonatomic, copy) returnType (^blockName)(parameterTypes);

Using Blocks as a Method Parameter

- (void)methodName:(returnType (^)(parameterTypes))blockName {...}

Using Blocks as an Argument to a Method Call

[object methodName: ^returnType (parameters) {...}];


If you're looking for a bookmarkable-friendly version, then check out fuckingblocksyntax.com. As you can see, blocks are fun, and can be used almost anywhere in your code. If you're not already using them, then give them a whirl in your code today.



Cory Bohon is an indie iOS and Mac developer at Cocoa App and Empirical Development. Follow this article's author, Cory Bohon on Twitter.

Formatting NSString for Display Using NSMutableArray

16 December 2013

Sometimes you need to concatenate multiple strings together for display purposes. You don't know if you have strings that are nil, or if you have valid strings for display, so what do you do? Most folks might immediately think about validating each of the elements, checking to see if they are nil, and adding them to a new string that appends each of the valid elements to it, then return it for display. However, there is a little trick that involves using an NSMutableArray that makes this process a little easier.

In each of the instances that I'm going to cover, we need to return a string that can be used for presentation. It contains three strings that need to be concatenated together with a space in between (you don't always know if the one or all of the elements will be nil or not).

Here's one way that I've seen folks concatenate strings:

- (NSString *)returnMyString {
    NSString *firstString = @"First";
    NSString *secondString = @"Second";
    NSString *thirdString = @"Third";

    return [NSString stringWithFormat:@"%@ %@ %@", firstString, secondString, thirdString];
}

That looks pretty good... or, not.

This is a particularly bad way to concatenate strings, because the elements that are nil can be added to the final string as "(null)". Pretty bad if you are planning on displaying the concatenated string in a UITableViewCell, UITextField, UILabel, etc. You can usually tell which developers use this method of string concatenation because app data when presented can usually be seen littered with "(null)" strings.

Here's another way, with the checks that are needed to ensure that no nil elements are added to the concatenated string:

- (NSString *)returnMyString {
    NSString *firstString = @"First";
    NSString *secondString = @"Second";
    NSString *thirdString = @"Third";

    NSString *concatenatedString = [NSString alloc] init];

    if (firstString) {
        concatenatedString = firstString;
    }

    if (secondString) {
        concatenatedString = [concatenatedString stringByAppendingString:[NSString stringWithFormat:@" %@", secondString]];
    }

    if (thirdString) {
        concatenatedString = [concatenatedString stringByAppendingString:[NSString stringWithFormat:@" %@", thirdString]];
    }

    return concatenatedString;
}

We can greatly reduce the need for all of this space and complexity by using some built-in functionality with the NSMutableArray class. The code below will concatenate the string and return it, but notice that it uses less code, and is more robust when adding new strings in the future.

- (NSString *)returnMyString {
    NSString *firstString = @"First";
    NSString *secondString = @"Second";
    NSString *thirdString = @"Third";

    NSMutableArray *strings = [[NSMutableArray alloc] init];

    if (firstString) [strings addObject:firstString];
    if (secondString) [strings addObject:secondString];
    if (thirdString) [strings addObject:thirdString];

    return [strings componentsJoinedByString:@" "];
}

This sure isn't the shortest way of concatenating a string together with a space, but it's pretty foolproof. Add the non-nil items to the NSMutableArray, then use the -componentsJoinedByString: method to turn those NSString elements into a string that has each of the components separated by a space.

This is great for forward-looking functionality because you can easily change the number of elements that get concatenated with little thought, and can change the joining string very easily. Want each of the strings separated by a comma (,)? No problem! Just change the string passed into the componentsJoinedByString method call in the return statement.

Cory Bohon is an indie iOS and Mac developer at Cocoa App and Empirical Development. Follow this article's author, Cory Bohon on Twitter.

Syncing Key-Value Pairs with NSUbiquitousKeyValueStore

09 December 2013

It may have a long name, but NSUbiquitousKeyValueStore can be a powerful, yet easy way, to get key-value pairs synced across multiple devices using iCloud. Typically, developers use NSUserDefaults to save bits of information that may be accessed infrequently, such as saved game state, or other user preferences. Almost anything can be stored in NSUserDefaults, including custom class objects that you create (assuming they are NSCoding-compliant).

About NSUbiquitousKeyValueStore

NSUbiquitousKeyValueStore works extremely similar to NSUserDefaults, and both classes even have the same methods for getting and setting values.

Getting Values

– arrayForKey:
– boolForKey:
– dataForKey:
– dictionaryForKey:
– doubleForKey:
– longLongForKey:
– objectForKey:
– stringForKey:

Setting Values

– setArray:forKey:
– setBool:forKey:
– setData:forKey:
– setDictionary:forKey:
– setDouble:forKey:
– setLongLong:forKey:
– setObject:forKey:
– setString:forKey:

Limitations

The thing to remember is that NSUbiquitousKeyValueStore is NOT a replacement for NSUserDefaults. First, you've got the physical limitations: if iCloud is unavailable, then the data will not sync. Next is that each application is limited to 1024 keys, each with a per-key size limit of 1 MB. Trying to write more keys than each application is allocated will cause the write attempt to fail and no change made to the key-value store.

There is also a key string limit of 64 bytes using a UTF-8 encoded string. Trying to write a longer key string will cause a runtime error.

To combat this, you should not attempt to insert large objects into the NSUbiquitousKeyValueStore. Leave this storage space only for necessities that need to be synced between devices (such as saved game state, or user preferences). In addition, you should keep all data synced to NSUbiquitousKeyValueStore in the local NSUserDefaults as well. If not for a fallback, at least for a comparison for syncing issues (which we'll cover later).

Syncing Items

Syncing with NSUbiquitousKeyValueStore is extremely simple. You'd use it just like you would NSUserDefaults, like so:

[[NSUbiquitousKeyValueStore defaultStore] 
setBool:YES forKey:@"MyKeyName"];

Just like NSUserDefaults, the NSUbiquitousKeyValueStore is a singleton class, and instance of which is accessed by calling +defaultStore.

That's it! NSUbiquitousKeyValueStore will do the rest, ensuring that the key and its value is properly synced to iCloud and that the key-value pair is made available on all devices that also support iCloud. If you need your values to immediately be written to disk and available to iCloud for syncing, then you can optionally call the -synchronize method.

Retrieving Items

To retrieve an item that has been synced using NSUbiquitousKeyValueStore, you can just the following method call:

BOOL savedBool = [[NSUbiquitousKeyValueStore defaultStore] 
boolForKey:@"MyKeyName"];

Avoiding Sync Conflicts

The thing to remember is that NSUbiquitousKeyValueStore is not a replacement for NSUserDefaults. NSUbiquitousKeyValueStore is not guaranteed to be available, so you need a fall back. In addition, you may run into syncing conflicts.

A syncing conflict may go something like this: Device A plays through level 11 in a game; Device B plays through level 3 in a game. Both devices sync to iCloud, but device B syncs last, meaning that "level 3" is written to the NSUbiquitousKeyValueStore.

When device A next loads the game, and tries to retrieve the level, it's going to see that the "level 3" value has been written to NSUbiquitousKeyValueStore, but it's local save state in NSUserDefaults shows that it's on level 11.

To ensure that the user of the game doesn't get mad, you'll most likely want to replace the iCloud saved game state with "level 11" (or the greater of the two). A simple if statement check could ensure that the game doesn't revert back to a non-current level for the user.

Notifications

NSUbiquitousKeyValueStore publishes notifications whenever the the local key-value store has changed due to new data from iCloud. This notification is only set when the device recieves the change from iCloud, and not when the application sets a new value.

To receive notifications, ensure that your class is subscribed to the NSUbiquitousKeyValueStoreDidChangeExternallyNotification NSNotification. Check out the documentation to learn about the values that are passed the notification.

Syncing other Data

NSUbiquitousKeyValueStore should never be used to sync application data such as databases. If you need to sync application-created data, then you should take a look at using iCloud's UIDocument syncing, or CoreData sync.

Cory Bohon is an indie iOS and Mac developer at Cocoa App and Empirical Development. Follow this article's author, Cory Bohon on Twitter.

Using -endEditing to dismiss the keyboard

24 November 2013

There are a lot of places where you may want to dismiss the on-screen iOS keyboard, but you may not always have a pointer to the UITextField that is currently the first responder. This can happen when dealing with a lot of UITextFields in a UITableView implementation, or any other myriad of possibilities.

Most folks choose to dismiss the keyboard by calling -resignFirstResponder on the text field to have it relinquish it's role as a first responder, thereby dismissing the keyboard if no other input view claims first responder status.

However, you can also easily dismiss the keyboard for a text input field attached to any view with one simple call (without having access to the text field pointer directly):

[self.view endEditing:YES];

Sending the -endEditing:(BOOL)force call to the view containing the input first responder will cause the text field to be sent a resign message, causing the on-screen keyboard to be dismissed. You can call -endEditing: on self.view if you are working with a UIViewController that implements text field subviews somewhere in the hierarchy; or, replace "self.view" with the container view that contains your text fields.

So, what's the force BOOL? This method looks at the current view and its subview hierarchy for a text field that is currently a first responder. If it finds one, it asks the text field to resign as first responder. However, if you pass in a BOOL of YES to the -endEditing: call, then the force parameter is set to YES and the text field will not be asked to resign, it will be force to resign instead.

The BOOL return value from the call will be YES if the view resigned the responder, and NO otherwise. This little trick works in iOS 2.0 and higher, and is available to be called on all UIView subclasses.

Cory Bohon is an indie iOS and Mac developer at Cocoa App and Empirical Development. Follow this article's author, Cory Bohon on Twitter.

Update: OS X Application Testing Mindmap

18 November 2013

There were a few people who read the post that I did on the OS X Testing Mindmap and wanted me to post the original files relating to the mindmap so they could customize and tweak them to their liking.

I would like to announce today that I have posted the original mindmap files both on GitHub and available for static download here.

If you would like to contribute to the mindmap files on GitHub, feel free to fork, and issue a pull request for any additions to the mindmap.

You can view the original files in many different formats, including:

View the files on GitHub here, and consider contributing to the project to help make the OS X Testing Mindmap even better.

Cory Bohon is an indie iOS and Mac developer at Cocoa App and Empirical Development. Follow this article's author, Cory Bohon on Twitter.

Older