Common method in Swift


1. Check for any field empty in NSDictionary

class func checkforEmptyValueinDictioanty(dic:NSDictionary)-> Bool{

for (keyVal, dataVal) in dic {

  if (dataVal.length()==0){

                println(\(keyVal): \(dataVal.length()))

                return false

            }

            

        }

        return true

    }

2.Email validation

class func isValidEmail(testStr:String) -> Bool {

let fullNameArr = testStr.componentsSeparatedByString(“@”)

        var firstPart: String = fullNameArr[0]

        if let range = firstPart.rangeOfCharacterFromSet(NSCharacterSet.letterCharacterSet()){

 }else{

            return false

        }

      let emailRegEx = “[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}”

 var emailTest = NSPredicate(format:“SELF MATCHES %@”, emailRegEx)

        let result = emailTest.evaluateWithObject(testStr)

        return result

    }

3. Alert in Swift

class func commonAlert(title:String,msg:String,curView:UIViewController){

        var device : UIDevice = UIDevice.currentDevice();

        var systemVersion = device.systemVersion;

        var iosVerion : Float = (systemVersion as NSString).floatValue

        if(iosVerion >= 8.0) {

    

        var alert = UIAlertController(title: title, message: msg, preferredStyle: UIAlertControllerStyle.Alert)

            alert.addAction(UIAlertAction(title: “Ok”, style: UIAlertActionStyle.Default, handler: nil))

                  // return alert

            curView.presentViewController(alert, animated: true, completion: nil)

        }else{

            let alert=UIAlertView(title: title, message: msg, delegate: self, cancelButtonTitle: “ok”)

            alert.show()

           

        }

    }

4. NSUserDefaults in swift as common function

class func saveToUserDefault(value:AnyObject, key:String)

    {

        NSUserDefaults.standardUserDefaults().setObject(value, forKey:key)

        NSUserDefaults.standardUserDefaults().synchronize()

    }

    

    class func userDefaultForKey(key:String) -> String

    {

        return NSUserDefaults.standardUserDefaults().objectForKey(key) as NSString

        

    }

    class func userDefaultForAny(key:String) -> AnyObject

    {

        return NSUserDefaults.standardUserDefaults().objectForKey(key) as AnyObject!

    }

    

    class func userdefaultForArray(key:String) -> Array<AnyObject>

    {

        return NSUserDefaults.standardUserDefaults().objectForKey(key) as Array

    }

    

    class func removeFromUserDefaultForKey(key:String)

    {

        NSUserDefaults.standardUserDefaults().removeObjectForKey(key)

        NSUserDefaults.standardUserDefaults().synchronize()

        

    }

5.Get screen height and width

let _screenWidth=UIScreen.mainScreen().bounds.size.width

let _screenHeight=UIScreen.mainScreen().bounds.size.height

Advertisements

Use HexColor in Swift as a color


Add it in your class 

extension UIColor {

   convenience init(red: Int, green: Int, blue: Int) {

       assert(red >= 0 && red <= 255, “Invalid red component”)

       assert(green >= 0 && green <= 255, “Invalid green component”)

       assert(blue >= 0 && blue <= 255, “Invalid blue component”)

       self.init(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: 1.0)

   }

   convenience init(netHex:Int) {

       self.init(red:(netHex >> 16) & 0xff, green:(netHex >> 8) & 0xff, blue:netHex & 0xff)

   }

}

Use it where you need…….

var color = UIColor(red: 0xFF, blue: 0xFF, green: 0xFF)

var color2 = UIColor(netHex:0xFFFFFF)

iPhone UITableView cells stay selected-Problem


Msy

Many Times , we have seen UITableView cells stay selected . we can solve this problem by two methods

1. put following code in didSelectRowAtIndexPath.

[tableView deselectRowAtIndexPath:[tableView indexPathForSelectedRow] animated:YES];

2. put code in viewWillAppear.

- (void) viewWillAppear:(BOOL)animated {
    [tableView deselectRowAtIndexPath:[tableView indexPathForSelectedRow]
 animated:animated];
    [super viewWillAppear:animated];
}

Add Search Into a Table View


In the mobile app world, people want their information fast, and they want it now!

iOS users expect their data to be available on-demand and presented quickly. Furthermore, they expect this to all happen in an easy to use and intuitive manner. It’s a tall order, to be sure!

Many UIKit based applications utilize the UITableView as a way to navigate through data, since scrolling is natural and fast. But what about the cases where there are large, even huge, amounts of data to sift through? With large datasets, scrolling through massive lists becomes slow and frustrating – so it’s vitally important to allow users to search for specific items.

Lucky for us, UIKit includes UISearchBar which seamlessly integrates with your table views and allows for quick, responsive filtering of information.

In this tutorial, you’ll learn how to add search capability into your UITableView based apps, including dynamic filtering and adding an optional Scope Bar. In the end, you’ll know how to make your apps much more user friendly and satisfy your users urgent demands!

Don’t Fear the Bar!

The ability to search a large table view is something that today’s users expect; when they find it isn’t present, they won’t be happy campers!

Don’t let this happen to your users.
Always give them a search option.

The problem is the UISearchBar can be confusing when you first look at it, because it isn’t very well documented and figuring out how to get all the pieces to fit together can be quite tricky.

However, once you work with the Search Bar a bit, you’ll find that it’s not nearly as frightening as you might expect – especially after you go through this tutorial!

