Converting One-Off Code to Method - objective-c

I have the following code which takes a touch on one button and draws a border around that button, then makes sure that all the other buttons have no border (8 buttons total). This is a method in a singleton class called AnswerButtons. This code works fine.
- (IBAction)button1WasTouched:(id)sender {
NSLog(#"Hello from button 1");
// retrieve, modify and update clueAnsState
NSMutableArray *newCAS = [[GameData gameData].curData objectForKey:#"clueAnsState"];
[newCAS replaceObjectAtIndex:0
withObject:#"2"];
[[GameData gameData].curData setObject:newCAS
forKey:#"clueAnsState"];
// Highlight the pressed button & make sure other buttons are not highlighted
for (NSInteger idx = 0; idx < 8; idx++) {
NSString *temp = [newCAS objectAtIndex:idx];
if ([temp isEqualToString:#"1"]) {
UIButton *b = [[AnswerButtons answerButtons].buttons objectAtIndex:idx];
[[b layer] setBorderWidth:0.0f];
}
if ([temp isEqualToString:#"2"]) {
UIButton *b = [[AnswerButtons answerButtons].buttons objectAtIndex:idx];
[[b layer] setBorderWidth:2.0f];
}
}
}
Now, I need to use this code for all 8 buttons, so I should write a method with one argument, the button number to modify (pos). In the singleton class .m I put which is virtually the same code:
- (void)activateAnswerAtPos:(int)pos {
// retrieve, modify and update clueAnsState
NSMutableArray *newCAS = [[GameData gameData].curData objectForKey:#"clueAnsState"];
[newCAS replaceObjectAtIndex:pos
withObject:#"2"];
[[GameData gameData].curData setObject:newCAS
forKey:#"clueAnsState"];
NSLog(#"%#", newCAS);
for (NSInteger idx = 0; idx < 8; idx++) {
NSString *temp = [newCAS objectAtIndex:idx];
if ([temp isEqualToString:#"1"]) {
UIButton *b = [[AnswerButtons answerButtons].buttons objectAtIndex:idx];
[[b layer] setBorderWidth:0.0f];
}
if ([temp isEqualToString:#"2"]) {
UIButton *b = [[AnswerButtons answerButtons].buttons objectAtIndex:idx];
[[b layer] setBorderWidth:2.0f];
}
}
}
So I changed the first code chunk to make it a call to the new method:
- (IBAction)button1WasTouched:(id)sender {
NSLog(#"Hello from button 1");
[sender activateAnswerAtPos:0];
}
Unfortunately, I'm doing something wrong as I get the following exception:
2012-03-30 19:41:40.199 P3[6751:f803] Hello from button 1
2012-03-30 19:41:40.201 P3[6751:f803] -[UIRoundedRectButton activateAnswerAtPos:]: unrecognized selector sent to instance 0x6e709f0
I'm not sure what's going on here; several alternatives don't work either and I think my troubleshooting is sending me in the wrong direction. What's wrong with the way I am calling this method? Clearly I'm not even getting to run the method. TIA.

It's hard to follow what you are trying to do but I would probably send all button actions to one method like this
- (void)buttonTapped:(UIButton *)buttonTapped;
{
NSArray *buttons = [AnswerButtons answerButtons].buttons;
// some kind of switch statement of logic to perform options depending on which button
// Can use the following to get the index
// NSInteger buttonIndex = [buttons indexOfObject:buttonTapped]
for (UIButton *button in buttons) {
if (button == buttonTapped) {
// highlight
} else {
// remove highlight
}
}
}

You're calling -activateAnswerAtPos: on sender, which is the button that was touched. You should instead call it on the instance of the class that defines the -activateAnswerAtPos: method. It's not clear from your code what that is, but my guess is self:
[self activateAnswerAtPos:0];

Related

How to understand where the crash is taking place from xcode

I'm new to xcode and I don't understand how I'm supposed to tell why the app is crashing from this report. When I click "Open in project" it takes me to a place in the code with little information to work on.
Picture of crash report
- (void)didTapOnJobTableView:(UIGestureRecognizer *)recognizer {
CGPoint tapLocation = [recognizer
locationInView:self.tableViewJobList];
NSIndexPath *indexPath = [self.tableViewJobList
indexPathForRowAtPoint:tapLocation];
if (indexPath && indexPath.row >= 0 && indexPath.row <
[self.dispatchTable count]) {
SDMobileAppDelegate *appDelegate = [SDMobileAppDelegate me];
Dispatch *d = [self.dispatchTable objectAtIndex:indexPath.row];
<<<<Last exception backtrace here
if (d != nil && ![d isCancelled]) {
JobListTableViewCell *cell = (JobListTableViewCell *)
[self.tableViewJobList cellForRowAtIndexPath:indexPath];
CGPoint tapLocalzied = [recognizer locationInView:cell];
if (CGRectContainsPoint([cell.labelPrts frame], tapLocalzied)) {
if ([d.prtsPckQty integerValue] > 0) {
dispatchForPartsPick = d;
NSMutableString *partsPickText = [NSMutableString
stringWithString:#""];
NSArray *list = [PartsPick getListFromDatabase:self.db
forDispatch:dispatchForPartsPick];
for (PartsPick *p in list) {
NSString *location = #"";
if (![Utilities isEmpty:p.binLoc]) {
location = [NSString stringWithFormat:#"[at %#]", p.binLoc];
}
[partsPickText appendFormat:#"%# %# %# %#\r\n", p.qty,
location, [p.prtNmbr stringByTrimmingCharactersInSet:[NSCharacterSet
whitespaceAndNewlineCharacterSet]], p.dscrptn];
if (![Utilities isEmpty:p.notes]) {
[partsPickText appendFormat:#"%#\r\n", p.notes];
}
[partsPickText appendString:#"\r\n"];
}
[ShowTextViewController show:self request:SEGUE_PARTSPICK_PREVIEW
header:[NSString stringWithFormat:lStr(#"PARTSPICK_PREVIEW"),
dispatchForPartsPick.invNmbr] message:#"" defaultText:partsPickText
editable:NO autoCap:UITextAutocapitalizationTypeNone delegate:nil];
} else {
[Utilities showOkAlertWithTitle:lStr(#"PTA")
andMessage:lStr(#"PARTSPICK_PREVIEW_NONE") onComplete:nil];
}
} else {
if ([Utilities allowedToGoToJob: d]) {
appDelegate.selectedDispatch = [NSNumber
numberWithLong:indexPath.row];
self.tabBarController.selectedIndex = 1;
} else {
[Utilities showOkAlertWithTitle:#"Cannot Continue"
andMessage:#"Cannot select until previous PVR is completed."
onComplete:nil];
}
}
} else {
[Utilities showOkAlertWithTitle:lStr(#"PTA")
andMessage:lStr(#"JOB_CANCELLED_CANNOT_SELECT") onComplete:nil];
}
}
}
Here is the code where this the above is used, specifically the gesture recognizer part:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self refresh];
XLog(#"Job List View will appear");
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(didTapOnJobTableView:)];
[self.tableViewJobList addGestureRecognizer:tap];
// startup the ticker
self.countdownTimer = [NSTimer scheduledTimerWithTimeInterval:1
target:self selector:#selector(countdownTimer:) userInfo:nil
repeats:YES];
SDMobileAppDelegate *appDelegate = [SDMobileAppDelegate me];
NSTimeInterval diff = [[appDelegate.refreshTimer fireDate]
timeIntervalSinceNow];
if (diff > 60) {
self.buttonForceRefresh.enabled = YES;
self.buttonForceRefresh.titleLabel.enabled = YES;
}
[self setTimeCardStatus];
}
That has lots of information to work with; you just don't know what it means yet. Been there - it's frustrating at times...
See Ray Wenderlich's site and Apple's docs to get started debugging:
https://www.raywenderlich.com/10209/my-app-crashed-now-what-part-1
https://www.raywenderlich.com/10505/my-app-crashed-now-what-part-2
"Unrecognized Selector" or "Does not respond to selector" means the object being called doesn't understand or can't find the method you're trying to call.
When that message is related to the user interface or interaction, it often means you forgot to hook up the IBOutlet or IBAction from the UI element to the code, or there's a typo in the names somewhere, or the method you're trying to call doesn't exist (or isn't publicly exposed) in the object being called.
Make sure you've hooked up your elements from interface builder to the code for the class, that the names are consistent, and that the method didTapOnJobTableViewactually exists in the class JobListViewController.

Custom InputView for UISearchBar doesn't work after tap cancel button in iOS7

In my iOS App , i need to set custom inputView for UISearchBar in iOS7.
So i wrote following codes.
NSArray *searchBarSubViews = [[self.sBar.subviews objectAtIndex:0] subviews];
for(int i =0; i<[searchBarSubViews count]; i++) {
if([[searchBarSubViews objectAtIndex:i] isKindOfClass:[UITextField class]])
{
UITextField* search=(UITextField*)[searchBarSubViews objectAtIndex:i];
[search setFont:[UIFont fontWithName:#"CustomFont" size:15]];
search.delegate = self;
[search setInputView:self.customKeyboard];
[self.customKeyboard setTextView:search];
}
}
It is working fine. However when i type with my custom keyboard and tap Cancel Button to resignFirstResponder.
And i tap UISearchBar again, i can't type any text in UISearchBar , including native english keyboard.
And also Cancel Button is hiding and UISearchBar is not working anymore.
I don't know why is happening?
How can i solve it?
I tried your code and it's working fine with my app. In fact thanks and congratulations seem to be in order, because for one reason or other you seem to have solved a problem others on this site had to built more elaborate workarounds for.
In my app the keyboard changes according to the selected scope of the searchbar:
scope == 0 presents my CustomKeyboard
scope != 0 presents the usual iPhone Keyboard.
My implementation of your code looks like this:
-(UITextField *)textFieldFormSearchBar{
NSArray *searchBarSubViews = [[self.searchBar.subviews objectAtIndex:0] subviews];
for(int i =0; i<[searchBarSubViews count]; i++) {
if([[searchBarSubViews objectAtIndex:i] isKindOfClass:[UITextField class]])
{
UITextField* search=(UITextField*)[searchBarSubViews objectAtIndex:i];
return search;
}
}
return nil;
}
-(BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar{
if (searchBar.selectedScopeButtonIndex==0) {
self.textFieldFormSearchBar.delegate = self;
self.textFieldFormSearchBar.inputView=self.customKeyboard;
self.customKeyboard.field=self.textFieldFormSearchBar;
}
else{
if (self.customKeyboard.superview!=nil) [self.customKeyboard removeFromSuperview];
self.textFieldFormSearchBar.delegate = self;
self.textFieldFormSearchBar.inputView=nil;
self.customKeyboard.field=nil;
}
return YES;
}
-(void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope{
if (selectedScope==0) {
self.textFieldFormSearchBar.delegate = self;
self.textFieldFormSearchBar.inputView=self.customKeyboard;
self.customKeyboard.field=self.textFieldFormSearchBar;
}
else{
if (self.customKeyboard.superview!=nil) [self.customKeyboard removeFromSuperview];
self.textFieldFormSearchBar.delegate = self;
self.textFieldFormSearchBar.inputView=nil;
self.customKeyboard.field=nil;
}
[self.textFieldFormSearchBar reloadInputViews];
}
-(BOOL)searchBarShouldEndEditing:(HDLSearchBar *)searchBar{
if (self.customKeyboard) {
[self.customKeyboard removeFromSuperview];
}
return [self.textFieldFormSearchBar resignFirstResponder];
}
Probably not the most efficient way to do it, but it does the trick. I hope you'll find something that helps you solve your problem.

One IBAction multiple buttons and labels

I have one label, two button. One to +1 and one to -1 from the label.
I use following code:
.h
int counter;
IBOutlet UILabel *count;
}
-(IBAction)plus:(id)sender;
-(IBAction)minus:(id)sender;
.m
-(IBAction)plus {
counter=counter + 1;
count.text = [NSString stringWithFormat:#"%i",counter];
}
-(IBAction)minus {
counter=counter - 1;
count.text = [NSString stringWithFormat:#"%i",counter];
}
The two buttons are linked to the label(count) in IB.
Now to my question. If I want to have more buttons and labels like this, how can I do that?
I know I can copy the code and relinked them in IB but that gonna take to long.
And when the buttons are linked to the count label, it doesn't work to just copy them in IB, the buttons works but it counting the first label. I need to count every label each.
So, how can I do this and save time? Its gonna be many of those.
You can generate your buttons in series, store them in an NSArray, and do the same with the labels. Then you can relate them using their index in the arrays.
// Assuming a view controller
#interface MyVC: UIViewController {
NSMutableArray *buttons;
NSMutableArray *labels;
}
// in some initialization method
buttons = [[NSMutableArray alloc] init];
labels = [[NSMutableArray alloc] init];
for (int i = 0; i < numberOfButtonsAndLabels; i++) {
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
// configure the button, then
[self.view addSubview:btn];
[buttons addObject:btn];
UILabel *lbl = [[UILabel alloc] initWithFrame:aFrame];
// configure the label, then
[self.view addSubview:lbl];
[labels addObject:lbl];
[lbl release];
}
- (void)buttonClicked:(UIButton *)sender
{
NSUInteger index = [buttons indexOfObject:sender];
UILabel *label = [labels objectAtIndex:index];
// use index, sender and label to do something
}

UIImageView added to an NSArray doesn't respond

I am fairly new to Objective-C, this is the first time I really don't know what to do.
I have a class - Parser - which creates UIImageViews, inits them with images and adds them to the UIView. The class also adds these UIImageViews to NSMutableArray - imgArray, which is a property of another class - Page.
Then, on the click of a button, I call the Page class from a Manager class, loop through the imgArray and try to set a new images for the UIImageViews in the array.
It doesn't work. Actually nothing I do to the UIImageViews doesn't work.
I try [img removeFromSuperView], [img setHidden:YES] and more. It doesn't response.
Here I declare the Array property in Page:
#property (nonatomic, retain) NSMutableArray *imgArray;
Here is the code from Parser where I create the image and add it to the array:
UIImageView *img = [[UIImageView alloc] initWithFrame: frame];
NSString *name = [c imageSource];
[img setImage: [UIImage imageFromBook: name]];
[view addSubview: img];
[c setImage:img];
if (!page.imgArray)
{
page.imgArray = [[NSMutableArray alloc] init];
}
[page.imgArray addObject:img];
[img release];
Here is the loop code from the Manager:
- (void) set3D:(bool)is3D
{
Page *page = [[DataManager data] currentPage];
int count = [page.imgArray count];
for (int i = 0; i < count; i++)
{
UIImageView *img = [page.imgArray objectAtIndex:i];
[img setImage:[UIImage imageNamed:image3DSource]];
}
}
Thanks in advance for any help!
There is no need to store the UIImageView's in an array.
When the UIImageView's are created, you can tag them with an arbitrary number, like.
#define K_MIN_IMGV 100
#define K_MAX_IMGV 120
- (void) setupViews
{
for (NSInteger count = K_MIN_IMGV; count < K_MAX_IMGV; ++count)
{
UIImageView *imgV = // create image view, set properties
imgV.tag = count; // tag the views for easy retrieval later
...
[mainView addSubview: imgV]; // add subviews
[imgV release], imgV = nil; // mainView now manages, release our allocation
}
}
// how to set new images
- (void) setupNewImages
{
for (NSInteger count = K_MIN_IMGV; count < K_MAX_IMGV; ++count)
{
UIImageView *imgV = (UIImageView *) [mainView viewWithTag: count]; // retrieve imageView
[imgV setImage: newImage]; // set new image
}
}
// To remove the imageView, you can use
UIImageView *imgV = (UIImageView *) [mainView viewWithTag: 123];
[imgV removeFromSuperview];
Have you tried to enumerate through the array using:
for(UIImageView* imageView in page.imgArray)
{
//Do code
}
This will tell you if there any imageViews in page.imgArray.
How are you adding objects to NSMutableArray and how are you initialising your NSMutableArray.
I remember having a problem adding objects to NSMutableArray but setting my init to solved this:
NSMutableArray* mutableArray = [NSMutableArray array];
Also what properties have you set on imgArray in page? Are you retaining the values?
Need to see more code to gain a fuller understanding.

My NSMutable Array isn't adding a button

I'm trying to add button to a scroll view using a NSMutableArray. The code works fine in a twitter example I am using as a reference, but for some reason it is not working in this case. In the twitter search case the code is implemented in the main class. While in this case I am implementing it in the flipside view. Could anyone help me out since I am a bit new to Objective c.
Thanks in Advance.
Here is the init where the NSMutableArray Buttons is initialized
- (id)init
{
self = [super init]; // initialize the superclass members
if (self != nil) // if the superclass initialized properly
{
// creates list of valid directories for saving a file
NSArray *paths = NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES);
// get the first directory
NSString *dir = [paths objectAtIndex:0];
// concatenate the file name "tagsIndex.plist" to the path
filePath = [[NSString alloc] initWithString:
[dir stringByAppendingPathComponent:#"tagsIndex.plist"]];
NSFileManager *fileManager = [NSFileManager defaultManager];
// if the file does not exist, create an empty NSMutableDictionary;
// otherwise, initialize an NSDictionary with the file's contents
if ([fileManager fileExistsAtPath:filePath] == NO)
{
tags = [[NSMutableDictionary alloc] init];
} // end if
else
{
tags = [[NSMutableDictionary alloc]
initWithContentsOfFile:filePath];
} // end else
buttons = [[NSMutableArray alloc] init]; // create array
infoButtons = [[NSMutableArray alloc] init]; // create array
}
return self; // if self == nil, object not initialized properly
} // end method init
Here we have the method where we are adding the object to the buttons array but it stays empty.
- (void)addNewButtonWithTitle:(NSString *)title
{
// create a new button
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
// give the button the title of the tag
[button setTitle:title forState:UIControlStateNormal];
// tell the button to call buttonTouched: when it is touched
[button addTarget:self action:#selector(buttonTouched:)
forControlEvents:UIControlEventTouchUpInside];
[buttons addObject:button]; // add the UIButton to the end of the array
//This Doesn't add it stays 0;
// sort the NSMutableArray by the UIButton's titles
[buttons sortUsingSelector:#selector(compareButtonTitles:)];
[self refreshList]; // refresh the list of favorite search Buttons
// Adjust the content size of the view to include the new button. The
// view scrolls only when the content size is greater than its frame.
CGSize contentSize = CGSizeMake(scrollView.frame.size.width,
buttons.count * (BUTTON_HEIGHT + BUTTON_SPACING) + BUTTON_SPACING);
[scrollView setContentSize:contentSize];
}
Here is the dealloc where I release the buttons array.
- (void)dealloc {
[buttons release];
[super dealloc];
}
I can't Figure out where the mistake is.
Here is the Code that is supposed to add a new button.
- (IBAction)addTag:sender
{
// make the keyboard disappear
[ItemTitleField resignFirstResponder];
[QuantityField resignFirstResponder];
NSString *key = ItemTitleField.text; // get the text in tagField
NSString *value = QuantityField.text; // get the text in queryField
// test if either field is empty
if (value.length == 0 || key.length == 0)
return; // exit from the method
if ([tags valueForKey:key] == nil) // test if the tag already exists
[self addNewButtonWithTitle:key]; // if not, add a new button
[tags setValue:value forKey:key]; // add a new entry in tags
ItemTitleField.text = nil; // clear tagField of text
QuantityField.text = nil; // clear queryField of text
[tags writeToFile:filePath atomically:NO]; //save the data
} // end method addTag:
- (void)addNewButtonWithTitle:(NSString *)title
{
// create a new button
// UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
UIButton *button = [[UIButton alloc] init];
or
UIButton *button = [[UIButton buttonWithType:UIButtonTypeRoundedRect] retain];
// give the button the title of the tag
[button setTitle:title forState:UIControlStateNormal];
// tell the button to call buttonTouched: when it is touched
[button addTarget:self action:#selector(buttonTouched:)
forControlEvents:UIControlEventTouchUpInside];
[buttons addObject:button]; // add the UIButton to the end of the array
//This Doesn't add it stays 0;
// sort the NSMutableArray by the UIButton's titles
[buttons sortUsingSelector:#selector(compareButtonTitles:)];
[self refreshList]; // refresh the list of favorite search Buttons
// Adjust the content size of the view to include the new button. The
// view scrolls only when the content size is greater than its frame.
CGSize contentSize = CGSizeMake(scrollView.frame.size.width,
buttons.count * (BUTTON_HEIGHT + BUTTON_SPACING) + BUTTON_SPACING);
[scrollView setContentSize:contentSize];
}