Accessing NSMutableArray Difficulties - objective-c

I am trying to build an NSMutableArray each time a button is pressed. I am using NSLog to check the array count after each button pressed and the value is zero. THe code is below.
ProjectViewController.h
NSMutableArray *numberQuery
...
#property (nonatomic, retain) NSMutableArray *numberQuery;
ProjectViewController.m
- (void)makeButtons{
UIButton * pickButton;
int y_plot = 150;
int x_plot = 70;
int z = 0;
for(int y = 1; y < 10; y++)
{
for(int x = 1; x < 5; x++){
z++;
pickButton = [UIButton buttonWithType:UIButtonTypeCustom];
pickButton.frame = CGRectMake(x*x_plot, y_plot, 60, 40);
[pickButton setBackgroundImage:[UIImage imageNamed:#"btnUnselected.png"] forState:UIControlStateNormal];
[pickButton addTarget:self action:#selector(digitClick:) forControlEvents:UIControlEventTouchUpInside];
[pickButton setTitle:[NSString stringWithFormat:#"%d",z] forState:UIControlStateNormal];
pickButton.titleLabel.textColor = [UIColor blackColor];
pickButton.tag = z;
[self.view addSubview:aButton];
}
y_plot=y_plot+45;
}
}
//************************
- (void)digitClick:(id)sender{
UIButton * chosenButton =(UIButton *)sender;
if ([sender isSelected] ==FALSE) {
[sender setSelected:TRUE];
[chosenButton setBackgroundImage:[UIImage imageNamed:#"btnSelected.png"] forState:UIControlStateNormal];
chosenButton.titleLabel.textColor = [UIColor whiteColor];
if([queryNumbersX count]<6){
[self numberSearchArray:chosenButton.tag];
}
}
else
{[sender setSelected:FALSE];
[chosenButton setBackgroundImage:[UIImage imageNamed:#"btnUnselected.png"]forState:UIControlStateNormal];
chosenButton.titleLabel.textColor = [UIColor blackColor];
}
forState:UIControlStateNormal];
NSLog(#"clicked button with title %d",chosenButton.tag);
}
//************************
-(void) numberSearchArray:(NSInteger)newNumber;
{
[self.numberQuery addObject:[NSNumber numberWithInt: newNumber]];
NSLog(#"numberSearchArray %d - count %d",newNumber, [self.numberQuery count]);
}
Am I using the NSMutableArray in the right manner...declaration?
This is the code in the viewDidLoad method
NSMutableArray *numberQuery = [[NSMutableArray alloc] initWithObjects:nil];
Although I have the array declared int he header file, It seems as though I cannot access it outside of the method in which it was allocated.

#property (nonatomic, retain) NSMutableArray *numberQuery;
You must balance that with
#synthesize numberQuery;
in the .m
and the correct creation would be
self.numberQuery = [NSMuatableArray arrayWithCapacity:someNumber];
By doing this
NSMutableArray *numberQuery = [[NSMutableArray alloc] initWithObjects:nil];
You are not using your #property you are creating a new variable, this is why you get the warning that your variable is not use, because it's scope is actually just the viewDidLoad method instead of the object.

It looks like that you have never alloced numberQuery. So it is always nil and thus addObject method is ignored. You need to alloc this in init (or any suitable place you like) and release in dealloc (or in other suitable place).

Related

subclassed label class is not key value coding-compliant

edit 1
This question is answered here Sorry for the noise.
edit 1
edit 0
I have included more code below and also an image of the result which shows the result I get, which is the same result I got without the subclassing, with just plain labels. In the first 3 rows the labels seem to cover up the button altogether, and in the 4th row there are no labels, and notice that the button #2 is indented on the 4th row. What's going on.
This code only applies to the first of the four rows, but the other 3 rows are similar.
self.cardList = [NSMutableArray arrayWithCapacity:0];
self.yHonorsOrigin = 100;
self.xHonorsOrigin = 100;
self.xHonorsStep = 40.0;
self.xHonorsCurrent = self.xHonorsOrigin;
for( int x=0;x<[cards length]; x++ ){
[cards substringWithRange:NSMakeRange(x,1)];
UIButton *b= [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.xHonorsCurrent += self.xHonorsStep;
[b setTitle:[cards substringWithRange:NSMakeRange(x,1)] forState:UIControlStateNormal];
[b setTitle:#" " forState:UIControlStateDisabled];
[b setFrame:CGRectMake(self.xHonorsCurrent, self.yHonorsOrigin, 20, 20)];
[b setEnabled:YES];
[b setUserInteractionEnabled:YES];
[self.view addSubview:b];
[b addTarget:self action:#selector(spadeButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
self.xHonorsCurrent = self.xHonorsOrigin + self.xHonorsStep/2;
for( int x=0;x<[cards length]-1; x++ ){
self.xHonorsCurrent += self.xHonorsStep;
UILabel *lab = [self valueForKey:#"theSuit" ];
lab.text = #"\u2660";
//lab.tintColor = [UIColor clearColor];
lab.center = CGPointMake(self.xHonorsCurrent, self.yHonorsOrigin);
[self.view addSubview:lab];
}
}
}
edit 0
I have attempted to subclass the UILabel class using BDBoundedLabel, but am throwing an exception that "subclassed label class is not key value coding-compliant for the key theSuit." Please help.
BDBoundedLabel.m
#import "BDBoundedLabel.h"
#implementation BDBoundedLabel
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
- (void)drawTextInRect:(CGRect)rect{
CGContextRef context=UIGraphicsGetCurrentContext();
CGContextStrokeRect(context, CGRectInset(self.bounds, 1, 1));
[super drawTextInRect:CGRectInset(rect, 5.0, 5.0)];
}
#end
viewController.h
#import <UIKit/UIKit.h>
#import "BDViewController.h"
#import "BDBoundedLabel.h"
#interface BDnameViewController : UIViewController{
IBOutlet BDBoundedLabel* theSuit;
}
viewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
self.cardList = [NSMutableArray arrayWithCapacity:0];
self.yHonorsOrigin = 100;
self.xHonorsOrigin = 100;
self.xHonorsStep = 40.0;
self.xHonorsCurrent = self.xHonorsOrigin;
// Do any additional setup after loading the view.
self.xHonorsCurrent = self.xHonorsOrigin + self.xHonorsStep/2;
for( int x=0;x<[cards length]-1; x++ ){
self.xHonorsCurrent += self.xHonorsStep;
UILabel *lab = [BDBoundedLabel valueForKey:#"theSuit" ];
lab.text = #"\u2660";
lab.center = CGPointMake(self.xHonorsCurrent, self.yHonorsOrigin);
[self.view addSubview:lab];
}
}
setValue:forKey: and valueForKey: will use the accessors methods (setter and getter), so you need to create them. Declare a property:
#property(nonatomic,assign) BDBoundedLabel* theSuit;
Also, like stated by Benjamin you are calling valueForKey: on a class object, maybe you meant to call the method with self as target, this way:
UILabel *lab = [self valueForKey:#"theSuit" ];
// Equivalent of lab= self.theSuit
Your code does not make any sense. You are performing KVO on a class object, which is almost never done. For most cases, KVO is only ever used on instances of a class, which is not what you are doing here.
Please try and clarify what you are trying to do.

Passing an object to selector action

Ok simple question but can't find an answer.
I'v got a button to save information in my app.
I have
NSMutableArray *textFields = [[NSMutableArray alloc] initWithCapacity:5];
UITextField *textField = nil;
This is the information i want to save, i'v got 5 textfields in textFields mutablearray.
[save addTarget:self action:#selector(saveInfo)
forControlEvents:UIControlEventTouchUpInside];
and
-(void)saveInfo {
[[[NSUserDefaults standardUserDefaults] setValue: ????? forKey:#"Phone"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
The question is how to access and get information from like textFields[1].text in my saveInfo void ?
Ok To get things a little bit clearer i'v added the whole class. its not very big, and maybe someone could see thats the problem with my implementation .
#implementation Settings
- (id)init: (TableViewController*) TableControll {
NSMutableArray *textFields = [[NSMutableArray alloc] initWithCapacity:5];
UITextField *textField = nil;
for (int i = 0; i < 3; i++) {
textField = [[UITextField alloc] initWithFrame:CGRectMake(0.0f, 0.0f+(i*35), 120.0f, 30.0f)];
textField.backgroundColor = [UIColor whiteColor];
[textField setBorderStyle:(UITextBorderStyleRoundedRect)];
[TableControll.view addSubview:textField];
[textFields addObject:textField];
[textField release]; textField = nil;
}
UITextField *textName = textFields[0];
textName.placeholder = #"Vardas";
UITextField *textNo = textFields[1];
textNo.placeholder = #"Telefonas";
textNo.keyboardType = UIKeyboardTypeNumberPad;
UITextField *textPin = textFields[2];
textPin.keyboardType = UIKeyboardTypeNumberPad;
textPin.placeholder = #"Pin";
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(150, 20, 160, 30);
[button setTitle:#"Advanced settings" forState:UIControlStateNormal];
[TableControll.view addSubview:button];
UIButton *save = [UIButton buttonWithType:UIButtonTypeRoundedRect];
save.frame = CGRectMake(150, 60, 160, 30);
[save setTitle:#"Save settings" forState:UIControlStateNormal];
[TableControll.view addSubview:save];
[button addTarget:self action:#selector(goAdvanced)
forControlEvents:UIControlEventTouchUpInside];
[save addTarget:self action:#selector(saveInfo)
forControlEvents:UIControlEventTouchUpInside];
return self;
}
-(void)goAdvanced {
AppDelegate *newControll = (AppDelegate*)[UIApplication sharedApplication].delegate;
[newControll ChangeController];
}
-(void)saveInfo {
for(int i=0;i<5;i++) {
UITextField *tempTxtField=[_textFields objectAtIndex:i];
NSLog(#"do it %#",tempTxtField.text);
}
}
#end
What you'd want to do if you are using interface builder is create a bunch of IBOutlet for your textfields instead of keeping them in an array. Check out this: tutorial
Now it looks like you're creating things by hand, so in this case, you probably just want to declare your array as #property so it can be accessed by your save method.
To access the text property of a UITextField from your array you would write:
((UITextField *)[textFields objectAtIndex:1]).text
If you want to access the all textfield,
for(int i=0;i<[textFields count];i++) {
UITextField *tempTxtField=[textFields objectAtIndex:i];
NSlog(#"%#",tempTxtField);
}
-(void)saveInfo {
NSMutableArray *tempArr = [NSMutableArray array];
for(int i = 0; i < [textFieldsArray count]; i++){
[tempArr addObject:[(UITextField*)[textFieldsArray objectAtIndex:i]text]];
}
[[[NSUserDefaults standardUserDefaults] setValue:tempArr forKey:#"Phone"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
I'm not entirely sure I understand your question, but this is what I would do in your place. Instead of creating an array to hold each of the textfields, I'd just assign them a custom tag. Any number will work (although avoid zero since that's the default tag on all views). So your init method would look like this:
for (int i = 0; i < 3; i++) {
textField = [[UITextField alloc] initWithFrame:CGRectMake(0.0f, 0.0f+(i*35), 120.0f, 30.0f)];
textField.backgroundColor = [UIColor whiteColor];
textField.tag = (i+1);
[textField setBorderStyle:(UITextBorderStyleRoundedRect)];
[TableControll.view addSubview:textField];
[textField release]; textField = nil;
}
Then in the code that you want to reference the text field, you'd retrieve the view by its tag, making sure to cast it as UITextField.
-(void)saveInfo {
for(int i=0;i<5;i++) {
UITextField *textField = nil;
UIView *view = [self.view viewsWithTag:i];
if ([view isKindOfClass:[UITextField class]]) {
textField = (UITextField *) view;
NSLog(#"do it %#",textField.text)
}
}
}
NOTE: I'm referencing self.view but you'll need to reference TableControll.view. You'll need to retain a reference to it somewhere in your code. Also, I'd recommend your start using ARC.
Hope that helps! Good luck!

Property retain in ios

Ok simple question but can't find an answer..
I need to pass my viewcontroller to an method "saveinfo" within a class which is called when the button is pressed, how to make viewcontroller visible to "saveinfo" method so i can use it there?
Ok i'll add the whole class. Basicaly I need to get the textfield information when the button is pressed. But i can't get access to textFields nor TableControll variables in my saveinfo method.
#implementation Settings
- (id)init: (TableViewController*) TableControll {
NSMutableArray *textFields = [[NSMutableArray alloc] initWithCapacity:5];
UITextField *textField = nil;
for (int i = 0; i < 3; i++) {
textField = [[UITextField alloc] initWithFrame:CGRectMake(0.0f, 0.0f+(i*35), 120.0f, 30.0f)];
textField.backgroundColor = [UIColor whiteColor];
[textField setBorderStyle:(UITextBorderStyleRoundedRect)];
[TableControll.view addSubview:textField];
[textFields addObject:textField];
[textField release]; textField = nil;
}
UITextField *textName = textFields[0];
textName.placeholder = #"Vardas";
UITextField *textNo = textFields[1];
textNo.placeholder = #"Telefonas";
textNo.keyboardType = UIKeyboardTypeNumberPad;
UITextField *textPin = textFields[2];
textPin.keyboardType = UIKeyboardTypeNumberPad;
textPin.placeholder = #"Pin";
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(150, 20, 160, 30);
[button setTitle:#"Advanced settings" forState:UIControlStateNormal];
[TableControll.view addSubview:button];
UIButton *save = [UIButton buttonWithType:UIButtonTypeRoundedRect];
save.frame = CGRectMake(150, 60, 160, 30);
[save setTitle:#"Save settings" forState:UIControlStateNormal];
[TableControll.view addSubview:save];
[button addTarget:self action:#selector(goAdvanced)
forControlEvents:UIControlEventTouchUpInside];
[save addTarget:self action:#selector(saveInfo)
forControlEvents:UIControlEventTouchUpInside];
return self;
}
-(void)goAdvanced {
AppDelegate *newControll = (AppDelegate*)[UIApplication sharedApplication].delegate;
[newControll ChangeController];
}
-(void)saveInfo {
for(int i=0;i<5;i++) {
UITextField *tempTxtField=[_textFields objectAtIndex:i];
NSLog(#"do it %#",tempTxtField.text);
}
}
#end
just add the NSMutableArray as ivar to your class:
#implementation TableControll {
NSMutableArray *_textFields;
}
- (id)init: (TableViewController*) tableControll {
_textFields = [[NSMutableArray alloc] initWithCapacity:5];
//init the textfields
//and add it as subview
}
// skipping the rest of the implementation
-(void)saveInfo {
for(int i=0;i<5;i++) {
UITextField *tempTxtField=[_textFields objectAtIndex:i];
NSLog(#"do it %#",tempTxtField.text);
}
}
#end
you should check if you could reuse the UITextFields or have to init the NSMutableArray every time again. It seems you don't use ARC, but you shouldn't write something like [textField release]; textField = nil;. You want to release the object to decrement the counter, but do not set it to nil (except in dealloc).

Why this brings about SIGABRT error?

I have some sources below.
- (void)Button:(UIButton *)button {
NSString *imageName = ((UIButton *)[self.view viewWithTag:button.tag]).titleLabel.text;
}
- (void)viewDidLoad {
NSMutableArray *_array = [[NSMutableArray alloc] init];
NSInteger iCount = [_array count];
for (i = 0; iCount > i; i++) {
UIButton *btn = [[UIButton alloc] init];
btn.titleLabel.text = [[_array objectAtIndex:i] objectForKey:#"FILE"];
btn.tag = i;
[btn addTarget:self action:#selector(Button:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
[btn release];
}
When I access Button method with 0 index tag, I get SIGABRT error.
What can I do ?
Read your console output properly, by default every view has the tag '0', so it can be crashed because it is taking some other view besides of uibutton, and may be that view don't not have the titleLabel property.Because it is the property of UIButton.

Objective-C: An array of UIButtons

If I have a large number of buttons set up in Interface Builder, how can I place them into an array via code?
For example, if I have three buttons and in the interface file I define them:
#property (nonatomic, retain) IBOutlet UIButton *button1;
#property (nonatomic, retain) IBOutlet UIButton *button2;
#property (nonatomic, retain) IBOutlet UIButton *button3;
If I want to rename each of these buttons to say "Hello", I want to be able to lump them into an array and then use a function such as:
for (int i = 0; i < someArray.count; i++)
{
someArray[i].text = #"Hello";
}
Could someone please provide information on how this is achieved (if it's possible)?
Thanks
Another approach is to wire the buttons up to an NSArray in Interface Builder.
#property (nonatomic, retain) IBOutletCollection(UIButton) NSArray *buttons;
The following code will add 5 buttons, each with a new tag and also connect it to an event. The buttons will be placed side by side with a 5px padding:
If you plan on accessing the button outside of the for{} scope below, you can define your button in your header, otherwise, you can define it inside the scope. UIButton * settButton;
.m
CGFloat staticX = 5; // Static X for all buttons.
CGFloat staticWidth = 60; // Static Width for all Buttons.
CGFloat staticHeight = 56; // Static Height for all buttons.
CGFloat staticPadding = 5; // Padding to add between each button.
for (int i = 0; i < 5; i++)
{
settButton = [UIButton buttonWithType:UIButtonTypeCustom];
[settButton setTag:i];
[settButton setFrame:CGRectMake((staticX + (i * (staticHeight + staticPadding))),5,staticWidth,staticHeight)];
[settButton setImage:[UIImage imageNamed:[NSString stringWithFormat:#"%i.png",i]] forState:UIControlStateNormal];
[settButton addTarget:self action:#selector(buttonEvent:) forControlEvents:UIControlEventTouchDown];
[settButtonView addSubview: settButton];
}
[self.view addSubview: settButtonView];
Assuming the buttons in IB are correctly wired to the IBOutlet properties then its as straightforward as:
NSArray *buttonArray = [[NSArray alloc] initWithObjects:button1,button2,button3,nil];
Since you created the buttons directly in Interface Builder, can't you just set them directly in code?
A more general solution would be something like this...if I assume two things: that they are all subviews of the UIViewController's view and that these UIButtons are the only UIButtons in that view, you can do something like this:
for (UIView *aView in [self.view subviews]) {
if ([aView isKindOfClass:[UIButton class]) {
UIButton *aButton = (UIButton *) aButton;
[aButton setTitle:#"Hello" forState:UIControlStateNormal];
}
}
I think that the easiest is to create a single button that you will init and add to a mutable array:
in *.m:
UIButton *buttonChar;
in your function:
buttonArray = [[NSMutableArray alloc] init];
for (int i=0; i<lenghtWord; i++) {
buttonChar = [[UIButton alloc] initWithFrame:CGRectMake(.2*size.height+(float)i*charFontSize, .5*size.width, charFontSize, charFontSize)];
buttonChar.tag = i;
[buttonChar setTitleColor:[UIColor blackColor] forState:(UIControlStateNormal)];
[buttonChar setTitle:[[NSString alloc] formatWithString:#"Button %d",i] forState:UIControlStateNormal];
buttonChar.titleLabel.font = [UIFont boldSystemFontOfSize:15];
buttonChar.titleLabel.textAlignment = UITextAlignmentCenter;
buttonChar.layer.cornerRadius = 5;
buttonChar.layer.masksToBounds = YES;
buttonChar.layer.borderWidth = 1;
buttonChar.layer.borderColor = [[UIColor blackColor] CGColor];
[buttonChar setBackgroundColor:[UIColor whiteColor]];
[buttonChar addTarget:self action:#selector(buttonAction:withEvent:) forControlEvents:UIControlEventTouchDragInside];
[buttonArray addObject:buttonChar];
}
buttons are available through:
[[buttonArray objectAtIndex:j] setTitle:#" " forState:UIControlStateNormal];
Since the tag option is also filled, I can always tell what button from the array was touched if it was displayed (buttonAction:withEvent:)
Cheers