When you look at the UISearchBar, you’ll discover it’s kind of like a lazy layabout. It doesn’t do any of the work of searching at all! The class simply provides a standard interface that users have come to expect from their iOS apps. It’s more like a middle-class manager in that respect; it’s great at delegating tasks to others. (Like my old boss!)

The UISearchBar class communicates with a delegate protocol to let the rest of your app know what the user is doing. All of the actual functions for string matching and other operations will be written by you. Although this may seem a tad scary at first (and more than a little unfair!), writing custom search functions gives you tight control over how results are returned specifically in your app. Your users will appreciate searches that are intelligent — and fast.

In this tutorial you’ll build a searchable Candy app which is based on a table view. (Mmmm, candy!)

But first — a quick road map of where this tutorial will take you:

  • Candy Class: You’ll build a custom object that will allow your search function to search through the sample data (and also satisfy those munchies).
  • Table View: Here you’ll quickly go through the steps of setting up a table view. If you already know how to do this, you can quickly breeze through this section.
  • Search Bar: You’ll implement a search bar class onto your view controller so you can introduce some search functionality.
  • Filtered Array: Here you’ll learn how to manipulate a filtered array to handle your new search function.
  • Sending Data: This will serve as a reinforcement to the changes that are necessary to things like navigation when dealing with a search bar
  • Scope Bar: Here you’ll experience a powerful feature of the UISearchBar class: a scope bar for further zeroing in on search results.
  • Hiding the UISearchBar: This last section will show you how to perform a popular feature – hiding the search bar until the user needs it!

Ready for some sugar-coated search results? Read on!

I Want Candy

I'm getting hungry just working on this tutorial!

I’m getting hungry just working on this tutorial!

In XCode, go to “File \ New \ Project…” and choose iOS\Application\Single View Application. Name the project “CandySearch” and make sure that “Use Storyboards” and “Use Automatic Reference Counting” are checked. Finally make sure that iPhone is selected for “Device” and click Next. Save the project at a location of your choice.

Start by clearing out some of the default files so you can truly start from scratch. In the Project Navigator, select ViewController.h and ViewController.m, right-click, select Delete, and then click “Move to Trash”. Then open up the MainStoryboard.storyboard, select the only view controller and delete it.

Now that you have a fresh project to work with, start by creating the storyboard. From the Object Browser (the lower half of the right sidebar) drag out a Navigation Controller to add iOS’s built-in navigation logic to our project. This will create two views on the storyboard – one that represents the navigation controller and one that will be the UITableView that will be the initial screen of the application.

One final view controller will serve as the detail view controller that is displayed when the user navigates or searches the table. Drag a View Controller object onto the storyboard and link the two views by control-dragging from the Table View to the new view controller and selecting “Push” as the modal segue from the popup. As of now, this is how your project should look:

Setting Up the Candy Class

Next you will create a model class to keep track of the information about each piece of candy you’re displaying, such as its category and name.

To do this, create a new file with the iOS\Cocoa Touch\Objective-C class template. Name the class Candy, and make it a subclass of NSObject.

Open up Candy.h and replace its contents with the following:

    #import <Foundation/Foundation.h>
 
    @interface Candy : NSObject {
        NSString *category;
        NSString *name;
    }
 
    @property (nonatomic, copy) NSString *category;
    @property (nonatomic, copy) NSString *name;
 
    + (id)candyOfCategory:(NSString*)category name:(NSString*)name;
 
    @end

This object has two properties that can be referenced the category of the candy, and the name of the candy. When the user searches for a candy in your app, you’ll be referencing the name property against the user’s search string. You’ll see how the category string will become important near the end of this tutorial when we implement the Scope Bar.

To finish making this object, replace the contents of Candy.m with the following code:

    #import "Candy.h"
 
    @implementation Candy
    @synthesize category;
    @synthesize name;
 
    + (id)candyOfCategory:(NSString *)category name:(NSString *)name
    {
        Candy *newCandy = [[self alloc] init];
        newCandy.category = category;
        newCandy.name = name;
        return newCandy;
    }
 
    @end

The method above gives your custom object a way to create a new instance of the Candy object which contains the name and category passed to the method. You’ll populate your table from the data stored in these Candy objects, which will allow you to easily filter the data using your search methods.

Now we are ready to set up the UITableView that our UISearchBar will filter!

Please set the UITableViewController, dear…

Next you will set up a UITableView that will work with the UISearchBar. Create a new file with the iOS\Cocoa Touch\Objective-C class template. Name the class CandyTableViewController, and make it a subclass of UITableViewController.

We will start by adding an array for the sample data. Open CandyTableViewController.h and add the following code below the @interface line:

    @property (strong,nonatomic) NSArray *candyArray;

Now for some quick edits to CandyTableViewController.m in order to finish the sample table. First, clean out some of the default code in the project that won’t be required. Remove all the code beginning with -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath to the end of the file (except the @end).

Also remove the numberOfSectionsInTableView: method, as it won’t be necessary in this app.

At the top of the file, import Candy.h so the table view controller understands this object.

    #import "Candy.h"

Now synthesize the candyArray below the @implementation line.

    @synthesize candyArray;

Now that you’ve connected the view controller with the Candy object, you can use the candyOfCategory:name: method to add some data. In this tutorial, you only need to create a limited number of values to illustrate how the search bar works; in a production app, you might have thousands of these searchable objects. But whether an app has thousands of objects to search or just a few, the methods used will remain the same. Scalability at it’s finest!

