Git Product home page Git Product logo

mbcontactpicker's Introduction

MBContactPicker

Synopsis

MBContactPicker is an implementation of a contact picker that looks like the one in Apple mail for iOS7. This can be dropped into any project, using interface builder and a few simple lines of code, you can have this custom contact picker into your app in very little time.

I wrote this library to provide an update to the awesome THContactPicker that our company used in the past. My main goal when I created this library was to build something that behaved and felt like the native mail app's contact selector.

My secondary goal was to make using it extremely simple while still providing a high level of flexibility for projects that need it.

Animated GIF of Contact Picker

Usage

Example

Below you'll find a rudimentary example of a view controller using MBContactPicker.

#import "ViewController.h"
#import "ContactObject.h"
#import "MBContactPicker.h"

@interface ViewController () <MBContactPickerDataSource, MBContactPickerDelegate>

@property (nonatomic) NSArray *contacts;
@property (weak, nonatomic) IBOutlet MBContactPicker *contactPickerView;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *contactPickerViewHeightConstraint;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSArray *array = @[
                       @{@"Name":@"Contact 1", @"Title":@"CTO"},
                       @{@"Name":@"Contact 2", @"Title":@"CEO"}
                       ];

    NSMutableArray *contacts = [[NSMutableArray alloc] initWithCapacity:array.count];
    for (NSDictionary *contact in array)
    {
        ContactObject *model = [[ContactObject alloc] init];
        model.contactTitle = contact[@"Name"];
        model.contactSubtitle = contact[@"Title"];
        [contacts addObject:model];
    }
    self.contacts = contacts;

    self.contactPickerView.delegate = self;
    self.contactPickerView.datasource = self;
}

#pragma mark - MBContactPickerDataSource

// Use this method to give the contact picker the entire set of possible contacts.  Required.
- (NSArray *)contactModelsForContactPicker:(MBContactPicker*)contactPickerView
{
    return self.contacts;
}

// Use this method to pre-populate contacts in the picker view.  Optional.
- (NSArray *)selectedContactModelsForContactPicker:(MBContactPicker*)contactPickerView
{
    return @[];
}

#pragma mark - MBContactPickerDelegate

// Optional
- (void)contactCollectionView:(MBContactCollectionView*)contactCollectionView didSelectContact:(id<MBContactPickerModelProtocol>)model
{
    NSLog(@"Did Select: %@", model.contactTitle);
}

// Optional
- (void)contactCollectionView:(MBContactCollectionView*)contactCollectionView didAddContact:(id<MBContactPickerModelProtocol>)model
{
    NSLog(@"Did Add: %@", model.contactTitle);
}

// Optional
- (void)contactCollectionView:(MBContactCollectionView*)contactCollectionView didRemoveContact:(id<MBContactPickerModelProtocol>)model
{
    NSLog(@"Did Remove: %@", model.contactTitle);
}

// Optional
// This delegate method is called to allow the parent view to increase the size of
// the contact picker view to show the search table view
- (void)didShowFilteredContactsForContactPicker:(MBContactPicker*)contactPicker
{
    if (self.contactPickerViewHeightConstraint.constant <= contactPicker.currentContentHeight)
    {
        [UIView animateWithDuration:contactPicker.animationSpeed animations:^{
            CGRect pickerRectInWindow = [self.view convertRect:contactPicker.frame fromView:nil];
            CGFloat newHeight = self.view.window.bounds.size.height - pickerRectInWindow.origin.y - contactPicker.keyboardHeight;
            self.contactPickerViewHeightConstraint.constant = newHeight;
            [self.view layoutIfNeeded];
        }];
    }
}

// Optional
// This delegate method is called to allow the parent view to decrease the size of
// the contact picker view to hide the search table view
- (void)didHideFilteredContactsForContactPicker:(MBContactPicker*)contactPicker
{
    if (self.contactPickerViewHeightConstraint.constant > contactPicker.currentContentHeight)
    {
        [UIView animateWithDuration:contactPicker.animationSpeed animations:^{
            self.contactPickerViewHeightConstraint.constant = contactPicker.currentContentHeight;
            [self.view layoutIfNeeded];
        }];
    }
}

