Creating a UIImageView using an NSString - objective-c

I have to create a number of UIImageViews based on values stored in an NSString. The value that is stored will become the name for my UIImageView, each one will be created individually of course.
So to keep things simple my question is, can one create a UIImageView based on the value stored within an NSString?
Rough Example:
-(UIImageView)createMyFruitViews:(NSString *)fruit
{
NSString *fruit = #"";
UIImageView *fruitImage [fruit value]; //<-- made up for example purposes.
return fruitImage;
}
If this is not possible, could you please suggest a way around this?
FYI I've read through the forums too, the only thing that comes close is How to use NSSstring to instantiate a UIImageview; however I don't understand the answer and I am not sure that it can apply to what I need.

Try using UIImageView *fruitImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:fruit]];

I'm not quite sure I understood what you need... as far as I can tell, you have the name of an image on a NSString object, right?
Lets say you have an array of strings, each string representing the name of an image:
NSArray *myImageNames = [NSArray arrayWithObjects:#"image1.png", #"image2.png", #"image3.png", nil];
Then you'll create your imageViews using these images:
for (NSString *imageName in myImageNames) {
UIImageView *myImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:imageName]];
[self.view addSubview:myImageView];
[myImageView release]; // If you're not using ARC
}
If I didn't get exactly what you need, please let me know.

Related

Is there a way to set the same image to many UIimageViews?