In viewDidLoad, clear out the templated comments and add the following code to provide some sample data:

    // Sample Data for candyArray
    candyArray = [NSArray arrayWithObjects:
                  [Candy candyOfCategory:@"chocolate" name:@"chocolate bar"],
                  [Candy candyOfCategory:@"chocolate" name:@"chocolate chip"],
                  [Candy candyOfCategory:@"chocolate" name:@"dark chocolate"],
                  [Candy candyOfCategory:@"hard" name:@"lollipop"],
                  [Candy candyOfCategory:@"hard" name:@"candy cane"],
                  [Candy candyOfCategory:@"hard" name:@"jaw breaker"],
                  [Candy candyOfCategory:@"other" name:@"caramel"],
                  [Candy candyOfCategory:@"other" name:@"sour chew"],
                  [Candy candyOfCategory:@"other" name:@"peanut butter cup"],
                  [Candy candyOfCategory:@"other" name:@"gummi bear"], nil];
 
    // Reload the table
    [self.tableView reloadData];

Replace the contents of tableView:numberOfRowsInSection: with the following line that returns the size of the candyArray:

return [candyArray count];

Add the following code above the final @end:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if ( cell == nil ) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }
    // Create a new Candy Object
    Candy *candy = nil;
    candy = [candyArray objectAtIndex:indexPath.row];
    // Configure the cell
    cell.textLabel.text = candy.name;
    [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
    return cell;
}

First, you tell the table view controller what to display for each row. You then access the candyArray object, reference the indexPath to decide which Candy object to pull, and then use that Candy object to populate the UITableViewCell.

You’ll need to set up the storyboard to recognize this code. Switch to MainStoryboard.storyboard, select the Root View Controller and change the Class field in the Identity Inspector (third tab on the top half of the right sidebar) to CandyTableViewController.

Then select the table view and wire the dataSource and delegate to the View Controller by switching to the Connections Inspector (it’s the sixth tab on the top half of the right sidebar) and dragging from each outlet to the Candy Table View Controller on the left sidebar.

Double click the title to change it from the rather unattractive “Root View Controller” title to “CandySearch”.

Save your changes and build and run. You now have a working table view! So much candy…so little time! We need…a UISearchBar!

Setting Up the UISearchBar

Now you’re ready to set up the UISearchBar! Start by opening up the storyboard and dragging a Search Bar and Search Display Controller object to the table view controller. Be careful — this is different from the Search Bar object, which is also available. Position the Search Bar between the Navigation bar and the Table View.

Note: Not sure what’s meant by a search display controller? According to Apple’s own documentation, a search display controller “manages display of a search bar and a table view that displays the results of a search of data managed by another view controller.

You initialize a search display controller with both a search bar and a view controller responsible for managing the original content to be searched. When the user begins a search action, the search display controller is responsible for superimposing the search interface over the original view controller’s view, and showing the search results. The results are displayed in a table view that’s created by the search display controller.”

So basically, the search display controller added above handles the task of showing the filtered data from a search in a separate view controller that you don’t have to worry about :]

UISearchBar Options in the Attributes inspector

While in the storyboard, take a moment to review the properties available for the Search Bar object. You may not use all of these, but knowing what’s available in the Attributes inspector is always valuable when working with a new UIKit component.

  • Text: This will change the actual string value that is present in the search bar. As your app has no need to have a default value in the search bar, you won’t need this.
  • Placeholder: This does exactly what you might expect – it allows you to put the light gray text in the Search bar that tells the user what the search bar can be used for. In the case of the Candy app, use something such as “Search for Candy”.
  • Prompt: This text will appear directly above the search bar. This is good for apps that have complicated search mechanisms, where the user might need instructions. (But in this app, the Placeholder text should be pretty clear!)
  • Style & Tint: These options allow you to customize the appearance of your search bar. The options are almost identical to those of the UINavigationBar and it is normally advisable to have your UISearchBar match your UINavigationBar for harmonious design.
  • Show Search Results Button: Provides a button on the right side of the search bar for performing functions such as displaying recent searches or showing the last search results. Interaction with this button is managed through the Search Bar Delegate methods.
  • Show Bookmarks Button: Shows the standard blue oval bookmarks icon in the right hand side of the search bar. Users expect this to bring up a list of their saved bookmarks. Like the search results button, this too is managed through the Search Bar Delegate methods.
  • Show Cancel Button: This button allows users to close the separate view controller that is generated by the search bar. Leave this unchecked, as the search bar will automatically show and hide the Cancel button when the user is in Search mode.
  • Shows Scope Bar & Scope Titles: The scope bar allows users to refine their search by limiting the results to a certain category, or scope. In a music application, for example, this bar may show choices such as Artists, Albums or Genres. For now, leave this box unchecked; you will implement your own scope bar later in this tutorial.
  • Capitalize, Correction & Keyboard: These are options that have been borrowed from the normal UITextField options and allow you to change your search bar’s behavior. For example, if the user will be searching on proper nouns like businesses or last names, you may want to consider turning off correction as it will be annoying to users. In this tutorial, the candy names are all common nouns, so keep autocorrect enabled.

Note: Knowing the available options allows you to reduce development time and be more efficient. So as a general note for your future iOS development, always take the time to get acquainted with the resources available :]

Setting Up the UISearchBarDelegate