// Optional
// This delegate method is invoked to allow the parent to increase the size of the
// collectionview that shows which contacts have been selected. To increase or decrease
// the number of rows visible, change the maxVisibleRows property of the MBContactPicker
- (void)contactPicker:(MBContactPicker*)contactPicker didUpdateContentHeightTo:(CGFloat)newHeight
{
    self.contactPickerViewHeightConstraint.constant = newHeight;
    [UIView animateWithDuration:contactPicker.animationSpeed animations:^{
        [self.view layoutIfNeeded];
    }];
}

@end

Contact Objects

Contact objects used in the MBContactPickerDataSource and MBContactPickerDelegate protocols must adhere to the id<MBContactPickerModelProtocol> protocol. You can use MBContactModel, a basic implementation provided for convenience, or you can adjust your model class to adhere to the id<MBContactPickerModelProtocol> as shown below:

#import "MBContactModel.h"

@interface MyContactObject : NSObject <MBContactPickerModelProtocol>
...
// Required
@property (nonatomic, copy) NSString *contactTitle;
// Optional
@property (nonatomic, copy) NSString *contactSubtitle;
@property (nonatomic) UIImage *contactImage;
...
@end

Customization/Configuration

Change Color of the Selected Contacts

Thanks to Roman for this enhancement.

[[ContactCollectionViewCell appearance] setTintColor:[UIColor orangeColor]];

Orange Colored Contacts

Additional Appearance Settings

You can also set the color of the input text and the prompt.

[[MBContactCollectionViewPromptCell appearance] setTintColor:[UIColor redColor]];
[[MBContactCollectionViewEntryCell appearance] setTintColor:[UIColor purpleColor]];

Suppress completion of alread-selected contacts

By default, the picker shows you contacts which have already been added to the collection as options for completion, but discards them when you choose them, to prevent duplicate contacts in the collection. This is to be consistent with the behavior of Apple's Mail.app, but is arguably a deficient user experience. To suppress the already-chosen contacts from the completion list, you can set the following property:

self.contactPickerView.allowsCompletionOfSelectedContacts = NO;

Enabling/Disabling

The MBContactPicker control's enabledness can be toggled by setting it's -enabled property. MBContactCollectionView has two properties, -allowsSelection and -allowsTextInput, that control whether contact cells can be selected/deleted and searching/adding new contacts, respectively.

UIResponder

MBContactPicker and MBContactCollectionView both adhere to the UIResponder protocol. objc_msgSend becomeFirstResponder and resignFirstResponder to them with abandon!

Custom Prompts

Modify MBContactPicker.prompt to change the prompt value from the default of @"To:". Set MBContactPicker.showPrompt to NO in order to remove the prompt completely. For i18n support, the prompt text is customizable in Localizable.strings via the "MBContactPickerPrompt" key.

Add Contact Picker Programmatically

If you have to add MBContactPicker programmatically, you will need to either manually add the constraints (preferred) or set translatesAutoresizingMaskToConstraints to YES and then set the frame. See this comment for more information

Motivation

This project exists to because no other cocoapods existed that solved the problem of providing a robust contact selector that was easy to implement, used the latest iOS tools, and matched the appearance of iOS7's flat design.

Installation

Edit your PodFile to include the following line:

pod 'MBContactPicker'

Contributors

I am actively maintaining this along with the team at Citrrus, so please fork our project and make it better!

Special thanks to Matt Hupman for putting this library into a project and providing feedback and PRs to make it better.

License

This project uses the MIT license, so there are no strings attached.

mbcontactpicker's People

Contributors

andresilvagomez avatar brunchboy avatar firmach avatar keego avatar mattcbowman avatar mhupman avatar npahucki avatar zkirill avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mbcontactpicker's Issues

How to customize?

I would like to let the token field look like the attached one. But how to customize the background and add a line below the input field? Since the view automatically sets everything in it's setup method I can't do much in the Storyboard.
img_0463

Not working if picker is the only view

Kind of wired but seems that if there is only MBPickerView on the ViewController view it doesn't show up. After I add any other view then it start working as expected.

I don't know how to explain more, but this is what I observe trying to setup picker for the very first time on clean view controller view.

Selected Contacts

Hi there, is it possible to keep the selected effect on the contacts for when you have an already populated list? And also, having different color states for those contacts.

Thanks!

MBContactPicker should implement UITextInput protocol