I'm working with an image heavy iOS app and I found myself typing almost the same line again and again:
...
A016.image = [UIImage imageNamed:img21];
A017.image = [UIImage imageNamed:img21];
A018.image = [UIImage imageNamed:img21];
...
Now I ask you: is there a way where I could store the UIImageViews names in an Array or something?
Only to beautify my very ugly code.
/John
Yes, you can put the UIImageViews in an array and put it in a for.
UIImageView * imageView1;
UIImageView * imageView2;
UIImageView * imageView3;
NSArray * imageViewsArray = [NSArray arrayWithObjects:imageView1,imageView2,imageView3,nil];
for (UIImageView * currentImageView in imageViewsArray) {
currentImageView.image = [UIImage imageNamed:img21];
}
Of course you can simplify something like that. But it's not entirely clear what the context is exactly.
If you have all your image views in an array you could do something like this.
// Assume an NSArray called imageViews exists with all the UIImageView instances in it.
for (UIImageView *imageView in imageViews) {
imageView.image = [UIImage imageNamed:img21];
}
If your image views aren't in an array already and are actually called A016, A017 etc., then I'd recommend you change your code design. Something like this is never a good idea. It results in bad, difficult to maintain code. If this is some kind of table of images, try putting the image views in an array in the first place.
That being said, there are ways to put variables like that in an array. If they are declared as #properties or ivars you can could do something like this.
NSMutableArray *imageViews = [NSMutableArray arrayWithCapacity:20];
for (int i = 0; i < 20; i++) {
NSString *variableName = [NSString stringWithFormat:#"A0%d", i];
UIImageView *imageView = [self valueForKey:variableName];
[imageViews addObject:imageView];
}
After that you can save the array as an ivar and do the same thing as above.
A more hardcoded version would be to simply put the image views into an array yourself:
NSArray *imageViews = [NSArray arrayWithObjects:..., A016, A017, A018,..., nil];
But I really recommend not using indexed variable names like that.

Objective-C: Image Management between classes

I am trying to create a model with multiple images in a factory model style. I have one class that handles the individuals, one class that handles the group of individuals and a ViewController.
testImage = [[UIImageView alloc] initWithFrame:CGRectMake(250, 500, 30, 30)];
testImage.image = [UIImage imageNamed:#"myImage.png"];
testImage.animationDuration = 1.5;
testImage.contentMode = UIViewContentModeCenter;
[self.view addSubview:testImage];
http://jcdeveloperworld.blogspot.com/2009/07/iphone-game-tutorial-part-1.html -- Thanks
That code works when it is just in the viewController, and now I am trying to make the individuals keep track of their own image. So i put the
testImage = [[UIImageView alloc] initWithFrame:CGRectMake(250, 500, 30, 30)];
testImage.image = [UIImage imageNamed:#"myImage.png"];
testImage.animationDuration = 1.5;
testImage.contentMode = UIViewContentModeCenter;
[self.view addSubview:testImage];
in a separate class and then tried to display it from my viewController. It is my understanding that I can't just tell the viewController to display something from a separate class.
flock *newFlock = [[flock alloc] init];
[newFlock makeFlock];
NSMutableArray *tempFlock = [[NSMutableArray alloc] init];
tempFlock = newFlock.theFlock;
individualsClass *tempIndividual = [[individualsClass alloc] init];
tempIndividual = [tempFlock objectAtIndex:0];
UIImageView *tempImage = [[UIImageView alloc] initWithFrame:CGRectMake(250, 500, 30, 30)];
tempImage = tempIndividual.individualImage;
[self.view addSubview:tempImage];
I also tried it without all the copying, but the dot notation started to get in the way because I'm accessing properties of objects in an NSMutableArray (which seems absurdly difficult in objective C). I could use some help in figuring that out too
ie.
flock.[theFlock.individualImage.image objectAtIndex:1] //Doesn't work
I am kind of new to objective C, so perhaps I'm attacking this problem wrong. This is being done for an iPad app
It's not clear what you're trying to do, but you're definitely doing a lot of stuff you don't need to. Consider these lines of your code:
NSMutableArray *tempFlock = [[NSMutableArray alloc] init];
tempFlock = newFlock.theFlock;
The first line declares a variable named tempFlock of type NSMutableArray *. Then it creates and initializes an empty NSMutableArray and assigns it to tempFlock. The second line then assigns newFlock.theFlock to tempFlock, overwriting the only reference to the array you created in the first line. You can just say this:
NSMutableArray *tempFlock = newFlock.theFlock;
Anyway, the correct syntax for your last block is this:
[flock.theFlock objectAtIndex:1].individualImage.image
So maybe this is what you want to do:
[self.view addSubview:[flock.theFlock objectAtIndex:1].individualImage];
Also, flock and individualsClass are not good class names in Objective-C. Flock and Individual might be better names.
And it's confusing that flock instances have a property named theFlock. It looks like theFlock is just an array of individuals, so a better name for the property would probably be individuals.
If all the "dot" syntax is causing problems with understanding just don't use them, they are just an alternate syntax for method invocation.
[myInstance value] is the same as myInstance.value, which can be viewed as a simple substitution.
Also avoiding long compound statements can help understanding, instead use one or more intermediate well named variables. Trust the compiler to optimize them.
So, as #rob writes:
[flock.theFlock objectAtIndex:1].individualImage.image
the equivalent could be:
[[[[flock theFlock] objectAtIndex:1] individualImage] image]
Broken into multiple statements:
tempFlock = [[flock theFlock] objectAtIndex:1];
tempIndividual = [tempFlock individualImage];
image = [tempIndividual image];

Create multiple UITextFields programmatically using a for loop

Brand new to coding; been utilizing stackoverflow religiously for months; first time asking a question; please be gentle.
I'm trying to create a series of UITextFields programmatically using a for loop. The fields should have names like "pax1name", "pax2name", "pax3name", etc.
The piece I'm missing is how to take a string and make it the name of a textField, changing the name of the textField each time the for-loop executes.
Here's my code, but maybe I'm going about this the wrong way? Thank you in advance!
// set up the names textfields
for (int i = 0; i < 7; i++) {
NSString *fieldName = [[NSString alloc] initWithFormat:#"pax%iname", (i + 1)];
// I can't figure out what goes here to create a UITextField with the name of fieldName
textField = [[UITextField alloc] initWithFrame:CGRectMake(15, (15 + (i * 40)), 400, 40)];
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.font = [UIFont systemFontOfSize:15.0];
textField.autocorrectionType = UITextAutocorrectionTypeNo;
textField.clearButtonMode = UITextFieldViewModeWhileEditing;
textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
[namesViewController addSubview: textField];
[fieldName release];
[textField release];
}
Normally you use the UIView property tag for that. Use [textField setTag:<youCustomTag>] in your loop to set the value, e.g. your variable i. Please note that tag expect an NSUInteger and not an NSString.
To access the correct text field afterwards you'd call [[namesViewController view] viewWithTag:<yourCustomTag>].
BUT, is it really necessary to create multiple text fields for your view controller? There might be a more elegant solution by creating just one single text field and setting the tag-property on demand when the user taps a row. I don't know if that would work for you.
I think you've been going the wrong way about this. UITextField has no property called "name". To identify a control, you can use its tag property. See this code:
for (int i = 0; i < 7; i++) {
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(...)];
textField.tag = i + 1;
...
}
When you say the name of the textfield I'm presuming you mean the variable name rather than setting the text that is displayed. I.e. you want to create the variables in a loop, but later be able to reference them individually by name.
In that case, you can't do what you want to do. What you can do is stick them in an array for handy access later on.
NSMutableArray *paxNameFields = [[NSMutableArray alloc] init]; // before your loop
[paxNameFields addObject: textField]; // inside the loop
[paxNameFields objectAtIndex: 5]; //sometime later use the 6th field
Or if you just want to be able to identify which UITextField you're passed into a delegate callback later on, you can set/check the tag property.
UITextFields don't HAVE names. You're probably coming from HTML-world, where these things are basically a big hash of name-value pairs. Not like that in Cocoa Touch. As #Florian Mielke says, they each have an int .tag property, which is probably what you want to set.

How to add UIImages to an NSMutableArray, and change the images later?

I am making a simple game that requires that I draw multiple UIImages in many different places. My problem here is that I need to add the UIImages to an NSMutableArray, and access them later. Using NSStrings to represent the images (such as for paths) will not work here, so I need to know how to change the images for every UIImage in the array.
My code is as follows (at least, for accessing the NSMutableArray). The NSMutableArray is declared in my .h file, and is initialized in a different method.
for (int a = 0; a <= [theArray count]; a ++) {
// I make a UIImage, which I will draw later
UIImage *theImage = [theArray objectAtIndex:a];
// then I do the drawing
}
This works fine. My problem is that I cannot figure out how to change a particular object in the NSMutableArray. How can I do this?
By the way, I am adding the UIImages to the NSMutableArray with the following code.
+ (void) createCarWithImage:(NSString*)theImageName {
UIImage *anImage= [UIImage imageNamed:theImageName];
[theArray addObject:anImage];
}
I think you want to use this method:
- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject
e.g.:
[theArray replaceObjectAtIndex:4 withObject:someOtherImage];
Just modify each UIImage in the NSMutableArray as is, you only have a pointer to the actual data. That is, regardless of what pointer you use to change the data, the data is changed for every pointer.
Additionally, you can also iterate over your UIImages with:
for (UIImage *img in theArray)
{
//send messages to img
}
Answer to Comment
You can modify the UIImage at index 4 by:
UIImage *image = [theArray objectAtIndex:4];
//send messages to image

Proper Memory Management for Objective-C Method

I'm programming an iPhone app and I had a question about memory management in one of my methods. I'm still a little new to managing memory manually, so I'm sorry if this question seems elementary.
Below is a method designed to allow a number pad to place buttons in a label based on their tag, this way I don't need to make a method for each button. The method works fine, I'm just wondering if I'm responsible for releasing any of the variables I make in the function.
The application crashes if I try to release any of the variables, so I'm a little confused about my responsibility regarding memory.
Here's the method:
FYI the variable firstValue is my label, it's the only variable not declared in the method.
-(IBAction)inputNumbersFromButtons:(id)sender {
UIButton *placeHolderButton = [[UIButton alloc] init];
placeHolderButton = sender;
NSString *placeHolderString = [[NSString alloc] init];
placeHolderString = [placeHolderString stringByAppendingString:firstValue.text];
NSString *addThisNumber = [[NSString alloc] init];
int i = placeHolderButton.tag;
addThisNumber = [NSString stringWithFormat:#"%i", i];
NSString *newLabelText = [[NSString alloc] init];
newLabelText = [placeHolderString stringByAppendingString:addThisNumber];
[firstValue setText:newLabelText];
//[placeHolderButton release];
//[placeHolderString release];
//[addThisNumber release];
//[newLabelText release];
}
The application works fine with those last four lines commented out, but it seems to me like I should be releasing these variables here. If I'm wrong about that I'd welcome a quick explanation about when it's necessary to release variables declared in functions and when it's not. Thanks.
Yes, you need to release them, but you need them just a little longer than beyond the end of your function.
The solution is called autorelease. Just replace release with autorelease and the objects stay around until the program gets back to the runloop.
When the program gets back there, everybody interested in one of the objects should have sent a retain message to it, so the object will not be deallocated when released by the NSAutoreleasePool.
edit actually, looking at your code, there's a lot more wrong with it. E.g. this:
UIButton *placeHolderButton = [[UIButton alloc] init];
placeHolderButton = sender;
doesn't make sense. First you allocate an object, then assign (a pointer to) it to variable placeHolderButton. That's fine.
Then you assign sender to that same variable. The reference to the object you just created is now lost.
Not sure if I get what you want, but this would be better:
-(IBAction)inputNumbersFromButtons:(id)sender {
UIButton *placeHolderButton = sender; // this is still a little useless, but ok
int i = placeHolderButton.tag;
NSString *addThisNumber = [NSString stringWithFormat:#"%i", i];
NSString *placeHolderString = firstValue.text;
NSString *newLabelText = [placeHolderString stringByAppendingString:addThisNumber];
[firstValue setText:newLabelText];
}
No allocs, so no releases necessary. The strings returned by those functions are already added to the autoreleasepool, so they will be deallocated automatically (if needed).
Well. Release them when you are done with them. The sooner the better. Some objects are tricky if you are new to memory management.
Release them in the dealloc method then.
The auto release pool can be handy, some people might disagree according to the performance issues.
you need to release anything containing the word new, alloc/init or copy.
also, you don't need to alloc/init this:
UIButton *placeHolderButton = [[UIButton alloc] init];
placeHolderButton = sender;
another way of doing this is:
UIButton *placeHolderButton = (UIButton *)sender;
in your version, it is allocating an instance with a retain count of +1, but you are immediately replacing the reference, so there is no way of releasing the memory later.
you are creating a lot of instances with alloc/init, and then replacing their references with autoreleased instances.
you could use
NSString *placeHolderString = [placeHolderString stringByAppendingString:firstValue.text];
instead of
NSString *placeHolderString = [[NSString alloc] init];
placeHolderString = [placeHolderString stringByAppendingString:firstValue.text];
which is again replacing a manually managed instance created on the first line, with an autoreleased instance on the second.
infact you could replace every alloc/init in this with the factory method and not have to deal with memory at all in it as they would be autoreleased instances.
-(IBAction)inputNumbersFromButtons:(id)sender {
//cast sender as a UIButton to suppress compiler warning, and allow us to reference it as placeholder button
UIButton *placeHolderButton = (UIButton *) sender;
int i = placeHolderButton.tag;
NSString *addThisNumber = [NSString stringWithFormat:#"%i", i];
[firstValue setText:[firstValue.text stringByAppendingString:addThisNumber]];
}
If you look at the class docs for NSString, any method with a + next to it(ie +stringWithString:(NSString *)string) is a class method, don't use these methods on a reference after you have called alloc/init on it.
I find it puzzling that you use alloc/init on a UIButton.
I always use the factory methods, e.g.
UIButton* aButton = [UIButton buttonWithType:UIButtonTypeCustom];
This returns an autoreleased button which I immediately add to its intended parent view.
Can't confirm it right now, but it looks as if the SDK caches UIButton instances and performs some optimizations behind the scenes. Every time I tried to retain a UIButton ivar, performance has degraded (especially when there is many sub views on screen)