After setting up the storyboard, you’ll need to do some coding work to get the search bar working. Add theUISearchBarDelegate and UISearchDisplayDelegate classes to the CandyTableViewController. To do this, switch to CandyTableViewController.h and replace:

@interface CandyTableViewController : UITableViewController

with:

@interface CandyTableViewController : UITableViewController <UISearchBarDelegate, UISearchDisplayDelegate>

In addition, add an IBOutlet for the search bar and a new “filteredCandyArray” which will hold our search results.

@property (strong,nonatomic) NSMutableArray *filteredCandyArray;
@property IBOutlet UISearchBar *candySearchBar;

Don’t forget to synthesize the new properties in CandyTableViewController.m:

@synthesize filteredCandyArray;
@synthesize candySearchBar;

Of course, now that you have an outlet, you need to wire the search bar on your storyboard to the outlet. Switch to the storyboard, select the Candy Table View controller, switch to the Connections Inspector, and drag a connection from the candySearchBar outlet to the Search Bar on the main screen.

Compile and run now, and you’ll get the search bar on the app — but it won’t filter anything yet! In order to do this, you’ll have to set up the filteredCandyArray.

Setting Up the Filtered Array

First you will have to initialize the NSMutableArray. You can initialize the array with the size of the candyArray, as it isn’t possible to have more filtered values than the number of values that we started with. Add the following line of code to viewDidLoad in CandyTableViewController.m where we set the candyArray, but before the [self.tableView reloadData]:

    // Initialize the filteredCandyArray with a capacity equal to the candyArray's capacity
    self.filteredCandyArray = [NSMutableArray arrayWithCapacity:[candyArray count]];

Add the following code to the end of the file:

#pragma mark Content Filtering
-(void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope {
    // Update the filtered array based on the search text and scope.
    // Remove all objects from the filtered search array
    [self.filteredCandyArray removeAllObjects];
    // Filter the array using NSPredicate
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF.name contains[c] %@",searchText];
    filteredCandyArray = [NSMutableArray arrayWithArray:[candyArray filteredArrayUsingPredicate:predicate]];
}

The above method will filter candyArray based on searchText (which is the search string entered by the user), and will put the results in filteredCandyArray. This filter method clears out any previous filtered search results by calling the “removeAllObjects” method. After the array has been cleared, a NSPredicate is used to filter the candy array based on the search string.

NSPredicate can filter an array using a simple condition string. Notice the format of the NSPredicate:

@"SELF.name contains[c] %@",searchText

Look a little confusing? Fear not; it’s actually fairly simple. SELF.name tells the NSPredicate to look at the “name” property of the Candy objects in the candyArray. “contains[c]” tells the predicate to search the “name” property for the provides text string, which is the search text in this case, in a case-insensitive manner.

Next, add the following code to the end of the file:

#pragma mark - UISearchDisplayController Delegate Methods
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
    // Tells the table data source to reload when text changes
    [self filterContentForSearchText:searchString scope:
     [[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];
    // Return YES to cause the search result table view to be reloaded.
    return YES;
}
 
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption {
    // Tells the table data source to reload when scope bar selection changes
    [self filterContentForSearchText:self.searchDisplayController.searchBar.text scope:
     [[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:searchOption]];
    // Return YES to cause the search result table view to be reloaded.
    return YES;
}

This code sets up the UISearchDisplayController Delegate methods that will call the content filtering function when the the user enters a search query.

The first method runs the text filtering function whenever the user changes the search string in the search bar. The second method will handle the changes in the Scope Bar input. You haven’t yet added the Scope Bar in this tutorial, but you might as well add this UISearchBarDelegate method now since you’re going to need it later.

Compile and run the app now; you’ll notice that using the Search Bar still does not bring up any filtered results. What gives? This is simply because you haven’t yet written the code to let cellRowForIndexPath: know when to use the normal data vs. the filtered data. Replace:

	candy = [candyArray objectAtIndex:[indexPath row]];

with:

    // Check to see whether the normal table or search results table is being displayed and set the Candy object from the appropriate array
    if (tableView == self.searchDisplayController.searchResultsTableView) {
        candy = [filteredCandyArray objectAtIndex:indexPath.row];
    } else {
        candy = [candyArray objectAtIndex:indexPath.row];
    }

This code tests to see if the currently displayed tableView is the search table or the normal table. If it is indeed the search table, the data is taken from the filteredCandyArray. Otherwise, the data comes from the full list of items. Recall that the search display controller automatically handles showing and hiding the results table, so all your code has to do is provide the correct data (filtered or non-filtered) depending on which table view is currently displaying.

You’ll have to do something similar with numbersOfRowsInSection: since the number of rows for the filtered vs. non-filtered array are very likely going to be different! Replace the current contents of the method with:

// Check to see whether the normal table or search results table is being displayed and return the count from the appropriate array
if (tableView == self.searchDisplayController.searchResultsTableView) {
    return [filteredCandyArray count];
} else {
    return [candyArray count];
}

Compile and run the app. You’ve got a functioning Search Bar that filters the rows of the main table! Huzzah! Play with the app for a bit to see how the user can search for various candies.

Note: You’ve probably noticed that that the if/else logic found in the numberOfRowsInSection: method is reused quite a few times. This is important when working with the Search Bar Display Controller and omitting this if/else check may result in bugs that will be difficult to track down. Just remember that the filtered results do not appear in the same table view as the main table. They are actually completely separate table views, but Apple has designed them in such a way that the experience is seamless for the end user — at the expense of being confusing to the novice developer!

Sending Data to a Detail View

When sending information to a detail view controller, you need to ensure that the view controller knows which table view the user is working with: the full table list, or the search results. The code for this will be similar to the code that we wrote in numbersOfRowsInSection: and cellForRowAtIndexPath: methods. Add the following code to the end of your CandyTableViewController.m file:

#pragma mark - TableView Delegate
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // Perform segue to candy detail
    [self performSegueWithIdentifier:@"candyDetail" sender:tableView];
}
 
#pragma mark - Segue
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([[segue identifier] isEqualToString:@"candyDetail"]) {
        UIViewController *candyDetailViewController = [segue destinationViewController];
        // In order to manipulate the destination view controller, another check on which table (search or normal) is displayed is needed
        if(sender == self.searchDisplayController.searchResultsTableView) {
            NSIndexPath *indexPath = [self.searchDisplayController.searchResultsTableView indexPathForSelectedRow];
            NSString *destinationTitle = [[filteredCandyArray objectAtIndex:[indexPath row]] name];
            [candyDetailViewController setTitle:destinationTitle];
        }
        else {
            NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
            NSString *destinationTitle = [[candyArray objectAtIndex:[indexPath row]] name];
            [candyDetailViewController setTitle:destinationTitle];
        }
 
    }
}

Open up the storyboard and make sure that the segue from the Candy Table View Controller to the Detail View has the identifier “candyDetail”. Compile and run the code at this point and see how the app now navigates to the Detail View from either the main table or the search table with ease.

Creating an Optional Scope Bar to Filter Results

If you wish to give your users another way to further filter their results, a Scope Bar can be used in conjunction with your search bar in order to filter out items by their category. The categories you will filter on are the ones you assigned to the Candy object when the candyArray was created: chocolate, hard, and other.

First, set up the scope bar on the storyboard. Go to the CandySearch View Controller and select the search bar. In the attributes inspector, check “Shows Scope Bar” in the Options section. Then modify the Scope Titles to be: “All”, “Chocolate”, “Hard” ,and “Other”. (You can use the + button to add more scope items and if you double-click an item, you can edit the item title). This is what your screen should look like:

Next, modify filterContentForSearchText: in CandyTableViewController.m to take the new scope into account. Replace the current method implementation with the following:

-(void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope {
	// Update the filtered array based on the search text and scope.
    // Remove all objects from the filtered search array
	[self.filteredCandyArray removeAllObjects];
	// Filter the array using NSPredicate
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF.name contains[c] %@",searchText];
    NSArray *tempArray = [candyArray filteredArrayUsingPredicate:predicate];
    if (![scope isEqualToString:@"All"]) {
        // Further filter the array with the scope
        NSPredicate *scopePredicate = [NSPredicate predicateWithFormat:@"SELF.category contains[c] %@",scope];
        tempArray = [tempArray filteredArrayUsingPredicate:scopePredicate];
    }
    filteredCandyArray = [NSMutableArray arrayWithArray:tempArray];
}

The new code introduces an additional NSPredicate — scopePredicate — that will further filter the array based on the scope. In order to support the “All” scope, you have to make sure that you don’t do any extra filtering if the scope is equal to “All”.

Compile and run the app. You’ll notice that the scope bar shows up — hey, that was easy! However, the app shows the scope bar before the user has even tapped on the Search Bar! It looks like we’re getting ahead of ourselves here. Add this code to the top of viewDidLoad (right after the call to super):

	// Don't show the scope bar or cancel button until editing begins
    [candySearchBar setShowsScopeBar:NO];
    [candySearchBar sizeToFit];

Compile and run now. Here’s how your scope bar should look:

Hiding the UISearchBar Like the Music App

It would be really neat if your app could initially hide the Search Bar, just like the way the Music app does. This initially gives your table view a little more real estate. Simply add the following code immediately below the code you just added to viewDidLoad:

    // Hide the search bar until user scrolls up
    CGRect newBounds = self.tableView.bounds;
    newBounds.origin.y = newBounds.origin.y + candySearchBar.bounds.size.height;
    self.tableView.bounds = newBounds;

Since your app hides the Search Bar, it wouldn’t be a bad idea to add a button to indicate to the user that a search function exists. The decision to include an explicit search button depends on the context of the app you’re developing, of course, but in this tutorial we’ll make it obvious that this app supports searching.

Begin by making an IBAction:

Add the follwing code to the bottom of CandyTableViewController.m:

-(IBAction)goToSearch:(id)sender {
    // If you're worried that your users might not catch on to the fact that a search bar is available if they scroll to reveal it, a search icon will help them
    // If you don't hide your search bar in your app, don’t include this, as it would be redundant
    [candySearchBar becomeFirstResponder];
}

Add the method definition to CandyTableViewController.h:

-(IBAction)goToSearch:(id)sender;

Now go to the storyboard and add a Bar Button Item to the navigation bar. In the Attributes Inspector, use Apple’s built-in search icon by changing the identifier to “search”. Then in the connections inspector, connect to goToSearch: by dragging from the “selector” item under “Sent Action” to the view controller.

Bingo! You now have a functional “Search” button on your navigation bar, which takes the user to the search interface. Compile and run to test…

and you’re done! Now give yourself a nice piece of candy :]

Where To Go From Here?

Here is a sample project with all of the code from the above tutorial.

Congratulations – you now have a working app that allows you to search directly from the main table view!

If you were going through this tutorial in order to learn how to implement search in your app, you’re in luck. The code that you’ve just worked through is completely extensible; all you have to do is add more objects as necessary. In a production app, the objects will not usually be defined directly in the code; they would be likely be loaded from some data source such as a plist file.

I hope to see you adding search capabilities to your table view apps in the future. If you have any questions or comments, please join the forum discussion below!

Table View Animations Tutorial: Drop-In Cards


The standard UITableView is a powerful and flexible way to present data in your apps; chances are that most apps you write will use UITableView in some form. However, one downside is that without some level of customization, your apps will look bland and blend in with the thousands of apps just like it.

To prevent boring table views, you can add some subtle animation to liven up the actions of your app. You may have seen this in the popular app Google Plus, where the cards fly in through the side with a cool animation. If you haven’t seen it yet, download it now to check it out (it’s free)!

In this table view animations tutorial, you’ll be enhancing an existing app to rotate the cells of a table as you scroll through. Along the way, you’ll learn about how transforms are achieved in UIKit, and how to use them in a subtle manner so as not to overwhelm your user with too much happening on-screen at once.

This tutorial assumes you know how to work with a UITableView. If you’re not really familiar with table views, you might want to start with a tutorial such as How to Create a Simple iPhone App that will teach you the basics of a TableView app.

Note from Ray: Full credit for this technique goes to Orta Therox, the newest member of our new “Code Team” at raywenderlich.com. Orta created the original sample project which Brian then polished and converted into this tutorial.

The Code Team is a group of expert-level coders interested in coming up with particularly cool demos demonstrating advanced techniques. The Tutorial Team then converts the best demos into high quality tutorials. If you are an expert level iOS developer and are interested in joining the Code Team, contact me!

Getting Started

Download the starter project and open it up in Xcode. You’ll find a simple storyboard project with a UITableViewController subclass (CTMainViewController) and a custom UITableViewCell (CTCardCell). The cell has all the properties that you need to set the data for each individual.

Build and run the project in the simulator; you’ll see the following:

Starter project

A perfectly good design, ready to be spiced up.

The app is off to a good start, but it could use a little more flair. That’s your job; you’ll use some Core Animation tricks to animate your cell.

Defining Your Transformation

You’ll add a rotation effect to your cards to make your app feel a little more dynamic. Core Animation can be used with all elements of UIKit, and some incredibly intricate things can be built using this framework. Although it’s incredibly powerful, there are some portions of it that are tremendously simple to implement.

To get your cards rotating, you’ll apply a transformation to the cell as it is displayed, and then animate it so that it returns to its normal position. Since this transformation will be applied to each row, there’s no sense regenerating the animation for every cell. Instead, you’ll store the animation in a property so that you can reuse it.

Open CTMainViewController.m and add the following property to the @interface block:

@property (assign, nonatomic) CATransform3D initialTransformation;

The code above sets up the property to store your animation.

Next, add the following code to viewDidLoad, immediately after changing the backgroundView:

CGFloat rotationAngleDegrees = -15;
CGFloat rotationAngleRadians = rotationAngleDegrees * (M_PI/180);
CGPoint offsetPositioning = CGPointMake(-20, -20);
 
CATransform3D transform = CATransform3DIdentity;
transform = CATransform3DRotate(transform, rotationAngleRadians, 0.0, 0.0, 1.0);
transform = CATransform3DTranslate(transform, offsetPositioning.x, offsetPositioning.y, 0.0);
_initialTransformation = transform;

The code above first sets up a few CGFloat and CGPoint constants to be used in the transformations. Next, it applies a series of simple transformations and translations to build up the effect, as follows:

  • Start with an identity transform, which is a fancy math term for “do nothing.”
  • Call CATransform3DRotate to apply a rotation of -15 degrees (in radians), where the negative value indicates a clockwise rotation.
  • Apply the rotation around the axis 0.0, 0.0, 1.0; this represents the z-axis, where x=0, y=0, and z=1.
  • Applying just the rotation to the card isn’t enough, as this simply rotates the card about its center. To make it look like it’s tipped over on a corner, add a translation or shift where the negative values indicate a shift up and to the left.

Note: The transformation ultimately is a complicated matrix. If you studied matrix math in school, you may recognize this as multiplication of matricies. Each step multiplies a new transformation until you end up with the final matrix.

Building up transformations

Building up transformations to produce the desired effect.

The transformation is now stored in a property; to see it in action, you need to apply it to your cards.

Applying Your Transformation

First, you’ll just apply the initial transformation to the cells to tip them on their side. You’ll worry about the reverse transformation — returning the cells to their original position — in just a bit.

Add the following line to import section at the top of CTMainViewController.m:

#import <QuartzCore/QuartzCore.h>

Next, add the following method to the implementation section of CTMainViewController.m:

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    UIView *card = [(CTCardCell* )cell mainView];
 
    card.layer.transform = self.initialTransformation;
    card.layer.opacity = 0.8;        
}

