Embedded Table View in UIView container - ios

So here's the case:
I wish to fill the prototype cells with the names of the friends selected in the UIPickerView over there. I have programatically filled the picker with the correct data, and set its properties using the delegate functions.
The "New Game Friends View" you see here has its own viewcontroller subclass, as has the table view, which I attempt to embed into a UIView on the "New Game Friends View".
I have in many ways tried to add data to the prototype cells, but with no luck. Here's my current addBtnClicked function:
- (IBAction)addBtnClicked:(id)sender {
WHGFriendTableViewController* tabView = (WHGFriendTableViewController*) [[self childViewControllers] objectAtIndex:0];
NSInteger row = [friendPicker selectedRowInComponent:0];
[[tabView selectedFriends] addObject:[[self friendList] objectAtIndex:row]];
}
This pretty much crashes my app. Whenever I hit the Add Friend button, the iPhone sends an abort signal, and gives back this message:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIViewController
selectedFriends]: unrecognized selector sent to instance 0x978d530'
Any help with this problem is very appreciated. Thanks in advance!

Do you have a property called selectedFriends on your New Friends view controller?
If the answer is yes try:
- (IBAction)addBtnClicked:(id)sender {
WHGFriendTableViewController* tabView = (WHGFriendTableViewController*) [[self childViewControllers] objectAtIndex:0];
NSInteger row = [friendPicker selectedRowInComponent:0];
[[self selectedFriends] addObject:[[self friendList] objectAtIndex:row]];
}
If selectedFriends is a property of WHGFriendTableViewController, you should create a public method that adds a friend to the Mutable Array and call it from addBtnClicked IBAction.

Related

selector and PerformSelector

