This question already has answers here:
Create multiple numbered variables based on a int
(2 answers)
Closed 10 years ago.
I have some variables like vh1 vh2 vh3 etc.
Is it possible in a for-loop to count with the i variable?
I mean something like for(int i = 1; blablabla) { [[vh + i] setBackGroundColor blablabla];}
Regards
Edit: vh1 etc. are UILabels!!!
While this is possible through introspection, if you have such variables you better put them in an NSArray, and access them with an index.
As other answerers have noted, with the new array syntax you can quite easily construct an array with all your objects in it, but it will keep the old values even if you subsequently change the values of the original ivars. That may or may not be what you are after.
If you are hell-bent on keeping your variables as single objects (as opposed to arrays,) then you can use key-value coding to access them programmatically. Key-value coding is also known as KVC.
The method that does it is valueForKey: and can be used both on self and other objects.
MyClass *obj = ... // A reference to the object whose variables you want to access
for (int i = 1; i <= 3; i++) {
NSString *varName = [NSString stringWithFormat: #"var%d", i];
// Instead of id, use the real type of your variables
id value = [obj valueForKey: varName];
// Do what you need with your value
}
There is more about KVC in the docs.
In the interest of completeness, the reason this direct access works, is because a standard KVC compliant object inherits a class method called accessInstanceVariablesDirectly. If you don't want to support this direct access, then you should override accessInstanceVariablesDirectly so it returns NO.
If you are loading the UILabels from XIB, you can use IBOutletCollection.
Declare property:
#property (nonatomic, strong) IBOutletCollection(UILabel) NSArray *labels;
Now you can link multiple labels in XIB to this property. Then in -viewDidLoad (after loading the XIB), your array is populated and you just use simple for-in:
for (UILabel *label in self.labels) {
label.backgroundColor = ...
}
You can access each values the following code.
UILabel *label1;
UILabel *label2;
UILabel *label3;
NSArray *array = #[label1, label2, label3];
for (int i = 0; i<3; i++) {
[array objectAtIndex:i];
}
Adding values to NSArray is available for initializing it.
If you want to add values later, you can use NSMutableArray.
I modified my code.
UILabel *label1 = [[UILabel alloc] init];
UILabel *label2 = [[UILabel alloc] init];
UILabel *label3 = [[UILabel alloc] init];
NSArray *array = #[label1, label2, label3];
for (int i = 0; i<3; i++) {
UILabel *label = [array objectAtIndex:i];
label.frame = CGRectMake(0, i*100, 150, 80);
label.text = [NSString stringWithFormat:#"label%d", i];
[self.view addSubview:label];
}
Related
I'm trying to put UILabels inside of an NSDictionary, I'm using tags as key, but the problem is, not all of the labels inside of the view is needed, the tags of the UILabels that is needed is also inside of an enum.
So what I want to do is, check the tag if it exist inside of the enum then add it to dictionary with tag as key.
for (NSObject *obj in [self.formView subviews]) {
if ([obj isKindOfClass:[UILabel class]]) {
UILabel *label = (UILabel *)obj;
// Here is where I want to add the check before I do this line
labelDict[[NSString stringWithFormat:#"%d",label.tag]] = label;
}
}
For Future Readers:
If you are also iterating on an NSArray type of object like the code above, you should use the NSArray function enumerateObjectsUsingBlock instead, this is the answer, doesn't it look more pretty:
[self.formView.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj isKindOfClass:[UILabel class]]) {
UILabel *label = (UILabel *)obj;
if ( label.tag >= TEXTFIELDTYPE_MIN_VAL && label.tag <= TEXTFIELDTYPE_MAX_VAL ) {
labelDict[[NSString stringWithFormat:#"%d",label.tag]] = label;
}
}
}];
Objective-C enums are inherited from C enums and cannot be reflected at runtime. Without abusing debug symbols (which would be an overly complicated task for a slow and unreliable result), I believe that it would be impossible to come up with a function that would tell you if an arbitrary value is a member of an arbitrary enum.
One possible workaround would be to create a NSSet that contains all the enum values you have, and check if your label's tag exists within that set. Otherwise, if your enum is sequential, you can check that the tag is between your enum's minimum value and maximum value.
Try this, instead of for loop of all subviews, run for loop of your enum values,
hopefully the enum values are in sequence then only this below code would work:
for(NSInteger tagVal = enum.firstEnum; tagVal <= enum.lastEnum; tagValue++) {
NSObject *obj = [self.formView viewWithTag:tagVal];
if ([obj isKindOfClass:[UILabel class]]) {
UILabel *label = (UILabel *)obj;
// Here is where I want to add the check before I do this line
labelDict[[NSString stringWithFormat:#"%d",label.tag]] = label;
}
}
Try this
if ([[dict allKeys] containsObject:lbl]) {
}
I wan't to add labels (strings from an array) onto buttons with a for loop.
I'm new in objective-c and I don't know how I can fit all the changes into the loop on each iteration.
If there is a better way to do this, please show me. Right now I got this, which only prints the second element in the array out at upper right corner.
for (int i=0; i< sizeof(arrayOfLetters); i++ ) {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(441,11,30,20)];
label.text = [NSString stringWithFormat:#"%#",[arrayOfLetters objectAtIndex:1]];
[self.view addSubview:label];
}
You are close. You want:
for (int i = 0; i < arrayOfLetters.count; i++) {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(441, 11 + i * 25, 30, 20)];
label.text = arrayOfLetters[i];
[self.view addSubview:label];
}
You should also give each label a different frame as I did here. Adjust as needed.
Keep in mind that the sizeof function gives you the size of the variable. Since arrayOfLetters is an object pointer the result will probably be 4. You want the actual count of the array. See the docs for NSArray.
Also, do not needlessly use stringWithFormat:. Only use it when you actually have a string that needs formatting.
I'm trying to store 25 objects in an array
for (int iy=0; iy<5; iy++) {
for (int ix=0; ix<5; ix++) {
TerrainHex *myObject = [[TerrainHex alloc] initWithName:(#"grassHex instance 10000") width:mGameWidth height:mGameHeight indexX:ix indexY:iy];
myObject.myImage.y += 100;
[TerrainHexArray addObject:myObject];
[self addChild:(id)myObject.myImage];
}
}
NSLog(#"Terrain array: %u", [TerrainHexArray count]);
The log is coming back as zero though.
In the .h file I have
#property NSMutableArray *TerrainHexArray;
And in the .m file I have..
#synthesize TerrainHexArray;
I just tried what someone suggested below, which is..
NSMutableArray *TerrainHexArray = [[NSMutableArray] alloc] init];
But it's just giving me a warning saying expected identifier.
It's almost certain that TerrainHexArray does not exist when you're doing the addObject calls and the NSLog. You say you tried adding the alloc/init after someone suggested it, which indicates you don't understand object management in Objective-C.
I'd suggest you step back, find a book on Objective-C, and read at least the first few chapters (up through the discussion of alloc/init et al) before you attempt any more coding.
Incidentally, it's standard C++/Objective-C coding practice (except in Microsoft) to use identifiers with a leading lower case character for instance names, reserving leading caps for types/class names.
What is TerrainHexArray? It looks like a class name, not an instance of an array. If you create a mutable array, then you can add the items to the array.
NSMutableArray *hexArray = [[NSMutableArray] alloc] init];
for (int iy=0; iy<5; iy++) {
for (int ix=0; ix<5; ix++) {
TerrainHex *myObject = [[TerrainHex alloc] initWithName:(#"grassHex instance 10000") width:mGameWidth height:mGameHeight indexX:ix indexY:iy];
myObject.myImage.y += 100;
[hexArray addObject:myObject];
[self addChild:(id)myObject.myImage];
}
}
NSLog(#"Terrain array: %u", [hexArray count]);
This is a basic example that I know can be simplified, but for testing sake, I would like to do this in such a way. I want to set a variable based on an appending string (the variables "cam0" and "pos1" are already declared in the class). The appending string would essentially be an index, and i would iterate through a loop to assign cameras (cam0, cam1..) to different positions (pos0, pos1..).
cam0 is defined as an UIImageView
pos1 is defined as a CGRect
This works for a NSString Variable named coverIndex:
NSString* text = [[NSString alloc] initWithString:#""];
NSLog(#"%#",(NSString *)[self performSelector:NSSelectorFromString([text stringByAppendingString:#"coverIndex"])]);
The correct string that I set for coverIndex was logged to the Console.
Now back to my UIImageView and CGRect. I want this to work.
NSString* camText = [[NSString alloc] initWithString:#"cam"];
NSString* posText = [[NSString alloc] initWithString:#"pos"];
[(UIImageView *)[self performSelector:NSSelectorFromString([camText stringByAppendingString:#"0"])] setFrame:(CGRect)[self performSelector:NSSelectorFromString([posText stringByAppendingString:#"1"])]];
My error is "Conversion to non-scalar type requested"
This is the only way I found to do this sort of thing (and get the NSLog to work), but I still believe there is an easier way.
Thank you so much for any help :)
Use KVC, it's an amazing piece of technology that will do just what you want:
for (int index = 0; index < LIMIT; index++) {
NSString *posName = [NSString stringWithFormat:#"pos%d", index];
CGRect pos = [[self valueForKey:posName] CGRectValue];
NSString *camName = [NSString stringWithFormat:#"cam%d", index];
UIImageView *cam = [self valueForKey:camName];
cam.frame = pos;
}
One way you can do this would be to create your cameras in a dictionary and use those special NSStrings to key in to it. Like,
NSMutableDictionary *myCams;
myCams = [[myCams alloc] init];
[myCams addObject:YOUR_CAM0_OBJECT_HERE forKey:#"cam[0]"];
[myCams addObject:YOUR_CAM1_OBJECT_HERE forKey:#"cam[1]"];
NSString camString = #"cam[0]"; // you'd build your string here like you do now
id theCamYouWant = [myCams objectForKey:camString];
Let's say I have several lines of code to clarify specific settings on a given UILabel variable:
numberMarkings[selectedBoxX][selectedBoxY][selectedSquareX][selectedSquareY][selectedNoteX][selectedNoteY].text = #"derp";
numberMarkings[selectedBoxX][selectedBoxY][selectedSquareX][selectedSquareY][selectedNoteX][selectedNoteY].center.x = 5;
numberMarkings[selectedBoxX][selectedBoxY][selectedSquareX][selectedSquareY][selectedNoteX][selectedNoteY].center.y = 3;
I'd like to setup a reference variable (&$varname in PHP) for this massive array index-specified variable in Obj-C. What is the best way to do this?
Just use a pointer:
UILabel* label = numberMarkings[selectedBoxX][selectedBoxY][selectedSquareX][selectedSquareY][selectedNoteX][selectedNoteY];
label.text = #"derp";
label.center.x = 5;
label.center.y = 3;
Since you are not writing into the array, you don't need anything fancier than that. If you were to overwrite the value in the array, then you could use a pointer to a pointer:
UILabel** label_in_array = &numberMarkings[selectedBoxX]/* ... */[selectedNoteY];
// Write to the label
UILabel* label = *label_in_array;
label.text = #"derp";
// Write to the array
[label release];
*label_in_array = [[UILabel alloc] init]; // Now numberMarkings[][][...][]
// holds a new uilabel object.