Variable IBOutlet name? - iphone

Is it possible to have a variable outlet name?.
For example you have 10 labels (perhaps seats on bus). each has an outlet, seat1 seat2 etc.
Is it possible to have a for loop
that concatenates #"seat" to the increment integer. So that I can access seat1, seat2 outlet without having to specify it individually.
This doesn’t work but makes it a bit clearer what I am trying to achieve.
int i;
for (i = 0; i < [seatarray count]; i++)
{
[#”seat” stringByAppendingString[ i stringValue]] = #””;
}

Starting iOS4 you can use IBOutletCollection which allows to connect multiple instances to a single outlet which represents an array of objects, e.g. IBOutletCollection which can store UILabels only:
#property (nonatomic, retain) IBOutletCollection(UILabel) NSArray *seats;

It might be easier to simply create the array yourself at load time:
self.seatarray = [NSArray arrayWithObjects:seat1, seat2, ..., seatN, nil];

You should be able to do that with key-value coding, something like (untested code)
for (int i = 0; i != 10; ++i) { [self setValue:#"foo" forKey:[#"seat" stringByAppendingFormat:#"%d", i]]; }

Related

Iterate through controls in iPhone

i have 9 IBOutlets for imageView named imageView1,imageView2,....
i have to assign first object of array to imageView1 & second object to imageView2,.....
Now my question is- is there any way to iterate through the property name
example-
for(int i=0;i<[randomizedArray count];i++)
{
NSString *imageViewName=[NSString stringWithFormat:#"%#%i",#"imageView",i];
imageViewName.image=[appDelegate.splittedImageArray ObjectAtIndex:i];
}
that means it automatically assign value as
imageView1.image=[appDelegate.splittedImageArray ObjectAtIndex:i];
imageView2.image=[appDelegate.splittedImageArray ObjectAtIndex:i];
The closest you could get to something like that without changing the IBOutlets would be this:
NSArray *imageViews = #[imageView1,imageView2,imageView3, ...];
for(int i=0; i<[randomizedArray count]; i++) {
[[imageViews objectAtIndex:i] setImage:[appDelegate.splittedImageArray objectAtIndex:i]];
}
But there is a better solution - IBOutletCollection
You can define a property like this:
#property (nonatomic, retain) IBOutletCollection(UIImageView) NSArray *imageViews;
And connect all of your imageViews like so:
Then you will have an array containing all of your UIImageViews, and you can use the above code without having to declare such an array manually...
dont think it complexly. This is very simple. put tag for the imageviews like tag 1 for imageview1, 2 for imageview2 and so on. Then run a for loop and pick the object and assign to the array. Thats all.
Like assume you put tag from 1 to 7 (don't put duplicate tag or 0 for any of your views)
NSMutableArray *arr = [[NSMutableArray alloc] init];
for(int ii = 1; ii<=7; ii++){
UIImageView *imgView = (UIImageView *)[self.view viewWithTag:ii];
[arr addObject:imgView];
}
yourArray = arr;
[arr release];//if your array is a property otherwise no need to release.
Hope this will help you.
use NSClassFromString
for(int i=0;i<[randomizedArray count];i++)
{
NSString *imageViewName=[NSString stringWithFormat:#"%#%i",#"imageView",i];
Class theClass = NSClassFromString(imageViewName);
theClass.image=[appDelegate.splittedImageArray ObjectAtIndex:i];
}
One way I have used to do this . Created the array of IBOutlets so you can iterate through it and assign the corresponding image.
for(int i=0;i<[randomizedArray count];i++)
{
UIImageView *imageView=[imageOutlets objectAtIndex:i];
UIImage *image=[images objectAtIndex:i];
imageView.image=image;
}

nsobject dealloc never called

I create an object in each iteration of a for loop. However the dealloc function is never called. Is it not supposed to be released at each iteration? I am using ARC and I have NSZombies deactivated. I don not see either any circular reference. Running the memory leak instruments from xcode it does not show any leaks, however the pointers memory of the class are never freed and the dealloc call never done. Any idea why this could happen?
Thank you!
for(int i=0; i<10; i++)
{
//calculate the hog features of the image
HogFeature *hogFeature = [self.image obtainHogFeatures];
if(i==0) self.imageFeatures = (double *) malloc(hogFeature.totalNumberOfFeatures*sizeof(double));
//copy the features
for(int j=0; j<hogFeature.totalNumberOfFeatures; j++)
self.imageFeatures[i*hogFeature.totalNumberOfFeatures + j] = hogFeature.features[j];
}
The HogFeature class declaration looks like this:
#interface HogFeature : NSObject
#property int totalNumberOfFeatures;
#property double *features; //pointer to the features
#property int *dimensionOfHogFeatures; //pointer with the dimensions of the features
#end
and the implementation:
#implementation HogFeature
#synthesize totalNumberOfFeatures = _totalNumberOfFeatures;
#synthesize features = _features;
#synthesize dimensionOfHogFeatures = _dimensionOfHogFeatures;
- (void) dealloc
{
free(self.features);
free(self.dimensionOfHogFeatures);
NSLog(#"HOG Deallocation!");
}
#end
Finally, the call to obtainHogFeatures inside the UIImage category looks like:
- (HogFeature *) obtainHogFeatures
{
HogFeature *hog = [[HogFeature alloc] init];
[...]
return hog;
}
You might want to enclose the inner loop with an #autoreleasepool { ... } which tells the compiler when to do the disposal, otherwise the pool will only be emptied when control returns to the main loop.
for (i = 0; i < 10; i++) {
#autoreleasepool {
...
}
}
As pointed out by CodeFi in the comments:
This will create a new autoreleasepool for each iteration of the loop, which would destroy each object after the iteration is completed, but would make the program do more work. If you don't mind all the objects hanging around until after the loop is completed, you would put the #autoreleasepool outside of the outer loop
#autoreleasepool {
for (i = 0; i < 10; i++) {
...
}
}
The reason the objects are sticking around is because they aren't being released. I don't see the declaration of self.imageFeatures - is this an array? If the features are being put in to an array, they won't be released as long as they remain in the array or the array itself isn't released.
I'm a little confused by the use of the C malloc and (attempted) free calls. There may very well be a motivation here I'm not aware of, but, given what you have provided, here is how I would write this, and I'd be surprised if the deallocs aren't triggered as expected:
NSMutableArray *features = [[NSMutableArray alloc] init];
for (int i = 0; i < 10; i++)
{
NSArray *hogFeatureArray = [[self image] obtainHogFeatures];
for (HogFeature *feature in hogFeatureArray)
{
[features addObject:hogFeature];
}
}
[self setImageFeatures:features];
The imageFeatures property is:
#property (nonatomic, retain) NSMutableArray *imageFeatures;
Assuming you've put all your hog feature instances into this imageFeatures array, they will be retained by that imageFeatures array. In order to observe your dealloc in action, one of two things needs to happen: You either need to remove a hog feature from the array, or you need to release the array itself (this would be done by setting the pointer to nil):
[self setImageFeatures:nil] // Previously assigned array now released
[[self imageFeatures] removeAllObjects]; // Works alternatively

access string names using variables in FOR statement

is is possible to access objects using variables in a FOR statement?
Say i have declared:
UIImageView *UIImageView0;
UIImageView *UIImageView1;
UIImageView *UIImageView2;
and i have 3 objects in an array and i call a FOR statement if x in the array is equal to 2 i want it to add the value of x to the UIImageView name like UIImageView1 etc
I have tried:
for (int x=0; x<[theArray count]; x++) {
UIImageView[x].image = etc....
}
but it gives me a error on UIImageView[x]
subscript requires size of interface 'UIImageView'
any ideas? or is it even possible with a UIImageView?
Thanks
You don't have three elements in an array, though; you have three independent variables with similar names. If you created an actual array, containing the values of the three variables, then you could use the for loop -- and in fact, the syntax would be just as you've shown (using the actual name of the array variable, of course.)
You could say
UIImageView * views[3] = {UIImageView0, UIImageView1, UIImageView2};
and then use, for example, views[i].image in your loop.
In order to put your UIImageView into an array you need to create an instance NSMutableArray (for instance)
The above code does not show any array, instead you have three ivars
UIImageView *UIImageView0;
UIImageView *UIImageView1;
UIImageView *UIImageView2;
and to access those you would use the name, not an array.
If you however put them into an NSMutableArray you can access them using
NSMutableArray array = [[NSMutableArray alloc]
initWithObjects:UIImageView0, UIImageView1, UIImageView2, nil];
[array objectAtIndex:i ]; // where i is 0,1 or 2
...
[array release];
You can put your UIImageView to another array, and get the UIImageView from that array.
NSArray *imagesArray = #[imageView0, ...]
for(size_t i = 0; i<theArray.count; i++)
{
UIImageView *imageView = [imagesArray objectAtIndex:i];
}
Or you can use the "tag" property of UIView like:
UIImageView *image0 = ...;
image0.tag = 100; //or 0 or something else
[self.view addSubview:image0];
And then get the UIImageView by tag in your FOR statement:
for(size_t i = 0; i<theArray.count; i++)
{
UIImageView *imageView = [self.view viewWithTag:100+i];
}

Trying to Concatenate Object names in Objective-C

I know I can concatenate a variable name using stringwithformat, but is it possible to concatenate an object name? I'm not having any luck working around this one.
image+1.hidden = YES; for example.
If I wanted to loop through that, say 10 times, how would I create the 'image+1' part?
Thanks for any help.
I don't think that it is possible to concatenate object names in objective c, but you could create an array of images, and then reference each image like
image[0].hidden = YES;
That would fit the for loop. You could also add the images (I assume that they are UIImages) to an NSArray, then loop through like so:
NSArray* arrayOfImages;
for(UIImage* image in arrayOfImages)
{
image.hidden = YES;
}
Add the objects to an NSArray or NSMutableArray. Then loop through the array to set each object's properties.
For the purposes of discussion mainly, you can use key-value coding to set a property by its name. So, supposing you had instance, an instance of a class that provides the properties image1, image2 and image3 then you could perform:
for(int x = 1; x < 4; x++)
{
// produce the name of the property as an NSString
NSString *propertyName = [NSString stringWithFormat:#"image%d", x];
// use key-value coding to set the property
[instance setValue:someValue forKey:propertyName];
}
For the full list of accessor methods that compliant classes export, see the NSKeyValueCoding Protocol Reference. NSObject implements NSKeyValueCoding, and all properties declared as #property and implemented as #synthesize are compliant, as are any other properties with suitable accessors.
As already noted in the other answers, when what you want is an ordered list of objects so that you can do something with each in turn, either a C-style array or an NSArray is the correct way to proceed, with an NSArray being preferred for style reasons.
NSArray *array = [[NSArray alloc] initWithObjects:image1, image2, image3, image4, image5, image6, image7, image8, image9, image10, nil]; // or use NSMutableArray
for (int x = 0; x < 10; x++) {
((UIImage*)[array objectAtIndex:x]).hidden = YES;
}

Retrieve NSNumber From Array

I am relatively new to Objective C and need some array help.
I have a plist which contains a Dictionary and an NSNumber Array, with more arrays to
be added later on.
NSMutableDictionary *mainArray = [[NSMutableDictionary alloc]initWithContentsOfFile:filePath];
NSArray *scoresArray = [mainArray objectForKey:#"scores"];
I need to retrieve all the values from the array and connect them to 10 UILabels which
I've set up in interface builder. I've done the following to cast the NSNumber to a String.
NSNumber *numberOne = [scoresArray objectAtIndex:0];
NSUInteger intOne = [numberOne intValue];
NSString *stringOne = [NSString stringWithFormat:#"%d",intOne];
scoreLabel1.text = stringOne;
This seems a very long winded approach, I'd have to repeat the 4 lines above ten times to retrieve all the array values. Could I use a for loop to iterate through the array with all of the values converted to Strings at the output?
Any info would be greatly appreciated.
// create NSMutableArray* of score UILabel items, called "scoreLabels"
NSMutableArray *scoreLabels = [NSMutableArray arrayWithCapacity:10];
[scoreLabels addObject:scoreLabel1];
[scoreLabels addObject:scoreLabel2];
// ...
NSUInteger _index = 0;
for (NSNumber *_number in scoresArray) {
UILabel *_label = [scoreLabels objectAtIndex:_index];
_label.text = [NSString stringWithFormat:#"%d", [_number intValue]];
_index++;
}
EDIT
I'm not sure why you'd want to comment out _index++. I haven't tested this code, so maybe I'm missing something somewhere. But I don't see anything wrong with _index++ — that's a pretty standard way to increment a counter.
As an alternative to creating the scoreLabels array, you could indeed retrieve the tag property of the subviews of the view controller (in this case, UILabel instances that you add a tag value to in Interface Builder).
Assuming that the tag value is predictable — e.g., each UILabel from scoreLabel1 through scoreLabel10 is labeled with a tag equal to the values of _index that we use in the for loop (0 through 9) — then you could reference the UILabel directly:
// no need to create the NSMutableArray* scoreLabels here
NSUInteger _index = 0;
for (NSNumber *_number in scoresArray) {
UILabel *_label = (UILabel *)[self.view viewWithTag:_index];
_label.text = [NSString stringWithFormat:#"%d", [_number intValue]];
_index++;
}
The key to making that work is that the tag value has to be unique for the UILabel and must be something you can reference with -viewWithTag:.
The code above very simply assumes that the tag values are the same as the _index values, but that isn't required. (It also assumes the UILabel instances are subviews of the view controller's view property, which will depend on how you set up your interface in Interface Builder.)
Some people write functions that add 1000 or some other integer that allows you group types of subviews together — UILabel instances get 1000, 1001, and so on, and UIButton instances would get 2000, 2001, etc.
try using stringValue...
scoreLabel1.text = [(NSNumber *)[scoresArray objectAtIndex:0] stringValue];