I have a UITableView with several sections. Each section contains a different set of data: phoneNumbers, addresses....
For each of those sets I have a model: PhoneNumber, Address. They're completely different but have some methods in common.
In my UITableView I have an array containing those models/classnames:
NSMutableArray *classNames;
In the viewDidLoad of my UITableView I do some initializations for all those sections:
//section 1: PhoneNumbers
phoneNumbers = [PhoneNumbers getAllIDs];
if (phoneNumbers && (phoneNumbers.count >0)) {
[classNames addObject:#"PhoneNumber"];
[dataIDs addObject:phoneNumbers];
}
I do this again for all the other sections/models:
//section 2: Addresses
addresses = [Address getAllIDs];
if (addresses && (addresses.count >0)) {
[classNames addObject:#"Address"];
[dataIDs addObject:addresses];
}
// section 3: .....
Ok so far for initialization. This looks good and works fine.
Then later on in my cellForRowAtIndexPath I'm retrieving the actual data via those ID's
NSInteger section = [indexPath section];
NSInteger row = [indexPath row];
NSArray *rows = [dataIDs objectAtIndex:section];
NSNumber *recordID = [rows objectAtIndex:row];
I then figure out in what class we have to fetch the actual data:
Class displayedDataClass = NSClassFromString ([classNames objectAtIndex:section]);
and get the data to populate the cell.
id displayedRecord = [[displayedDataClass alloc] init];
[displayedRecord getByID:recordID];
I can then set the labels in my cell using :
[cell.someLabel setText:[displayRecord fullDesciption]];
So far so good, I succesfully abstracted everything, the cellForRowAtIndexPathdoesn't need to know where things come from, as long as those classes respond to the methods for retrieving the data for the labels (in the case above fullDesciption)
Now I need an actionButton in every Cell performing some kind of action
To make sure I understood the concept of selectors and performSelection I just quick and dirty made in action in my TableView Class:
- (void) buttonTarget {
NSLog (#"yes");
}
And in my cellForRowAtIndexPath method created a button with the following target:
button addTarget:self action:#selector(buttonTarget) forControlEvents:UIControlEventTouchUpInside];
Ok, so far so good, things work like expected. But this is not what I really wanted. The action should not be performed here, but in the actual class (PhoneNumber,Address,...).
To keep things clean I made a model Action, containing the icon for the button, a description and the selector:
#interface Action : NSObject
#property (nonatomic, strong) NSString *description;
#property (nonatomic, strong) UIImage *icon;
#property (nonatomic ) SEL selector;
#end
In my PhoneNumber class (and similar classes) the action is set to the correct selector:
Action *phoneAction = [[Action alloc] init];
phoneAction.description = NSLocalizedString(#"Call", #"Call button description");
phoneAction.icon = [UIImage imageNamed:#"phone"];
phoneAction.selector = #selector(callPhone);
Of course callPhone is implemented in the PhoneNumber class.
In my TableView I then get the actions for that cell
action = [displayedRecord action];
I then try to use that selector in my Button:
[button addTarget:displayedRecord action:[action selector] forControlEvents:UIControlEventTouchUpInside];
But here things go wrong: we never arrive in that method and I get the following error:
[UIDeviceWhiteColor callPhone]: unrecognized selector sent to instance
0x874af90 2013-12-29 23:23:03.629 thinx[27242:907] * Terminating app
due to uncaught exception 'NSInvalidArgumentException', reason:
'-[UIDeviceWhiteColor callPhone]: unrecognized selector sent to
instance 0x874af90'
Sounds like you have a zombie. When you get an action being sent to an object that makes no sense, it usually means that your object is being deallocated before you can send a message to it.
In your case, you're adding "displayedRecord" as the target for your button.
In order for that to work, you need to keep a strong reference to displayedRecord call for the lifetime of your button object. What owns your displayedRecord object?
If you can't debug this from looking at your code you can use the zombies instrument to try to figure it out.
In your unrecognized selector error you sent the message to an object called UIDeviceWhiteColor. Does that class have a method called callPhone? It seems to me that displayedRecord is not pointing to the object you think it is.

Putting data in embedded Table View in UIView container

It's this case again:
I wish to fill the prototype cells with the names of the friends selected in the UIPickerView over there. I have programatically filled the picker with the string representation of my Player object data, and set its properties using the delegate functions.
The "New Game Friends View" you see here has its own viewcontroller subclass, as has the table view, which I attempt to embed into a UIView on the "New Game Friends View". The table view IS an instance of my WHGFriendTableViewController class. I know this because this function does not throw any exceptions:
- (IBAction)addBtnClicked:(id)sender {
WHGFriendTableViewController* tabView = (WHGFriendTableViewController*) [[self childViewControllers] objectAtIndex:0];
NSInteger row = [friendPicker selectedRowInComponent:0];
[[tabView selectedFriends] addObject:[[self friendList] objectAtIndex:row]];
[[tabView tableView] reloadData];
}
Now the problem is: while the function above does not throw any exceptions, it still does not work. It appears that nothing really happens when I insert the objectAtIndex:row into the NSMutableArray selectedFriends (which is a property) in the table view's view controller.
This:
NSLog(#"New length: %d", [[tabView selectedFriends] count]);
prints 0 after inserting the new object. I have no idea why. Printing the count of [self friendList] gives three, just as I expect. The reloadData message does not make anything appear in the table view.
Any ideas why I cannot insert new data into the table view with my code, when this seems to be working with no exceptions whatsoever? Thanks in advance!
Have you alloced & init your NSMutableArray selectedFriends?
Also have you set the dataSource and delegate of your table view?

"Array out of bounds" error when trying to add subview in iOS

I'm currently writing an app and I'm experiencing a problem that seems to be caused by code that I did not write (i.e., Apple's classes). I create an instance of a subclass of UIViewController that I wrote. I add it as a child view controller of another custom view controller. Then, when I try to add this new view controller's view as a subview of the parent view controller's view I get a crash with this error.
Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'
I have tested and determined that the problem is specifically cause by trying to add the view as a subview. I reference the view in an NSLog just to make sure that it isn't simply the act of referencing it that's causing the error. I've tried adding the view as a subview of different views and that also crashed, so the problem is not with the parent view. Finally, I have tried to add a different view as a subview to the parent view and that did work, further proving that the parent view is fine, and that the prospective subview is at fault. The code where I allocate it is this:
ScheduleSelectorViewController* selector = [[ScheduleSelectorViewController alloc] initWithNibName:#"ScheduleSelectorViewController" bundle:nil];
This has always worked for me. I don't know what it is I've changed. I don't know enough about the inner workings of subview hierarchy to know which array is empty and is causing this crash, so if anyone can help me out I would be extremely grateful.
If there's any other information I could supply that would help let me know.
UPDATE:
Here is the code where it crashes. I have placed NSLogs to indicate the line at which it breaks.
- (void) addViewControllerToStack:(UIViewController *)controller withKey:(NSString *)key
{
if ( !self.stack ) {
self.stack = [[NSMutableDictionary alloc] init];
}
NSLog(#"subviews %#", [controller.view subviews]);
[[controller view] setFrame:offScreenFrame];
[self addChildViewController:controller];
NSLog(#"code gets to here");
[self.view addSubview:controller.view];
NSLog(#"but not to here");
[self.view bringSubviewToFront:controller.view];
[self.stack setObject:controller forKey:key];
[self.stackKeys addObject:key];
}
For the record, the subviews array is not nil.
Check if you have set view's.hidden = YES; somewhere
I was pulling my hair for more than hour to find out I was hiding my pager control and try to set the pageIndicatorTintColor property later which also throw array out of bounds issue.
Make sure you did not override init/ initWithNibName methods in ScheduleSelectorViewController without calling the super methods.
And of course you can always print out [self.view subviews] for parent view in console to understand if subview array is whether nil. If it is nil you should initiate it before adding any views.

Link ActionSheet button to TableView

I have an action sheet that pops up on a view controller. That action sheet has 3 buttons, "Choose Existing Icon", "Take Picture", and Cancel.
I have the Take Picture button working just fine. However, I want the Choose Existing Icon button to link to a UITableViewController that has a list of premade icons that I will have seeded the application with. How do I go about linking the button to the table of icons?
I have tried this in the clickedAtButtonIndex method,
NSString *buttonTitle = [actionSheet buttonTitleAtIndex:buttonIndex];
if ([buttonTitle isEqualToString:#"Choose Existing Icon"])
{
IconViewController *iconPicker = [[IconViewController alloc] init];
[self presentViewController:iconPicker animated:YES completion:nil];
}
But this crashes. I want it to let the user see a table of icons and select one. Then have that icon show up in a UIImageView on the original controller.
Thanks for any help
EDIT
I'll change to buttonIndex, thanks for the tip on that. I followed a tutorial and didn't think much about it.
When I run the code as it is here, I get this error when I tap the "Choose Existing Icon" button.
2013-10-01 13:06:18.680 CardMinder[594:60b] * Assertion failure in -[UITableView _configureCellForDisplay:forIndexPath:], /SourceCache/UIKit/UIKit-2903.2/UITableView.m:6235
2013-10-01 13:06:18.684 CardMinder[594:60b] * Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:'
There is a method for calling functions at button touchs in uiactionsheet similar to uialertview
http://blog.mugunthkumar.com/coding/ios-code-block-based-uialertview-and-uiactionsheet/ ..... read this blog

UIScrollView loses reference to delegate

I need to create a number of UIScrollViews dynamically and fill them with content. This is all good except when i set the delegate to self and pan the list i get this exception:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString scrollViewDidScroll:]: unrecognized selector sent to instance 0x7581230'
NSCFString obviously isn't my view controller (which implements the protocol UIScrollViewDelegate) so from what i gather somehow the memory gets messed up and it doesn't keep the reference correctly. Occasionally this can be something else too which strongly points to something being wrong with the memory
Here's the code to create the list:
for (NSUInteger i = 0; i < self.stories.currentStory.selectableWordCount; i++) {
UIScrollView *list = [[UIScrollView alloc] init];
list.alwaysBounceVertical = YES;
list.showsVerticalScrollIndicator = NO;
list.clipsToBounds = NO;
list.delegate = self;
list.pagingEnabled = YES;
[self.view addSubview:list];
.. // add UILabels to the list, set the frame, contentSize etc
[self.wordLists addObject:list]; // this is a #property (nonatomic, strong) NSMutableArray, declared in a private interface()
}
If i NSLog the delegate it's correct. respondsToSelector also matches fine. Interestingly if i comment out the scrollViewDidScroll: respondsToSelector: doesn't match any more and (probably because of this) the UIScrollView won't attempt to call this method any more. This then means that it can reach the delegate correctly to check for the method availability but when it gets called something goes wrong.
I'm targeting iOS5 with ARC. If this wasn't the case i would assume that i messed something up with the memory myself but now i don't have the same control.
I'm having a hard time debugging this issue, any help on how to proceed would be appreciated
D'uh. I was obviously looking in the wrong place. The view controller was added through a .xib and the view was pointing to a subview on the stage. However i needed to create an IBOutlet to the view controller in the main view controller to make sure it stays in memory. Hopefully this can help somebody else with a similar problem :)

Resources