TableView calls tableView:willDisplayCell:forRowAtIndexPath on its delegate just before each cell is displayed. The above method grabs a reference to the subview named mainView defined in CTCardCell. The layer property of the UIView elements hold a reference to the Core Animation layer for the view; in turn, layers have a transform property.

By default, transform is set to the identity transform, but here you override this and set the transform to the one you just stored in the property. Finally you set the initial opacity of the layer to 0.8 to look slightly transparent; as the animation progresses you’ll fade the card in to an opacity of 1.0 — which you’ll take care of a little later.

You’ll notice that you’re transforming a child view of the cell, and not the cell itself. Rotating the actual cell would cause part of it to cover the cell above and below it, which would cause some odd visual effects, such as flickering and clipping of the cell. This is why the cell has a large view (mainView) containing all the other items.

Before you build the project, you’ll need to link the framework into the project to see your hard work in action.

Click the CardTilt target in the navigator section on the left of the XCode window. Click Build Phases, then expand the little triangle next to ‘Link Binary with Libraries’. Click the small ‘+’ at the bottom of that section, and add QuartzCore.framework to the build.

Since you don’t want to leave the cells with this crooked alignment, go ahead with the next section before you run the project.

Things Fall Into Place

Core Animation provides a great mechanism to create simple animations in your applications. All you have to do is provide a starting point, as you did above with your initial transform, and an ending point, which you’ll do below, and Core Animation figures out the steps along the way.