On the iPhone 6/6+ when you have the landscape keyboard, clicking on a preexisting item then clicking the 'forward' and 'backwards' arrow will cause the application to crash with something like the following:

Application Specific Information:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
 reason: '-[MBContactCollectionView selectedTextRange]: 
unrecognized selector sent to instance 0x13c902c00'

By implementing the UITextInput protocol I can prevent it from crashing however you can't continue to go forward and back once you've selected an item in the picker.

Add Address Book Integration

It would be nice to be able to plug this in and have it automatically pull in the device's address book as an option. This would make the library even easier to use.

didEnterCustomText delegate method never called.

The method delegate method - (void)contactPicker:(MBContactPicker*)contactPicker didEnterCustomText:(NSString*)text never gets called on the delegate. I took a quick look at the code and it is not being used anywhere from what I can see. Was this a feature that was going to be added then was not?

From the context it look like this method was supposed to fire if I added some text that was not included in the list of contacts. Is that right?

Long contact names donโ€™t get trimmed to quite fit

With the ContactPicker embedded in a table cell, adding a contact whose name is too long to fit seems to almost work, but yields the following warning in the log:

2014-01-15 16:20:16.876 Cirrus[8237:70b] the behavior of the UICollectionViewFlowLayout is not defined because:
2014-01-15 16:20:16.876 Cirrus[8237:70b] the item width must be less that the width of the UICollectionView minus the section insets left and right values.
2014-01-15 16:20:16.876 Cirrus[8237:70b] Please check the values return by the delegate.
2014-01-15 16:20:17.181 Cirrus[8237:70b] Did Add: A list with an excessively long name

The attached image shows it seems a few pixels too wide; the rounded corners are cropped off, and the third dot of the ellipsis is just barely visible.

ios simulator screen shot jan 15 2014 16 25 05

Adding MBContactPicker to view programatically

Hey!
I've been using this tool on some projects and it's been really helpful, thank you Cittrus!
I am relatively new to objective-c and iOS development but I'm learning on the go.

On my new personal project one of my goals was to design the whole app programatically.
I've been trying to add an MBContactPicker to a view programatically (using initWithFrame: ) with no success.
On the example provided I see that it is placed using a storyboard, which is what I would like to avoid if possible.

Is there a special way to use this nice tool with only code?

Thanks!

Can the collection view use a gray tint color when disabled?

I know that there is an example of how to change the tint color in the read me, and that works fine if there is only one picker view in your layout, but we have a situation where we would like to use two, to pick different things, and each might be enabled or disabled, depending on user permissions, and we would like to give the user visual feedback before they tap on the picker as to whether it is enabled. Since changing the tint color is class-wide, rather than per instance of the picker, we cannot distinguish between them.

Would you consider having a way to set the tint on a per-Picker basis? Or even having the picker always use a gray tint when it is disabled?

Needs an example using a nib without AutoLayout switched ON.

I can see there's support for manually managing the frames but there isn't an example in the app doing this. It would be nice for newbies to be able to use it out of the box without having to figure out what needs to be done with the control when not using AutoLayout.

Multiple ContactPickers no longer working on iOS7.1

Setup 3 contact pickers in one view, each with an initial height of 30 and with a spacing of 0. When you try and click on them, you can only select the view that is furthest back in the view hierarchy (first one in the order in a Storyboard).

When I run it on an ios 7.0 simulator, this issue is not there. Switch to the 7.1 simulator and it doesn't work.

I'll start looking through the source to figure out what changed, however if anyone else has experienced or fixed this already, please let me know.

[question] How to allow non existent contacts?

I'd like to use this control to manage "tagging" in my application, but i dont know if its possible to allow "non-contacts" registries and how to allow registries that aren't in an array of "posibilites".

Btw very nice implementation! the best that i've seen.

Rename the rest of the project assets to MB*

@MattCBowman How do you feel about this? I think it would be nice to have consistency across the library. If I'm using MBContactPicker but I decide I need more control, it would be nice to just use MBContactCollectionView. It would also play nicely with auto-complete! โšก

Dynamic Search

Instead of providing a static array at the set up it would be more useful to return results depending on what the user typed in the field dynamically. (Would allow to fetch the contact from a web server for example or some kind of database.)

set Propmpt text color

hi

