Objective-C loop needed - objective-c

I need some help on automating this with a loop (as I have 500+ buttons). The code is bellow. Thank you.
MyButton *button1 = [[MyButton alloc] init];
button1.name = #"One";
button1.controller = self;
button1.image = [NSImage imageNamed:button1.name];
_buttonArray = [[NSMutableArray alloc] init];
[arrayController addObject:button1];
MyButton *button2 = [[MyButton alloc] init];
button2.name = #"Two";
button2.controller = self;
button2.image = [NSImage imageNamed:button2.name];
_buttonArray = [[NSMutableArray alloc] init];
[arrayController addObject:button2];

Better to name the buttons with a pattern like: "Button125", etc.
Example code, not tested:
for (int i=1; i<= 500; i++) {
[MyClass createButtonNumber:i]; // Where MyClass is the class name this code is in.
}
+ (MyButton *)createButtonNumber:(int)number {
MyButton *button = [MyButton new];
button.name = [NSString stringWithFormat:#"Button%03i", number];
button.controller = self;
button.image = [NSImage imageNamed: button.name];
[arrayController addObject:button];
return button; // Just incase it is needed.
}
Note: The following code repeated for each button makes no sense and has been left out of the example code.
_buttonArray = [[NSMutableArray alloc] init];

for (NSInteger i = 1; i <= 500; ++i) {
MyButton *button = [[MyButton alloc] init];
button.name = ...; // Needs a method to convert from i to corresponding English words
button.controller = self;
button.image = [NSImage imageNamed:button.name];
[arrayController addObject:button];
}
You need an algorithm to convert from i to English words (e.g 1 to "One", 2 to "Two" etc). This can be done with an NSNumberFormatter with numberStyle set to NSNumberFormatterSpellOutStyle, see this for more info.
You still needs 500+ images named according to the buttons' names.

It's just a guess, but UITableView and UITableViewCell might be what you need. I can think of no sane reason to use 500 UIButtons.

Related

Constraint spacing UILabel in For Loop

I have a small problem and hope someone can help me solve it ... I searched the net and made some attempts, but I could not solve my problem.
I created a FOR loop that plays a specified number of labels obtained through an array, as you can see from the code that I posted below ...
Now my problem is how to insert constraint programmatically. I need that between a label and the other (horizontal) there is a specific space.
Example:
if I label 4 I would like these would take around the horizontal space is in the iPhone display SE both iPhone 7 Plus ..
So my question is how do I set a specific space between each label and pass in the FOR loop?
CGFloat padding = 0;
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:#"INFO UNIVERSITARIE",#"INFO GENERALI", #"TROVA SEDI", nil];
for (NSInteger i = 0; i < array.count; i ++) {
NSString *valueText = [array objectAtIndex:i];
UILabel *label = [[UILabel alloc] init];
label.frame = CGRectMake(padding *i, 0, 50, 30);
label.text = [NSString stringWithFormat:#"%#", valueText];
label.textColor = [UIColor whiteColor];
label.font = [UIFont fontWithName:#"HelveticaNeue" size:12];
[label sizeToFit];
[_baseView addSubview:label];
padding = label.frame.size.width;
label.translatesAutoresizingMaskIntoConstraints = NO;
}
Researching this, I remembered that the UIStackView is our new friend, designed specifically for this problem.
NSArray *array = #[ #"INFO UNIVERSITARIE",#"INFO GENERALI", #"TROVA SEDI" ];
NSMutableArray *labels = [NSMutableArray array];
for (NSString *string in array) {
UILabel *label = [[UILabel alloc] init];
label.text = string;
[labels addObject:label];
}
UIStackView *stackView = [[UIStackView alloc] initWithArrangedSubviews:labels];
stackView.axis = UILayoutConstraintAxisHorizontal;
stackView.spacing = 12.0;
stackView.frame = self.view.bounds;
[self.view addSubview:stackView];
Just learned about this myself, but I tried this code and it works nicely.

Duplicating UIView

I can't figure out how could I duplicate UIView with its contents. Or is it even possible?
I have made and UIView with a label and a button inside a .xib file. Now I wish to copy this view n times only with different label text.
I'm trying to do this like this, but such way I only get the last object shown. _view1 is IBOutlet just like _view1Label.
NSMutableArray *Info = [[NSMutableArray alloc]initWithCapacity:number.intValue];
for(int i = 0; i != number.intValue; i++)
{
NSString *number = [NSString stringWithFormat:#"Zona%i ",[[NSUserDefaults standardUserDefaults] stringForKey:#"ObjectNumber"].intValue];
NSString *zona = [NSString stringWithFormat:#"%#%i",number, i+1];
NSString *parinkta = [[NSUserDefaults standardUserDefaults] stringForKey:zona];
_view1Label.text = parinkta;
_view1.hidden = false;
CGRect newrect = CGRectMake(_view1.frame.origin.x, _view1.frame.origin.y + (80 * i), _view1.frame.size.width, _view1.frame.size.height);
_view1.frame = newrect;
[Info addObject:_view1];
}
for(int i = 0; i != number.intValue; i++)
{
UIView *add = [Info objectAtIndex:i];
[self.view addSubview:add];
}
I guess you'll get the idea what I am trying to do, maybe my idea of doing this is totaly wrong, so could anyone help me get on the path on this ?
Load the view multiple times from the nib, adjusting the label contents on each copy you load. This is much easier, shorter, less prone to error than trying to copy the UIView contents in-memory which you're trying to do.
Here's an example of using UINib to access the nib contents:
UINib *nib = [UINib nibWithNibName:#"nibName" bundle:nil];
NSArray *nibContents = [nib instantiateWithOwner:nil options:nil];
// Now nibContents contains the top level items from the nib.
// So a solitary top level UIView will be accessible
// as [nibContents objectAtIndex:0]
UIView *view = (UIView *)[nibContents objectAtIndex:0];
// assumes you've set the tag of your label to '1' in interface builder
UILabel *label = (UILabel *)[view viewWithTag:1];
label.text = #"My new text";
So just repeat the above code for each nib instance you want.
if you wish to show n views then you have to create the view n times, inside the first for loop, you can not place a single view in multiple places
If you are created the first view through code then you can use the following method.
Change your for loop like:
for(int i = 0; i != number.intValue; i++)
{
NSString *number = [NSString stringWithFormat:#"Zona%i ",[[NSUserDefaults standardUserDefaults] stringForKey:#"ObjectNumber"].intValue];
NSString *zona = [NSString stringWithFormat:#"%#%i",number, i+1];
NSString *parinkta = [[NSUserDefaults standardUserDefaults] stringForKey:zona];
UIView *tempView = [[UIView alloc] init];
UILabel *tempLabel = [[UILabel alloc] init];
tempLabel.frame = _view1Label.frame;
tempLabel.text = _view1Label.text;
[tempView addSubview: tempLabel];
tempView.frame = _view1.frame;
_view1Label.text = parinkta;
_view1.hidden = false;
CGRect newrect = CGRectMake(_view1.frame.origin.x, _view1.frame.origin.y + (80 * i), _view1.frame.size.width, _view1.frame.size.height);
_view1.frame = newrect;
[Info addObject:tempView];
}

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!

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 setting an object to a class that is not known

I have an array of view controllers (there are more that I have shown):
..
settings = [[settingsSettingTab alloc] initWithNibName:#"settingsTab" bundle:nil];
other = [[otherSettingTab alloc] initWithNibName:#"otherTab" bundle:nil];
..
NSArray *views = [NSArray arrayWithObjects:settings,other, nil];
I then loop through them and assign some details to them before pushing them:
for (int i = 0; i < views.count; i++) {
...
NSString *className = NSStringFromClass([[views objectAtIndex:i] class]);
Class myClass = NSClassFromString(className);
myClass *subView = (myClass*)[views objectAtIndex:i];
[self.scrollView addSubview:subView.view];
}
How can I assign the right class to the *subView. It worked fine when I had only one type of view in my array and then I just used:
settingTab *subView = (settingTab*)[views objectAtIndex:i];
But now I need to check and use the right one. I have googled the question, but I'm not sure of how I would describe it? (dynamic typing? Duck typing?) Any pointers would be really appreciated.
Thanks
EDIT:
Here is the whole code:
NSArray *titles = [NSArray arrayWithObjects: #"Basics", #"Colours", #"Shapes", #"Settings", #"Other", nil];
basics = [[basicsSettingTab alloc] initWithNibName:#"basicsTab" bundle:nil];
colours = [[colorsSettingTab alloc] initWithNibName:#"colorsTab" bundle:nil];
shapes = [[shapesSettingTab alloc] initWithNibName:#"shapesTab" bundle:nil];
settings = [[settingsSettingTab alloc] initWithNibName:#"settingsTab" bundle:nil];
other = [[otherSettingTab alloc] initWithNibName:#"otherTab" bundle:nil];
NSArray *views = [NSArray arrayWithObjects: basics,colours,shapes,settings,other, nil];
for (int i = 0; i < views.count; i++) {
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * i + 20;
frame.origin.y = 0;
CGFloat newWidth = 280;
CGFloat newHeight = 320;
CGFloat locx = 0;
CGFloat locy = 0;
CGRect panel = CGRectMake(locx, locy, newWidth, newHeight);
frame.size = panel.size;//self.scrollView.frame.size;
//subview.view.backgroundColor = [colors objectAtIndex:i];
NSString *className = NSStringFromClass([[views objectAtIndex:i] class]);
Class myClass = NSClassFromString(className);
myClass *subView = (myClass*)[views objectAtIndex:i];
[subView.view setFrame:frame];
subView.tabTitle.text = [titles objectAtIndex:i];
[subView.view.layer setCornerRadius:5.0f];
[subView.view.layer setMasksToBounds:YES];
subView.delegate = self;
[self.scrollView addSubview:subView.view];
}
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * views.count, self.scrollView.frame.size.height);
pageControl.numberOfPages = views.count;
}
From your edit, we see that you have a property tabTitle on each of your custom view controllers. I would recommend that you create a new UIViewController subclass that implements tabTitle, and use that as the superclass for each of your custom controllers. That way your code only needs to know that they are all a MyTabViewController class (for want of a better class name!). So in your for loop:
MyTabViewController *subview = (MyTabViewController *)[views objectAtIndex:i];
[subview.view setFrame:frame];
[subview.tabTitle setText:[titles objectAtIndex:i]];
// ...
[self.scrollView addSubview:subView.view];
Everything else (view property for example) is defined by UIViewController, from which all your subclasses are descendants.
EDIT
Incidentally, I would be careful about the naming of your objects - your view controllers are not views. In particular, this might cause confusion where you have subview.view. Perhaps more appropriate would be subviewController.view, or even just controller.view?
The properties you are setting are common to all through since they all inherit from UIViewController.
replace:
myClass *subView = (myClass*)[views objectAtIndex:i];
with:
UIViewController *subViewController = (UIViewController *)[views objectAtIndex:i];
Also, do be careful about using the terms "view" and viewController" interchangably. They are not the same thing and can get very confusing/complex when you name things like they are.
If all of them are subclasses of UIViewController, then just use it:
****
frame.size = panel.size;//self.scrollView.frame.size;
//subview.view.backgroundColor = [colors objectAtIndex:i];
UIViewController* subView = (UIViewController*)[views objectAtIndex:i];
[subView.view setFrame:frame];
****
If you are not doing anything special to every view controller, then you just don't need to know exact class of it as long as it is subclass of some known class...
Hope it helps :)