Saturday, March 27, 2010

The next step: Creating two part selections

The next stage has some common characteristics.  They have a set of dialogs where two selections are made, and then actions take place.

Case 1: Load words from another set.

  • Select a set of word lists:
    • Select all, and Clear all are there to help.  This is multiselect.
  • Display all words in the selected lists.
  • Select words from the displayed words.
    • Select All, and Clear all are there to help.  This is multiselect.
  • Select OK, to merge all selected words into current list.

Case 2: Merge words in my set to other lists

  • Select words in my current set for merging
  • Select a set of words
  • Add my words to each set selected.

Case 3: Edit words


  • Display all words currently in the list.
  • Allow deletion of words, modeled on Mail (multi select)
  • Allow adding new words to the set
    • This will be based on the current add word method.
    • It will allow selecting words, or typing them in.
    In the above text, one common theme is selecting things from a list.  The first thing to be done is to extend my table control to allow multi-select, preferably from multiple methods.  In addition I need to be able to have a flow through various selection types with minimal custom code for each flow.


    This is a major enhancement, once this is done well most of the rest of the application will be trivial.  In addition there are many other applications I have in mind which can use this same functionality.  Having this in a library will greatly accelerate the development of those applications

    Friday, March 26, 2010

    Fetched List Controller, sections and categories

    I was creating a fetched list controller, and my predicate did not sort by the category.  I found that I got a lot of errors in my log file when I fetched data.  In particular I was using a 'nil' predicate to fetch all data.

    2010-03-27 00:12:50.173 SightWordsUnlimited[18877:207] NSFetchedResultsController ERROR: object Fry First 20009 returned nil value for section name key path 'Category'. Object will be placed in unnamed section
    2010-03-27 00:12:50.174 SightWordsUnlimited[18877:207] NSFetchedResultsController ERROR: object Hi returned nil value for section name key path 'Category'. Object will be placed in unnamed section
    2010-03-27 00:12:50.175 SightWordsUnlimited[18877:207] NSFetchedResultsController ERROR: object Test99 returned nil value for section name key path 'Category'. Object will be placed in unnamed section
    2010-03-27 00:12:50.176 SightWordsUnlimited[18877:207] NSFetchedResultsController ERROR: The fetched object at index 6 has an out of order section name '. Objects must be sorted by section name'



    In addition when I went to another dialog, and changed the managed context the fetched object controller was using, the mismatched sections caused a 'Bad Access Exception'.
    The error I received was:


    *** -[_NSDefaultSectionInfo sectionOffset]: message sent to deallocated instance 0x3b41d10




    I put a quick fix in, in my JLFetchedControllerSource I modified the fetch so that if a section field is present, sort by that prior to sorting by the key.  I think the code is a little ugly but it seems to work.




    NSSortDescriptor *catSort=nil;
    if (self.sectionField!=nil)
    catSort=[[NSSortDescriptor alloc] initWithKey:self.sectionField ascending:YES];
    NSSortDescriptor *keysortDesc=[[NSSortDescriptor alloc] initWithKey:sortField ascending:YES];
    NSSortDescriptor *first=keysortDesc;
    NSSortDescriptor *second=nil;
    if (catSort!=nil)
    {
    first=catSort;
    second=keysortDesc;
    }
    NSArray *sortDescs=[[NSArray alloc] initWithObjects:first,second,nil];

    The list edit form

    The next form is the core of managing my lists. It dispays the name of the list and the category and allows direct editing of these features. Categories are intended to be use for filtering and sorting so that a larger number of lists can be used.

    Next a series of large friendly buttons allow transfer to other areas:
    Edit list
    This brings up the current contents of the list the user can then delete words in bulk or add new words.

    Merge from other lists
    This will allow the user to select one or more other lists. After selecting these lists a dialog will be brought up showing the combined set of words in those lists. The user can then select which words they want. Select and clear all will be available.

    Merge to list
    This will bring up a dialog that allows the user to select words to merge. Once done a dialog will be brought up allowing the user to select lists to send these words to.

    A common factor in these dialogs is the selection of lists.  The core feature of this application vs other sight word applications is intended to be the easy manipulation of lists.

    Below is the initial cut of the dialog.  After I get the application working I intend to do an 'aesthetic' run-through to add landscape capability and to make it look prettier.  This is the primary reason I didn't do this as a table, I think it is easier to implement as a standard dialog, and it offers more freedom to make modifications.



    Now this screenshot isn't the most attractive dialog, but it includes the essential information.  

    I do intend to clean it up prior to release, and to also make another .nib file that contains a landscape version of the dialog.












    I also refactored the sight word display, since I am having it initiated from two locations, I made a static method on the SightWordDisplay class that shows the dialog.   I also intend to clean up this some more, I'm not satisfied with my 'singleton' sight word state.

    Thursday, March 25, 2010

    Continuing with development

    The last major refactoring is done, now the application is still a little creaky.  I want to restructure the application so that instead of having a clunky dialog for editing lists, it has a simpler structure

    I'm planning to replace the current add list dialog with an 'edit list dialog'.  This will be a custom dialog that allows you to edit the list name, the category, and also to go to several list selection dialogs:
    1) Merge Lists -- Select one or more lists to merge into the current list.
    2) Add/Edit words -- A single dialog that allows you to see the current words in the list, and depending on buttons you choose, either delete words, or add words (selecting from the current set).   This will support multiple selection types:  When adding words it will bring up a filter selection that selects from all words.
    3) You can also go the Display Words Dialog and display the word list as if you had selected it from the main screen.

    This will not be a table driven dialog, but will instead be a custom form which supports both portrait and landscape modes.   

    Wednesday, March 24, 2010

    Refactoring Suggested Items: Standard Callback Handler

    The standard callback handler


    One of the other items that I created is a standard callback handler. This is responsible for taking standard actions from the table, and converting them into semantic actions on my data model.


    The interface


    The interface is pretty standard, note that JLCallbackHandler implements the UITableViewDelegate protocol.  This will have a reference to a JLTableController object, and know how to call it when actions occur.  In addition it has a reference to the JLTableSource so that it can retrieve selected items and act upon them.


    //  JLStandardCallbackHandler.h
    //  JLFoundation
    //
    //  Created by Jon Lundy on 3/20/10.
    //

    #import "JLTableControl.h"
    #import "JLStandardCallbackHandler.h"

    @interface JLStandardCallbackHandler : NSObject {
    id<JLTableController> tableController;
    id<JLTableSource> source;
    }

    @end

    The implementation


    The implementation is very simple, but it helps abstract out these tasks and enables more complicated behavior in the future.  It takes the given index path, asks the source for the data at that path, and then dispatches to the proper callback in the table controller.



    //
    //  JLStandardCallbackHandler.m
    //  JLFoundation
    //
    //  Created by Jon Lundy on 3/20/10.
    //

    #import "JLStandardCallbackHandler.h"


    @implementation JLStandardCallbackHandler
    @synthesize tableController;
    @synthesize source;
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
    {
    id itemAtIndex=[source objectAtIndexPath:indexPath];
    [tableController rowSelected:itemAtIndex];
    }

    - (void)tableView: (UITableView *)tableView
    accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
    {
    id itemAtIndex=[source objectAtIndexPath:indexPath];
    [tableController acessorySelected:itemAtIndex];

    }



    @end

    Refactoring Suggested Items: The template

    The container template


    The first template is a small set of code that has some utility routines to create two types of tables, and which contains the other strategies.  It is currently a little clunky, a future refactoring will try to make the API cleaner


    The header file



    /
    //  JLTableContainer.h
    //  JLFoundation
    //
    //  Created by Jon Lundy on 3/20/10.
    //

    #import
    #import

    @interface JLTableContainer : NSObject
    {
    NSObject<JLCallbackHandler> *callbackHandler;
    NSObject<JLTableSource> *tableSource;
    NSObject<JLCellProvider> *cellProvider;
    NSObject<JLTableController> *tableController;
    UITableView *table;
    }
    @property (retain,nonatomic) NSObject *callbackHandler;
    @property (retain,nonatomic) NSObject *tableSource;
    @property (retain,nonatomic) NSObject *cellProvider;
    @property (retain,nonatomic) NSObject *tableController;
    @property (retain,nonatomic) UITableView *table;

    // Create a set of controllers for a simple fetch controller that
    // sorts on a given sort with a key displayed for the value of hat field.
    // the tableController is passed in.
    + (JLTableContainer*) createFetchControlledTable:(UITableView *)table
    forEntity:(NSString *)entityName forSimpleKey:(NSString *)keyName
    inContext:(NSManagedObjectContext *) context
    createSectionsBy:(NSString *) sectionName
    controlledBy:(NSObject<JLTableController>*) controller;
    + (JLTableContainer*) createFetchControlledTable:(UITableView *)table
      forEntity:(NSString *)entityName forSimpleKey:(NSString *)keyName
      inContext:(NSManagedObjectContext *) context
    createSectionsBy:(NSString *) sectionName
    controlledBy:(NSObject<JLTableController>*) controller
    accessoryDisplay:(UITableViewCellAccessoryType) accessoryType;

    // If this source supports searching via a predicate, then update the
    // predicate with that call.  Note that if the source DOES NOT
    // restrict by predicate, then this call will do nothing.

    - (void) updatePredicate:(NSPredicate *) predicate;
    // Connect the objects to each other to form the delegation chain of the
    // template object.
    - (void) connectObjects;
    @end




    The source file



    //
    //  JLTableContainer.m
    //  JLFoundation
    //
    //  Created by Jon Lundy on 3/20/10.
    //  Copyright 2010 __MyCompanyName__. All rights reserved.
    //

    #import "JLTableContainer.h"


    @implementation JLTableContainer

    @synthesize callbackHandler;
    @synthesize tableSource;
    @synthesize cellProvider;
    @synthesize tableController;
    @synthesize table;
    + (JLTableContainer*) createFetchControlledTable:(UITableView *)table
      forEntity:(NSString *)entityName forSimpleKey:(NSString *)keyName
      inContext:(NSManagedObjectContext *) context
    createSectionsBy:(NSString *) sectionName
    controlledBy:(NSObject<JLTableController>*) controller
    {
    return [JLTableContainer createFetchControlledTable:table forEntity:entityName forSimpleKey:keyName inContext:context 
    createSectionsBy:sectionName controlledBy:controller
    accessoryDisplay:UITableViewCellAccessoryNone];
    }


    + (JLTableContainer*) createFetchControlledTable:(UITableView *)table
      forEntity:(NSString *)entityName forSimpleKey:(NSString *)keyName
      inContext:(NSManagedObjectContext *) context
    createSectionsBy:(NSString *) sectionName
    controlledBy:(NSObject<JLTableController>*) controller
    accessoryDisplay:(UITableViewCellAccessoryType) accessoryType

    {
    JLTableContainer *returnValue=[[JLTableContainer alloc]init];
    SimpleDescriptionCellProvider *simpleCellProvider=[[SimpleDescriptionCellProvider alloc] init];
    simpleCellProvider.accessoryType=accessoryType;
    returnValue.table=table;
    JLFetchedControllerSource *source=[[JLFetchedControllerSource alloc] init];
    source.sortField=keyName;
    source.managedEntityName=entityName;
    source.sectionField=sectionName;
    source.fetchContext=context;
    JLStandardCallbackHandler *callHandler=[[JLStandardCallbackHandler alloc]init];
    returnValue.tableController=controller;
    returnValue.cellProvider=simpleCellProvider;
    returnValue.tableSource=source;
    returnValue.callbackHandler=callHandler;
    [returnValue connectObjects];
    return [returnValue autorelease];
    }

    - (void) connectObjects
    {
    table.delegate=callbackHandler;
    table.dataSource=tableSource;
    if (callbackHandler!=nil)
    {
    callbackHandler.tableController=tableController;
    callbackHandler.source=tableSource;
    }
    if (tableSource!=nil)
    {
    tableSource.cellProvider=cellProvider;
    tableSource.table=table;
    }
    if (cellProvider!=nil)
    {
    }
    if (tableController!=nil)
    {

    }
    }

    - (void) updatePredicate:(NSPredicate *) predicate
    {
    // Check to make source our source is not null and implements the
    // requested protocol.
    if (self.tableSource!=nil)
    {
    if (  [tableSource conformsToProtocol:@protocol(RestrictWithPredicate)]  ) {
    id<RestrictWithPredicate> restricted=(id<RestrictWithPredicate>) self.tableSource;
    [restricted updatePredicate:predicate];
    }
    }
    }
    - (void) dealloc
    {
    [callbackHandler release];
    [tableSource release];
    [cellProvider release];
    [tableController release];
    [super dealloc];
    }

    @end

    Points of Interest

    Static builder methods

    The first thing to note is that there is a rather large public static method that lets you construct a fetched result controller which has standard behavior.  This API is clumsy, but it should work.  
    In addition I defined an updatePredicate utility method. This method will first verify that the table source
    corresponds to the new protocol, RestrictWithPredicate.  If it does, then it will update the predicate with
    the passed in data.  This allows me to have various optional functions that can be used by manipulating the container object instead of having a lot of casting in the middle.

    My goal is to restructure this API a little bit so that it is cleaner, and more modular to use.
    if (self.tableSource!=nil)
    {
    if (  [tableSource conformsToProtocol:@protocol(RestrictWithPredicate)]  ) {
    id<RestrictWithPredicate> restricted=(id<RestrictWithPredicate>) self.tableSource;
    [restricted updatePredicate:predicate];
    }
    }

    Restructuring calls


    The method connectObjects is used to restructure the various strategies.  Each strategy knows about other strategies in the suite.  This call enables you to change strategies, and then make a single call to connect everything back up again.

    Usage


    Now that I have these methods in place I was able to quickly restructure my main sight word list to instead of selecting all sight words into memory, using a NSFetchedResultsController.  I disconnected the .nib file from the File Owner in Interface Builder, and added the following code in viewDidLoad.  

    self.container=[JLTableContainer createFetchControlledTable:self.tableView
      forEntity:@"WordList"
      forSimpleKey:@"ListName"
      inContext:currentState.control .managedObjectContext
      createSectionsBy:@"Category" 
      controlledBy:self
      accessoryDisplay:UITableViewCellAccessoryDetailDisclosureButton
    ];
    [self.container updatePredicate:nil];

    I then removed all of the standard table callbacks, and implemented these two callbacks:

    Selecting a row

    - (void) rowSelected:(id) selectedObject
    {
    WordList *list=(WordList*)selectedObject;
    SightWordDisplay *display=[[SightWordDisplay alloc] initWithNibName:@"SightWordDisplay" bundle:nil];


    SightWordProvider *provider=[[SightWordProvider alloc] initWords:list];
    display.provider = provider;
    // display.title=provider.wordList.ListName;
    // Copied from Beginning IPhone Development. Not sure I like the global reference.
    [self.navigationController  pushViewController:display animated:YES];
    [display release];
    }

    Selecting an accessory



    - (void) acessorySelected:(id) selectedObject
    {
    ListEditor *editor=[[ListEditor alloc ] initWithNibName:@"ListEditor" bundle:nil];
    editor.wordlist=(WordList*)selectedObject;
    SightWordsUnlimitedAppDelegate *delegate =
    [[UIApplication sharedApplication] delegate];

    [delegate.rootController pushViewController:editor animated:YES];
    [editor.tableView reloadData];
    [editor release];

    }

    The goal is to remove the table management logic from my view controller, and let it concentrate on business logic.

    Note that I broke the ability to delete word lists when I did this.  I'm going to have to go put it back in.  The nice thing about a shared class is that when I add this functionality back in, it will be available to any class using the library.



    Refactoring Suggested Items. List Logic

    The next goal is a big one, refactor the display of items from the DataFetchController into a separate class. The reasons behind this refactoring are:

    1. This is a common task which needs to be performed frequently. Anytime you find yourself pasting in a set of similar methods, you really should consider refactoring that.
    2. This is a more object oriented approach, and favors composition over inheritance. This allows for smaller sets of objects to work together. Every sample class I see usually has the view controller implementing the UITableViewDelegate and the UITableViewDataSource. I want to factor these out into a set of common classes that can work together.
    3. Currently I'm targeting IPhone OS 3.0 or greater since I'm using core data. At some point I might want to target earlier versions of the OS. In this case I would need to work with arrays instead of core data objects. In addition I can switch between using relationship properties, and queries with minimal effort.
    4. As I learn more about the framework, additional capabilities can be backfilled into earlier projects by changing the base classes. [Note that this does add additional testing time when I make changes].

    The design:


    The top layer of this will be a container class that encapsulates a set of strategies. This is basically a template design pattern with individual strategies for certain tasks.    These strategies will be 4 protocols which define the behavior characteristics. The first version of implementing these protocols will be simple. In addition various implementations will have different capabilities rhey might support. Instead of implementing these in every class we will define additional protocols that define this behavior


    JLTableContainer


    This is the template object that contains the other sources.  It will contain utility routines that enable you to quickly create common tables, and configure their behavior.  The initial version will be rather thin, just the existing fetched controller behavior, but additional functionality will be added as the libraries mature.

    JLTableSource

    This implements the UITableViewDataSource protocol and defines methods that determine which data items are available. This will probably have very few methods other than properties for the other members of the hierarchy.

    Initial subclasses will be:
    • JLFetchedControllerSource -- Implements a wrapper around a fetch controller.
    • JLSetArrayController -- Implements a wrapper around a set or array.

    JLCellProvider

    This is a very specific class that given a given index path provides the cell for this index.
    Initial subclasses will include:

    • JLKeyValueCellProvider -- Provides a value based on a key from the object.
    • JLDescriptionProvider -- Uses the standard NSObject description method as text.
    • JLSelectionProvider -- Provides a checkbox and monitors it's behavior. This will also implement the callbacks as well.

    JLCallbackHandler

    This is a wrapper around the common actions, such as selecting an accessor or cell, and then performing an action. It will encapsulate the association of the action with a specific object, and then call the JLTableController to actually do the action.

    Initial subclasses will include:
    • JLStandardCallbacks -- Delegate the standard callbacks to the designated list.
    • JLSelectionProvider -- Encapsulate a class that tracks selections/deselection in combination with the cell provider.

    JLTableController

    This is the domain class that acts upon choices. It implements the UITableViewDelegate It provides methods that respond to the choices the user made, and potentially provides methods for controlling a navigation bar or control bar, or a search bar.
    Initial versions:
    • JLSelectionProvider -- A base class for doing selections.
    • JLTableSearcher -- Searching through a list for values.


    Tuesday, March 23, 2010

    Categories in Static Library

    I'm using categories to expand a few classes in my static library, I have a category on UIView that creates an image of the view, and a category on NSPredicate that generates a predicate for looking for words starting with a search string.

    This worked fine on the simulator, but CRASHED the iPhone.  I had developed for a week simulator only, and was dismayed to find my iPhone not working.

    After some digging I found a few posts on stack overflow that referenced using the -all_load flag, I tried that and it did not work.  Then I noticed that I had another category that DID work, an expansion of set.  The difference was that the expansion of NSSet did not have it's own files.

    I then created a dummy class, and put all my categories into that class, after doing this my application worked fine, even though I didn't actually instantiate the class anywhere.

    Sample include file (note in one case I included the category interface from another include, in the other I just cut & pasted it in:
    //

    //  CategoryDummy.h
    //  JLFoundation
    //
    //  Created by Jon Lundy on 3/23/10.
    //

    #import
    #import "UIView_Helper.h"
    #import "JLPredicateHelper_NSPredicate.h"

    @interface UIView(AnimationHelper)

    //
    // Create a image of the current view, and give it a frame 
    // identical to the current location.  The image view is autoreleased.
    // 

    - (UIImageView *)createImageOfView;

    @end

    // A bug seems to cause categories to NOT work if they aren't in a file that
    // is explicitly included.


    @interface CategoryDummy : NSObject {

    }

    @end


    And for the source file:

    //
    //  CategoryDummy.m
    //  JLFoundation
    //
    //  Created by Jon Lundy on 3/23/10.
    //

    #import "CategoryDummy.h"

    #import


    @implementation CategoryDummy

    @end




    @implementation NSPredicate(JLPredicateHelper)


    + (NSPredicate *) createSearchPredicate:(NSString*) fieldToSearchOn startingText:(NSString*) startingText
    {
    NSString *searchString=[startingText stringByAppendingString:@"*"];
    NSString *predicateFormat=[[NSString alloc] initWithFormat:@"%@ like[cd] %%@",fieldToSearchOn];
    NSPredicate *predicate=[NSPredicate predicateWithFormat:predicateFormat,searchString];
    [predicateFormat release];
    return predicate ;
    }
    @end

    @implementation UIView(AnimationHelper)



    //
    // Create a image of the current view, and give it a frame 
    // identical to the current location.  The image view is autoreleased.
    // 
    - (UIImageView *)createImageOfView
    {
    // First getting a view of the current image.
    UIGraphicsBeginImageContext(self.bounds.size);
    [self.layer renderInContext:UIGraphicsGetCurrentContext()];
    // this function returns an autoreleased image.
    UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    UIImageView *imageView=[[UIImageView alloc] initWithImage :viewImage];
    imageView.frame=self.frame;
    return [imageView autorelease];
    }
    @end


    Where JLPredicateHelper is:


    //
    //  JLPredicateHelper_NSPredicate.h
    //  JLFoundation
    //
    //  Created by Jon Lundy on 3/19/10.


    @interface NSPredicate(JLPredicateHelper) 

    // This routine will create a predicate that searches a table on a certain field for any values
    // that start with the same text (case insensitive).  The predicate is returned autorelease.
    + (NSPredicate *) createSearchPredicate:(NSString*) fieldToSearchOn startingText:(NSString*) startingText;

    @end

    This was all I had to do to get my categories working on the iPhone.  I was even able to remove the -all_load compiler flag.

    Friday, March 19, 2010

    Snow Leopard

    I put off purchasing Snow Leopard until last week, thinking that the Xcode for Leopard was sufficient, I finally purchased it so that I could do IPad development.  I quickly learned that I was wrong, the static analysis capabilities of the xcode version 3.2.1 was wonderful, and quickly found several memory leaks that would have taken hours for me to find on my own.

    If you are on the fence about upgrading, it is definitely worth it to have the newer version.

    Saturday, March 13, 2010

    Refactoring Suggested items. Moving keyboard helper out.

    Moving keyboard helper out


    The next segment of code that I currently have in place inside the file is changing the size of a view based on the keyboard appearing or disappearing.  I created a new class KeyboardHelper which is used to do this.  It registers for keyboard notifications and changes the view size as the keyboard appears or disappears (disappears is not currently well tested).

    When it is deallocated it will unregister the notifications to help ensure that notifications are not sent.

    A future enhancement might be to see if the current view is REALLY active prior to doing frame changes.


    header file



    A simple header file, only one public method, which initializes this with a view.


    // The keyboard helper is an object that when given a view will
    // resize that view when the keyboard appears or disappears.   
    // The dealloc of this will unregister the notification.
    @interface KeyboardHelper : NSObject {

    @private
    UIView *view;
    CGRect originalSize;

    }
    @property (nonatomic,retain) UIView *view;
    @property (nonatomic) CGRect originalSize;


    - (id) initWithView:(UIView*) viewToUse;
    @end


    Source file





    The source is also fairly simple
    @implementation KeyboardHelper
    @synthesize view;
    @synthesize originalSize;

    - (id) initWithView:(UIView*) viewToUse
    {
    self.view=viewToUse;

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardAppearing:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDisappearing:) name:UIKeyboardWillHideNotification object:nil];
    return self;
    }

    - (void)keyboardDisappearing:(NSNotification *)notification {
    view.frame=originalSize;
    }

    - (void)keyboardAppearing:(NSNotification *)notification {
    NSDictionary *keys=[notification  userInfo];
    NSValue *value=[keys objectForKey:UIKeyboardBoundsUserInfoKey];
    CGRect bounds;
    [value getValue:&bounds];
    CGRect myFrame=[self.view frame];
    originalSize=myFrame;
    view.frame=CGRectMake(myFrame.origin.x,myFrame.origin.y,myFrame.size.width,
    myFrame.size.height-bounds.size.height);
    }

    - (void) dealloc
    {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [super dealloc];

    }



    Usage




    And to use it, do the following:
    a) Create a property for the keyboard monitor, the standard (retain,nonatomic).
    b) Add the following in viewDidLoad
    self.keyboardHelper=[[KeyboardHelper alloc] initWithView:self.suggestions];

    where suggestions is the view you want to resize.

    To see the changes for this refactoring, check out