views:

200

answers:

3

Hi, I'm new at objective-c and stuck with a problem. Is it possible to take an argument of a function to use as some variable names?

For example, say I have a bunch of image: aPic1, aPic2, bPic1, bPic2, cPic1, cPic2, and I want to create an action so that every time when a button is clicked, the view controller will hide Pic1 and display Pic2, depending which button is clicked.

- (void) performAction:(NSMutableString *) text
{
    [text appendString:@"Pic1"].hidden = YES;    //I wanna hide textPic1, which is a UIImageView
    [text appendString:@"Pic2"].hidden = NO;     //I wanna show textPic2, which is also a UIImageView
}

I know I should not use NSString or NSMutableString in this case. Anyone has any idea how I can achieve my objective with this kind of function? Thanks.

A: 

You could store all your subviews in a dictionary:

NSMutableDictionary *viewsByName = [[NSMutableDictionary alloc] init];

[viewsByName addObject:aPic1 withKey:@"aPic1"];
[viewsByName addObject:aPic2 withKey:@"aPic2"];
[viewsByName addObject:bPic1 withKey:@"bPic1"];
[viewsByName addObject:bPic2 withKey:@"bPic2"];

And then:

- (void) performAction:(NSString *) text
{
    ((UIView *)[viewsByName objectWithKey:[NSString stringWithFormat:@"%sPic1",text]]).hidden = YES;
    ((UIView *)[viewsByName objectWithKey:[NSString stringWithFormat:@"%sPic2",text]]).hidden = NO;
}
Philippe Leybaert
Few little additions if nobody doesn't mind.As for using tags - it's better not to use the actual numbers but to define constants for tags (i.e. TAG_IMAGEVIEW_PIC1).As for using dictionary - it's better not use mutable dictionaries for storing immutable data; another important thing is not to forget to release this dictionary in viewDidUnload along with the views.
Ivan Karpan
+2  A: 

Hello Anthony!

Yes you can. (c) :)

For the solution I suggest to work you will need to be able to access (set/get) your variables via methods (easily done using properties or writing your own setters and getters).

Here's an example:

- (void)performAction:(NSMutableString *)text {
    [(UIImageView *)[self performSelector:NSSelectorFromString([text stringByAppendingString:@"Pic1"])] setHidden:YES];
    [(UIImageView *)[self performSelector:NSSelectorFromString([text stringByAppendingString:@"Pic2"])] setHidden:NO];
}

As for properties I actually thought about simply giving you a sample code to get start using this great feature of Objective-C ASAP, which I will do. Though I'm not sure about going deep into this topic because it may require too much of Internet paper, so that's why after the sample code I'll also add a few links for further reading.

@interface AClass : NSObject {
    // Here's where you declare variables
    NSObject *objectForInternalUseWeWantToBeRetained;
    id linkToObjectUsuallyNotRetained;
    int nonObjectVariable;
    BOOL aVariableWithARenamedGetter;
}

// And here's where their properties are declared
@property (nonatomic, retain) NSObject *objectForInternalUseWeWantToBeRetained;
@property (nonatomic) id linkToObjectUsuallyNotRetained;
@property (nonatomic, assign) int nonObjectVariable;
@property (nonatomic, assign, getter=renamedVariableGetter) BOOL aVariableWithARenamedGetter;


@end


@implementation AClass

// Here we command the machine to generate getters/setters for these properties automagically
@synthesize objectForInternalUseWeWantToBeRetained, linkToObjectUsuallyNotRetained, nonObjectVariable, aVariableWithARenamedGetter;

// But you can implement any of the getters/setters by yourself to add some additional behaviour
- (NSObject *)objectForInternalUseWeWantToBeRetained {
    // Some additional non-usual stuff here

    // And after that we do the getters job - return the variables value
    return objectForInternalUseWeWantToBeRetained;
}

// And of course we don't forget to release all the objects we retained on dealloc
- (void)dealloc {
    [objectForInternalUseWeWantToBeRetained release];

    [super dealloc];
}


@end

// And here's where their properties are declared
@property (nonatomic, retain) UIImageView *testPic1;
@property (nonatomic, retain) UIImageView *testPic2;


@end

Warning: I ran through the suff very quickly. Here's a nice tutorial at CocoaCast blog - Properties in Objective-C 2.0, which I think might be a good starting point. BTW they provide a lot of learning materials (podcasts, screencasts, etc) so browsing their site further might be useful. And of course the main place to learn all about Objective-C and Cocoa is official documentation, here's where it is about properties.

Ivan Karpan
`valueForKey:` does the same thing ;)
Dave DeLong
But I was first! :D There are so many ways to do this... We didn't even mention getting the same results via NSInvocation. o_O
Ivan Karpan
Thanks Ivan for your help. This solves my problem. But as you mentioned declaring properties, I've always wondered how to choose the correct properties to declare for each of my variable. (Obviously my reading is severely insufficient :p) Grateful if you could give me some guides. Thanks.
Anthony Chan
+1  A: 

This is possible, but in a roundabout way. You can make the ivars @properties on your class, and then access them via:

id myIvar = [self valueForKey:[text appendString:@"Pic1"]];
[myIvar setHidden:YES];

Or you can go lower in the runtime and use these methods:

#import <objc/runtime.h>

id myIvarValue = nil;
[text appendString:@"Pic1"];
Ivar theIvar = object_getInstanceVariable(self, [text UTF8String], &myIvarValue];
[myIvarValue setHidden:YES];
Dave DeLong