To define the end point for your animation, add the following code to tableView:willDisplayCell:forRowAtIndexPath in CTMainViewController.m file just after the point where you set the initial layer properties:

    [UIView animateWithDuration:0.4 animations:^{
        card.layer.transform = CATransform3DIdentity;
        card.layer.opacity = 1;
    }];

In the code above, the animateWithDuration parameter represents the length of the transition in seconds. To make the animation run faster or slower, simply change this value.

When you’re debugging animations, it’s helpful to make your animation really long, like four or five seconds; this way you can catch little things that escape your notice when the animation runs at normal speed, such as clipping issues with the cell frame — or perhaps to grab a screenshot when writing a tutorial! :]

Next, you apply the CATransform3DIdentity transformation to bring your cell back to its original position. Finally, you animate the opacity of the cell back to 1.0; this will provide the “fade-in” effect you started earlier when you set the initial opacity to 0.8.

Note: Core Animation provides a block syntax where you declare the final condition of your animation sequence and how long it should take. The framework figures out the details for you. If you are new to blocks, see How To Use Blocks in iOS 5 (part 1 and part 2).

If you’re interested in the “why” and “how” of block syntax, Nils Hayat wrote a really great article which explains how to get from C declarators to Objective-C block syntax.

Build and run your application; scroll through the list and the cells of your table now rotate into place as they appear on the screen.

Rotation of card cell.

Not all properties support animation; the Core Animation Programming Guide provides a list of animatable properties for your reference.

Adding Some Limits to Your Transformation

Although the animation effect is neat, you’ll want to use it sparingly. If you’ve ever suffered through a presentation that overused sound effects or animation effects, then you know what effect overload feels like!

In your project, you only want the animation to run the first time the cell appears — as it scrolls in from the bottom. When you scroll back toward the top of the table, the cells should scroll without animating.

You need a way to keep track of which cards have already been displayed so they won’t be animated again. To do this, you’ll use a collection called a set.

Note: A set is an unordered collection of unique entries with no duplicates, while an array is an ordered collection that does allow duplicates. The Foundation collection classes NSSet and NSArray handle these two collections for you.

In your case, you just need a collection to hold the cells that have already been displayed; using an array leads to a more complicated implementation as you’d need to look up every card to see it it was already in the array, or you’d need to insert cards multiple times as the user scrolled up and down the table.

The general disadvantage of a set is that it doesn’t guarantee an order, but the ordering of your cells is already handled by the table datasource, so it isn’t an issue in this case.

Add the following code to the interface definition section of CTMainViewController.m:

@property (nonatomic, strong) NSMutableSet *shownIndexes;

Next, add the following code to viewDidLoad in CTMainViewController.m:

_shownIndexes = [NSMutableSet set];

Finally, modify tableView:willDisplayCell:forRowAtIndexPath: in CTMainViewController.m as follows:

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (![self.shownIndexes containsObject:indexPath]) {
        [self.shownIndexes addObject:indexPath];
 
        UIView *card = [(CTCardCell* )cell mainView];
 
        card.layer.transform = self.initialTransformation;
        card.layer.opacity = 0.8;
 
        [UIView animateWithDuration:0.4 animations:^{
            card.layer.transform = CATransform3DIdentity;
            card.layer.opacity = 1;
        }];        
    }
}

In the code above, instead of animating every cell each time it appears as you scroll up and down the table, you check to see if indexPath is contained in the set you defined earlier. If the indexPath is not in the set, this is the first time the cell has been displayed; therefore you transform the initial position, run the animation, then add the indexPath to the set. If it was already in the set, then you don’t need to do anything at all.

Build and run your project; scroll up and down the tableview and you’ll only see the cards animate the first time they appear on-screen.

Where To Go From Here?

Now that you’ve covered the basics of adding animation to cells, try changing the values of your transform to see what other effects you can achieve. Some suggestions are:

  1. Faster or slower animation
  2. Larger rotation angle
  3. Different offsets; if you change the rotation angle, you will likely need to change the offset to make the animation look right. What does the animation look like if you drop the offset entirely and use 0,0 for the parameters?
  4. Go nuts and create some whacked-out transforms.
  5. Advanced:Can you get the card to rotate along the horizontal or vertical axis? Can you make it look like it flips over completely?
  6. Advanced:Add an else clause to tableView:willDisplayCell:forRowAtIndexPath: and perform a different animation when cells are displayed a second time.