im try use this in my project but im not able to set diferent prompt text color kinda dont know what else try :(

my project is in swift

Unknown type name 'UIImage'

MBContactModel.h produces two "Unknown type name 'UIImage'" errors, likely because UIKit isn't imported in the file. This breaks the build :(

UICollectionViewFlowLayout warning

The first time a letter is typed, the following warning is printed to the console:

Logging only once for UICollectionViewFlowLayout cache mismatched frame
UICollectionViewFlowLayout has cached frame mismatch for index path <NSIndexPath: 0xc000000000200016> {length = 2, path = 0 - 1} - cached value: {{54, 0}, {311, 31}}; expected value: {{59, 0}, {50, 31}}
This is likely occurring because the flow layout subclass MBContactCollectionViewFlowLayout is modifying attributes returned by UICollectionViewFlowLayout without copying them

Making a copy of the attributes returned by layoutAttributesForElementsInRect and layoutAttributesForItemAtIndexPath solves the problem.

Pass MBContactPicker in MBContactPickerDelegate methods

I utilize three MBContactPickers (all share the same delegates) for a mail compose and there is currently no way to differentiate which contact picker caused the hideFilterContacts and updateViewHeightTo methods. That being said, for my own code I changed the following methods:

- (void)hideFilteredContacts;
- (void)updateViewHeightTo:(CGFloat)newHeight;

to

- (void)hideFilteredContactsForContactPicker:(MBContactPicker *)contactPicker;
- (void)updateViewHeightTo:(CGFloat)newHeigh forContactPicker:(MBContactPicker *)contactPicker;

Just wanted to see if there was a design choice to not pass the picker, since you did pass the contact picker for MBContactPickerDataSource. Let me know if you want the change I'll submit a pull request with the updated code/demo/readme.

UICollectionView crash during dealloc after rotation from landscape to portrait

I experienced a strange crash when the contact picker is deallocated when the parent view controller is destroyed, but only after rotating from landscape to portrait. I can reproduce the issue with the project example storyboard by creating a new initial view that pushes to the example VC. Rotate the device to landscape and back to portrait, pop the view and you get the following:

2014-03-13 22:20:57.143 MBContactPicker[14727:60b] *** Assertion failure in -[MBContactCollectionView dealloc], /SourceCache/UIKit_Sim/UIKit-2935.137/UICollectionView.m:654

Enabling zombie objects gives you a bit more information.
2014-03-13 22:23:28.671 MBContactPicker[14765:60b] *** -[MBContactCollectionViewFlowLayout respondsToSelector:]: message sent to deallocated instance 0x10925db80

Attempting to hold onto the layout object in a member variable results in the following giving a bit more information:
2014-03-13 22:27:25.632 MBContactPicker[14840:60b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UICollectionView (<MBContactCollectionView: 0x109857600; baseClass = UICollectionView; frame = (0 0; 320 31); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x109277bc0>; layer = <CALayer: 0x109273950>; contentOffset: {0, 0}> collection view layout: <MBContactCollectionViewFlowLayout: 0x109281390>) was deallocated while an update was in flight'

It appears some update to the layout is queued up after the dealloc is slated to run. A change that seemed to fix the problem and retain functionality is modifying the MBContactCollectionView forceRelayout function from:

[self performBatchUpdates:nil completion:nil];

to

MBContactCollectionViewFlowLayout *layout = MBContactCollectionViewFlowLayout*)self.collectionViewLayout;
[layout finalizeCollectionViewUpdates];

iOS 8 Support

Looks like iOS 8 support is broken. No keyboard on click (though it accepts support from external keyboards).

I'll take a look into it, but can't guarantee I'll get anything back.

Remove EntryCell Property from CollectionView

Keeping a handle to the entry cell itself is ๐Ÿ’ฉ. Keeping a pointer to just the current text value is good enough, we can apply that text whenever datasource is asked for the entry cell.

Long contact names and autorotation

I fully accept that this may be a failure on our part rather than an issue with the picker; there may be a method we should call upon auto-rotation to let the picker know about and deal with it, but I could not find any pointers to that in the read me file, so here is what find. When starting with a contact with a long name in portrait mode, the width is set up to fit nicely:

ios simulator screen shot jan 15 2014 17 32 25

However, upon rotating to landscape mode, the size stays small:

ios simulator screen shot jan 15 2014 17 32 37

Removing and re-adding the contact from the list does get it re-created with an appropriate width:

ios simulator screen shot jan 15 2014 17 33 53

However, at that point, rotating back to portrait leaves it too long to fit the view, and yields errors in the log:

2014-01-15 17:34:13.276 Cirrus[9748:70b] the behavior of the UICollectionViewFlowLayout is not defined because:
2014-01-15 17:34:13.276 Cirrus[9748:70b] the item width must be less that the width of the UICollectionView minus the section insets left and right values.
2014-01-15 17:34:13.277 Cirrus[9748:70b] Please check the values return by the delegate.
2014-01-15 17:34:28.022 Cirrus[9748:70b] Did Select: A list with an excessively long name

ios simulator screen shot jan 15 2014 17 34 34

Again, deleting and re-adding the contact causes it to have the correct width,

Figure out how to hide the prompt cell without providing a small width

This would probably involve centralizing all of our calculations so that when the prompt is hidden it's not used the calculate cell indexes.

The cleanest and most onerous solution would be to fix the flow layout so that sections do not force line breaks. If we did it this way, there would be no need for calculations and we could hard-code the prompt and entry cells to be the first index in their respective sections.

Rendering issue for selected contact upon view reappearance

Our picker is embedded in a table cell with a disclosure arrow which provides an alternate means of selecting contacts, for people who do not know anything about the available set to choose from (and therefore have no idea what to start typing) when they are first using the app.

The issue occurs if there is a contact selected in the picker when this alternate view is pushed to, for example:
ios simulator screen shot jan 15 2014 16 31 32

When the alternate selection view controller pops back to the table with the picker in it, even if no changes are made to the picker contents, the selected contact is rendered incorrectly, and remains that way until it is tapped on (or backspaced into) and then tapped away from:
ios simulator screen shot jan 15 2014 16 31 51

An even stranger result can be seen in a slightly different flow. Again, starting with a contact selected:
ios simulator screen shot jan 15 2014 16 42 51

This time the alternate controller is used to add another contact to the set that are being displayed by the picker. Now, the formerly-selected contact is drawn as normal but not selected, while both other contacts are drawn as opaque blue rectangles, again until each is tapped on and then off of:
ios simulator screen shot jan 15 2014 16 43 11

This happens even though we call [self.distributionListPicker resignFirstResponder]; in the tableView:didSelectRowAtIndexPath: handler which is pushing to the secondary view controller. If, however, we tap on a different table row, thereby taking over the first responder, then go back to the picker row, the contact shows as not selected, and pushing to and from the alternate view controller does not lead to any rendering issues.

Fails to compile with Xcode 7.1

use of undeclared identifier '_focused' in MBContactCollectionViewContactCell.m, line 87. I'm using the podfile for installation.

Regressions? Glitches/crashes when initial picker display includes contacts

This had been working before, but as of tonight (using the master branch), when our picker is set up to contain contacts during the initial display of the view which contains it, they do not display properly. I suspect this may be due to the new approach to handling an empty prompt. Indeed, a quick test confirms that these problems go away if I leave the prompt at its default value of To: but occur when setting it to the empty string.

With a single contact present, the picker appears empty. But clicking on the right edge of the picker places the insertion point to the right of where the invisible contact should be. Trying to click on that invisible contact places the insertion point at the beginning of the line (leftmost edge of the picker). And trying to backspace over the invisible contact results in a crash:

2014-01-14 21:09:54.690 Cirrus[17973:70b] -[MBContactCollectionViewEntryCell setFocused:]: unrecognized selector sent to instance 0x144654e0
2014-01-14 21:09:54.696 Cirrus[17973:70b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MBContactCollectionViewEntryCell setFocused:]: unrecognized selector sent to instance 0x144654e0'
*** First throw call stack:
(
    0   CoreFoundation                      0x030f55e4 __exceptionPreprocess + 180
    1   libobjc.A.dylib                     0x02e788b6 objc_exception_throw + 44
    2   CoreFoundation                      0x03192903 -[NSObject(NSObject) doesNotRecognizeSelector:] + 275
    3   CoreFoundation                      0x030e590b ___forwarding___ + 1019
    4   CoreFoundation                      0x030e54ee _CF_forwarding_prep_0 + 14
    5   Cirrus                              0x000a2d73 -[MBContactCollectionView collectionView:didSelectItemAtIndexPath:] + 195
    6   Cirrus                              0x000a4189 -[MBContactCollectionView textField:shouldChangeCharactersInRange:replacementString:] + 729
    7   UIKit                               0x0209a7b6 -[UITextField keyboardInputShouldDelete:] + 252
    8   UIKit                               0x01b88ba7 -[UIKeyboardImpl callShouldDeleteWithWordCountForRapidDelete:characterCountForRapidDelete:] + 691
    9   UIKit                               0x01b93985 -[UIKeyboardImpl deleteFromInputWithExecutionContext:] + 84
    10  UIKit                               0x01b90415 -[UIKeyboardImpl handleDeleteAsRepeat:executionContext:] + 130
    11  UIKit                               0x01b9ec1f -[UIKeyboardImpl handleKeyWithString:forKeyEvent:executionContext:] + 633
    12  UIKit                               0x01b9e766 -[UIKeyboardImpl handleKeyEvent:executionContext:] + 1808
    13  UIKit                               0x01b9dfbf __33-[UIKeyboardImpl handleKeyEvent:]_block_invoke + 51
    14  UIKit                               0x020c23c8 -[UIKeyboardTaskQueue continueExecutionOnMainThread] + 402
    15  UIKit                               0x020c2a6f -[UIKeyboardTaskQueue addTask:] + 144
    16  UIKit                               0x01b9df84 -[UIKeyboardImpl handleKeyEvent:] + 227
    17  UIKit                               0x019c740b -[UIApplication _handleKeyUIEvent:] + 330
    18  UIKit                               0x01b0dfa4 -[UIResponder(Internal) _handleKeyUIEvent:] + 59
    19  UIKit                               0x01b0dfa4 -[UIResponder(Internal) _handleKeyUIEvent:] + 59
    20  UIKit                               0x01b0dfa4 -[UIResponder(Internal) _handleKeyUIEvent:] + 59
    21  UIKit                               0x01b0dfa4 -[UIResponder(Internal) _handleKeyUIEvent:] + 59
    22  UIKit                               0x01b0dfa4 -[UIResponder(Internal) _handleKeyUIEvent:] + 59
    23  UIKit                               0x01b0dfa4 -[UIResponder(Internal) _handleKeyUIEvent:] + 59
    24  UIKit                               0x01b0dfa4 -[UIResponder(Internal) _handleKeyUIEvent:] + 59
    25  UIKit                               0x01b0dfa4 -[UIResponder(Internal) _handleKeyUIEvent:] + 59
    26  UIKit                               0x01b0dfa4 -[UIResponder(Internal) _handleKeyUIEvent:] + 59
    27  UIKit                               0x01b0dfa4 -[UIResponder(Internal) _handleKeyUIEvent:] + 59
    28  UIKit                               0x01b0dfa4 -[UIResponder(Internal) _handleKeyUIEvent:] + 59
    29  UIKit                               0x01b0dfa4 -[UIResponder(Internal) _handleKeyUIEvent:] + 59
    30  UIKit                               0x01b0dfa4 -[UIResponder(Internal) _handleKeyUIEvent:] + 59
    31  UIKit                               0x01b0dfa4 -[UIResponder(Internal) _handleKeyUIEvent:] + 59
    32  UIKit                               0x01b0dfa4 -[UIResponder(Internal) _handleKeyUIEvent:] + 59
    33  UIKit                               0x01b0dfa4 -[UIResponder(Internal) _handleKeyUIEvent:] + 59
    34  UIKit                               0x01b0dfa4 -[UIResponder(Internal) _handleKeyUIEvent:] + 59
    35  UIKit                               0x019c72ba -[UIApplication handleKeyUIEvent:] + 84
    36  UIKit                               0x019c725e -[UIApplication handleKeyHIDEvent:] + 458
    37  UIKit                               0x019af07c _UIApplicationHandleEventQueue + 2954
    38  CoreFoundation                      0x0307e83f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
    39  CoreFoundation                      0x0307e1cb __CFRunLoopDoSources0 + 235
    40  CoreFoundation                      0x0309b29e __CFRunLoopRun + 910
    41  CoreFoundation                      0x0309aac3 CFRunLoopRunSpecific + 467
    42  CoreFoundation                      0x0309a8db CFRunLoopRunInMode + 123
    43  GraphicsServices                    0x052299e2 GSEventRunModal + 192
    44  GraphicsServices                    0x05229809 GSEventRun + 104
    45  UIKit                               0x019b3d3b UIApplicationMain + 1225
    46  Cirrus                              0x0002daed main + 141
    47  libdyld.dylib                       0x03aed70d start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

With three initial contacts present, taking more than one line, the initial rendering of the view crashes as follows:

2014-01-14 21:03:36.411 Cirrus[17931:70b] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-2903.23/UITableView.m:1330
2014-01-14 21:03:36.417 Cirrus[17931:70b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 2.  The number of rows contained in an existing section after the update (0) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
*** First throw call stack:
(
    0   CoreFoundation                      0x030f55e4 __exceptionPreprocess + 180
    1   libobjc.A.dylib                     0x02e788b6 objc_exception_throw + 44
    2   CoreFoundation                      0x030f5448 +[NSException raise:format:arguments:] + 136
    3   Foundation                          0x00cf3fee -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 116
    4   UIKit                               0x01a8485d -[UITableView _endCellAnimationsWithContext:] + 13402
    5   UIKit                               0x01a93caa -[UITableView endUpdatesWithContext:] + 51
    6   UIKit                               0x01a93cd8 -[UITableView endUpdates] + 41
    7   Cirrus                              0x0001e7c9 -[ComposeViewController contactPicker:didUpdateContentHeightTo:] + 201
    8   Cirrus                              0x000aad0b -[MBContactPicker contactCollectionView:willChangeContentSizeTo:] + 475
    9   Cirrus                              0x000a37ae -[MBContactCollectionView collectionView:willChangeContentSizeTo:] + 270
    10  Cirrus                              0x000a7a9a -[MBContactCollectionViewFlowLayout finalizeCollectionViewUpdates] + 362
    11  UIKit                               0x01fdab3f __37-[UICollectionView _updateWithItems:]_block_invoke1214 + 1774
    12  UIKit                               0x01a16282 +[UIView(UIViewAnimationWithBlocks) _setupAnimationWithDuration:delay:view:options:factory:animations:start:animationStateGenerator:completion:] + 484
    13  UIKit                               0x01a16622 +[UIView(UIViewAnimationWithBlocks) animateWithDuration:delay:options:animations:completion:] + 108
    14  UIKit                               0x01fda16a -[UICollectionView _updateWithItems:] + 2097
    15  UIKit                               0x01fd5978 -[UICollectionView _endItemAnimations] + 14317
    16  UIKit                               0x01fdb4c4 -[UICollectionView _endUpdates] + 44
    17  UIKit                               0x01fdb66b -[UICollectionView performBatchUpdates:completion:] + 418
    18  Cirrus                              0x000a9aec -[MBContactPicker reloadData] + 812
    19  Cirrus                              0x000a8a83 -[MBContactPicker didMoveToWindow] + 339
    20  UIKit                               0x01a19077 -[UIView(Internal) _didMoveFromWindow:toWindow:] + 1689
    21  UIKit                               0x01a18cd7 -[UIView(Internal) _didMoveFromWindow:toWindow:] + 761
    22  UIKit                               0x01a18cd7 -[UIView(Internal) _didMoveFromWindow:toWindow:] + 761
    23  UIKit                               0x01a2a707 -[UIScrollView _didMoveFromWindow:toWindow:] + 65
    24  UIKit                               0x01a18cd7 -[UIView(Internal) _didMoveFromWindow:toWindow:] + 761
    25  UIKit                               0x01a18cd7 -[UIView(Internal) _didMoveFromWindow:toWindow:] + 761
    26  UIKit                               0x01a18cd7 -[UIView(Internal) _didMoveFromWindow:toWindow:] + 761
    27  UIKit                               0x01a2a707 -[UIScrollView _didMoveFromWindow:toWindow:] + 65
    28  UIKit                               0x01a10500 __45-[UIView(Hierarchy) _postMovedFromSuperview:]_block_invoke + 162
    29  Foundation                          0x00ec738c -[NSISEngine withBehaviors:performModifications:] + 107
    30  Foundation                          0x00d56f05 -[NSISEngine withAutomaticOptimizationDisabled:] + 48
    31  UIKit                               0x01a103bd -[UIView(Hierarchy) _postMovedFromSuperview:] + 313
    32  UIKit                               0x01a1b4c1 -[UIView(Internal) _addSubview:positioned:relativeTo:] + 1847
    33  UIKit                               0x01a0e9b1 -[UIView(Hierarchy) addSubview:] + 56
    34  UIKit                               0x019aae05 -[_UIParallaxDimmingView didMoveToWindow] + 129
    35  UIKit                               0x01a19077 -[UIView(Internal) _didMoveFromWindow:toWindow:] + 1689
    36  UIKit                               0x01a18cd7 -[UIView(Internal) _didMoveFromWindow:toWindow:] + 761
    37  UIKit                               0x01a10500 __45-[UIView(Hierarchy) _postMovedFromSuperview:]_block_invoke + 162
    38  Foundation                          0x00ec738c -[NSISEngine withBehaviors:performModifications:] + 107
    39  Foundation                          0x00d56f05 -[NSISEngine withAutomaticOptimizationDisabled:] + 48
    40  UIKit                               0x01a103bd -[UIView(Hierarchy) _postMovedFromSuperview:] + 313
    41  UIKit                               0x01a1b4c1 -[UIView(Internal) _addSubview:positioned:relativeTo:] + 1847
    42  UIKit                               0x01a0e9b1 -[UIView(Hierarchy) addSubview:] + 56
    43  UIKit                               0x019a7892 __53-[_UINavigationParallaxTransition animateTransition:]_block_invoke + 2001
    44  UIKit                               0x01a153ef +[UIView(Animation) performWithoutAnimation:] + 82
    45  UIKit                               0x019a6c96 -[_UINavigationParallaxTransition animateTransition:] + 1155
    46  UIKit                               0x01ae1e4e -[UINavigationController _startCustomTransition:] + 3446
    47  UIKit                               0x01aee0c7 -[UINavigationController _startDeferredTransitionIfNeeded:] + 688
    48  UIKit                               0x01aeecb9 -[UINavigationController __viewWillLayoutSubviews] + 57
    49  UIKit                               0x01c28181 -[UILayoutContainerView layoutSubviews] + 213
    50  UIKit                               0x01a1e267 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 355
    51  libobjc.A.dylib                     0x02e8a81f -[NSObject performSelector:withObject:] + 70
    52  QuartzCore                          0x0177a2ea -[CALayer layoutSublayers] + 148
    53  QuartzCore                          0x0176e0d4 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 380
    54  QuartzCore                          0x0176df40 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 26
    55  QuartzCore                          0x016d5ae6 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 294
    56  QuartzCore                          0x016d6e71 _ZN2CA11Transaction6commitEv + 393
    57  QuartzCore                          0x016d7544 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 92
    58  CoreFoundation                      0x030bd4ce __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 30
    59  CoreFoundation                      0x030bd41f __CFRunLoopDoObservers + 399
    60  CoreFoundation                      0x0309b344 __CFRunLoopRun + 1076
    61  CoreFoundation                      0x0309aac3 CFRunLoopRunSpecific + 467
    62  CoreFoundation                      0x0309a8db CFRunLoopRunInMode + 123
    63  GraphicsServices                    0x052299e2 GSEventRunModal + 192
    64  GraphicsServices                    0x05229809 GSEventRun + 104
    65  UIKit                               0x019b3d3b UIApplicationMain + 1225
    66  Cirrus                              0x0002daed main + 141
    67  libdyld.dylib                       0x03aed70d start + 1
    68  ???                                 0x00000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

Delegate method badly named and not present in protocol

The method -(void) contactcollectionView:(MBContactCollectionView *)contactCollectionView didEnterCustomContact:(NSString*)text can be called on the MBContactPickerDelegate. However, this method suffers from two problems:

  1. It's not named consistently with the other methods, it should be: -(void) contactCollectionView:(MBContactCollectionView *)contactCollectionView didEnterCustomContact:(NSString*)text
  2. This method is NOT declared in the MBContactPickerDelegate protocol, but there is a completely unused method called - (void)contactPicker:(MBContactPicker*)contactPicker didEnterCustomText:(NSString*)text;. I Imagine this this method was meant to have the same function as the misnamed method, but some how got overlooked.

Both super easy fixes. If I get a few moments later today I'll send a pull request.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.