Crazy Rotations

Crazy rotations that you can (but maybe shouldn’t) apply to your cells. See if you can duplicate these!

A great exercise is to try and identify animations in your favorite apps. Even with the simple animation from this tutorial, there are countless variations you can produce on this basic theme. Animations can be a great addition to user actions, such as flipping a cell around when selected, or fading in or out when presenting or deleting a cell.)

If you want to see this technique in a slightly different context, check out UIView Tutorial for iOS: How To Use UIView Animation.

Again, a big thank you goes to Orta Therox for the original implementation of this code. Anything clever in the animation is from Orta, the sloppy parts are from myself.

If you have any questions about this table view animations tutorial or this technique in general, please join the forum discussion below!

Custom UITableViewCell Using Interface Builder


Hey everyone, welcome to my first of many screencasts coming in the next few weeks. Today I am going to show you how to layout a UITableViewCell in Interface Builder and have a UITableView populate with those type of cells. I am adopting a new structure for my screencasts which will be 5 or so mintues of keynote slides giving background info followed by 20 – 25 mintues of step by step development. The entire video will be directly below this paragraph, but scrolling down you will see a text based step by step of the whole tutorial as well. Hope you guys enjoy.

Skill Level MEDIUM

Here is a link to the screencast to watch. We are working on getting an embedded version in, but I figure this is basically just as functional. Have fun!

Custom UITableViewCell Screencast Video

Source Code

Available Here

Background Information

picture-1

picture-2

picture-3

picture-4

picture-5

picture-6

picture-7

picture-8

picture-9

picture-10

picture-11

Building The App

Step 1

picture-12

This step shouldn’t require any extra information.

Step 2

picture-13

datasourceconnection

Step 3

picture-14

In CustomTableCellTutorialViewController.m you must define the two required UITableViewDataSource methods. These methods will fill up the table view with data. For now we will put in dummy data just to make sure all of our connections are working.

– (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

{

return 10;

}

– (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

static NSString *CellIdentifier = @”Cell”;

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil){

cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

}

[cell setText:[NSString stringWithFormat:@”I am cell %d”, indexPath.row]];

return cell;

}

Step 4

picture-15

Here you will need to be in xCode and go to File -> New File…

Select Objective C Class and make sure it is a UITableViewCell subclass, depending on your version of the SDK selecting this will differ. Look around and you will find it, call it iCodeBlogCustomCell. With this done enter these IBOutlets in the iCodeBlogCustomCell.h file enter the following IBOutlets:

IBOutlet UILabel *articleName;
IBOutlet UILabel *authorName;
IBOutlet UILabel *date;

IBOutlet UIImageView *imageView;
IBOutlet UIView *viewForBackground;

Add the @property and synthesize them in the main.

Step 5

picture-16

This step does not require and code but does require a lot of work in Interface Builder. I highly recommend you watch the screencast to see the step by step procedure here. Essentially what I do is create a new View XIB file. Opening this, I delete the standard UIView in the XIB and drag a UITableViewCell from my library into my document window. I assign the UITableViewCell to be of type iCodeBlogCustomCell. With this done layout the interface with the proper elements and hook them up by right clicking on the UITableViewCell in the document window.

Step 6

picture-17

This is where the real magic is. We are going to return to CustomTableCellTutorialViewController.m and edit the UITableViewDataSource methods we implemented earlier. The code I use has me putting in 4 separate PNG files that I add to my project. You can find your own to put inside the cells. Make sure the UIImageView inside the cell is set for Aspect Fit so you don’t have to worry about resizing the images. The functions should be changed to be:

– (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 100;
}

– (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @”iCodeBlogCustomCell”;

iCodeBlogCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil){
NSLog(@”New Cell Made”);

NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@”iCodeBlogCustomCell” owner:nil options:nil];

for(id currentObject in topLevelObjects)
{
if([currentObject isKindOfClass:[iCodeBlogCustomCell class]])
{
cell = (iCodeBlogCustomCell *)currentObject;
break;
}
}
}

 

if(indexPath.row % 4 == 0)
{
[[cell authorName] setText:@”Collin Ruffenach”];
[[cell articleName] setText:@”Test Article 1″];
[[cell date] setText:@”May 5th, 2009″];
[[cell imageView] setImage:[UIImage imageNamed:@”1.png”]];
}

else if(indexPath.row % 4 == 1)
{
[[cell authorName] setText:@”Steve Jobs”];
[[cell articleName] setText:@”Why iPhone will rule the world”];
[[cell date] setText:@”May 5th, 2010″];
[[cell imageView] setImage:[UIImage imageNamed:@”2.png”]];
}

else if(indexPath.row % 4 == 2)
{
[[cell authorName] setText:@”The Woz”];
[[cell articleName] setText:@”Why I’m coming back to Apple”];
[[cell date] setText:@”May 5th, 2012″];
[[cell imageView] setImage:[UIImage imageNamed:@”3.png”]];
}

else if(indexPath.row % 4 == 3)

{
[[cell authorName] setText:@”Aaron Hillegass”];
[[cell articleName] setText:@”Cocoa: A Brief Introduction”];
[[cell date] setText:@”May 5th, 2004″];
[[cell imageView] setImage:[UIImage imageNamed:@”4.png”]];

}

return cell;
}