Objective C Function Question - objective-c

Hey guys, check this out. I have a function that treats for me a string. No matter what it does, i just want to knwo if is possible to this function return the result for the place that it was executed. I mean, check this:
[self priceFormat:#"1"];
priceLabel.text = price;
-(void) priceFormat:(NSString*)price {
price = #"2";
}
I just want to my function treats the string and return it to the same place that it was executed.
Thanks!

Three ways to do this
Way one, using a pointer
- (void)priceFormat:(NSString **)price {
*price = #"2";
}
Wat two, using an instance variable
What you might want instead is an ivar. In the interface (most often the h file) of your class:
NSString *price;
and in the implementation (the m or mm file):
- (void)priceFormat:(NSString *)price {
price = #"2";
}
I have created an example of this here.
If you want the price to be available to other objects as well (not just self), you might want to create a property for it and synthesize it. Then use self.price = #"2"; instead. More on this here: http://MacDeveloperTips.com/objective-c/objective-c-properties-setters-and-dot-syntax.html
Just make sure you make it a copy property (NSString in use)!
Way three using return
Note, that you can also return directly from a method:
- (NSString *)priceFormat:(NSString *)price {
return #"2";
}
priceLabel.text = [self priceFormat:#"1"];

Related

Setting and using ivars or passed parameters in setter functions

I know this sounds like a really silly and stupid question but is there any difference in using the target ivars or the passed parameters when making extended setter functions like in:
- (void)setText:(NSString)text {
_text = text;
self.label.text = text; // VS
self.label.text = _text;
}
Is there any functionality or efficiency difference between the two assignments for self.label.text?
No, there is no difference between using the ivar and the passed parameter in your example.
However, there is a difference if you use the accessor:
// These are the same
self.label.text = text;
self.label.text = _text;
// This will call the getter
self.label.text = self.text
As an illustration of the difference, consider if we had a custom (silly) getter:
- (NSString *)text
{
return #"Hello";
}
In this case, the literal string #"Hello" would be returned regardless of the value of text.

Function calls with pointers in Objective C

I'm a newbie in Objective C, used to write C. Anyway, I have a class called DataProcessing:
DataProcessing.m
...
- (BOOL)MyStringTweaker:(NSString *)strIn : (NSString *)strOut {
if(some_thing) {
strOut = [NSString stringWithFormat:#"I_am_tweaked_%#", strIn];
return true;
}
else
return false;
}
...
From the AppDelegate (OSX Application)
AppDelegate.m
...
NSString *tweaked;
DataProcessing *data_proc = [[DataProcessing alloc] init];
if([data_proc MyStringTweaker:#"tweak_me":tweaked])
NSLog([NSString stringWithFormat:#"Tweaked: %#", tweaked]);
else
NSLog(#"Tweaking failed...");
...
This doesn't work, *tweaked is NIL after the call to MyStringTweaker...
What am I missing?
Objective-C, like C, is pass-by-value only. You need to change your method signature to be:
- (BOOL)MyStringTweaker:(NSString *)strIn : (NSString **)strOut
and use:
*strOut = [NSString stringWithFormat:#"I_am_tweaked_%#", strIn];
to do the assignment.
Then, where you call it, you need to pass the address of the pointer you want to fill in:
[data_proc MyStringTweaker:#"tweak_me" :&tweaked]
A good explanation is in the comp.lang.c FAQ.
Editorial aside: Why not label the second argument? It looks weird to have it naked like that.

NSString to class instance variable

I am looking for a way to convert from NSString to a class instance variable. For sample code below, say filter is "colorFilter". I want filternameclassinstancegohere to be replaced with colorFilter.
- (void)filterSelected:(NSString *)filter
{
self.filternameclassinstancegohere = ….;
}
While there were good suggested solutions given for this question, I discovered what I needed is the NSClassFromString method. Here is a final implementation:
- (void)filterSelected:(NSString *)filter
{
//self.filternameclassinstancegohere = ….;
self.myViewController = [[NSClassFromString(filter) alloc] initWithNibName:filter bundle:nil];
}
Consider using one NSMutableDictionary instance variable with string keys rather than 40 instance variables.
You can create an arbitrary selector using NSSelectorFromString():
SEL methodName = NSSelectorFromString(filter);
[self performSelector:methodName];
This will call a method colorFilter in your example above.
Would be wise to check with respondsToSelector before calling, too.
If the filter value can only be a small, constant number of things, just use an enumeration and a switch statement:
enum Filter
{
ColorFilter,
FooFilter,
BarFilter
};
- (void)filterSelected:(Filter)filter
{
switch(filter)
{
case ColorFilter:
self.colorFilter = ...;
break;
case FooFilter:
self.fooFilter = ...;
break;
case BarFilter:
self.barFilter = ...;
break;
}
}
If the set of filter values is large and could change frequently, then you could also use Key-Value Coding. It's more complicated but more flexible.

How to log arguments in runtime?

I created a new function to log every method from a class in runtime.
The problem that I have is in this line :
id value = va_arg(stackFrame, id);
Doesn't convert the type of object inside the arguments.
Any idea on what I'm doing wrong? Is there another way to do this?
void DebugArguments ( id self, SEL _cmd,...)
{
id receiver = self;
SEL receiverSelector = _cmd;
va_list stackFrame;
va_start(stackFrame, _cmd);
NSMethodSignature *signature
= [receiver methodSignatureForSelector:receiverSelector];
NSUInteger count = [signature numberOfArguments];
NSUInteger index = 2;
for (; index < count; index++)
{
id value = va_arg(stackFrame, id);
if (!value)
{
NSLog(#"Arguments: %#",value);
}
}
va_end(stackFrame);
}
I call the function InitDebug from a class like this : -
(void)MyTest:(NSString *)string {
InitDebug(self, _cmd); } I hope
to log the Argument string from the
method MyTest.
In the future, it is helpful to show all the code.
In any case, you can't do that; when you call InitDebug(...), you are pushing a new frame onto the stack and va_arg() will decode in the context of that frame, not the surrounding frame. Nor can you "go up the stack" and start grubbing about in the arguments of the calling frame as there is no guarantee that the calling frame is even preserved at that point.
If you really want to do something like this, you would probably want to subclass NSProxy and use it is a proxy between the caller and whatever object you want to log. You could then leverage the built-in forwarding mechanism of Objective-C to muck about with the arguments.

convert id into enum using objective-c

I am trying to implement a simple method, however I am still quite a newbie on objective-c.
I have this simple method which is trying to convert from an id to a specific value in enum, if matched.
This is the enum
typedef enum {
DXTypeUnknown = 0,
DXDatasource = 1,
DXGroup = 2
} DXPropertyType;
And this is the relevant method:
-(DXPropertyType)typeFromObject:(id)_type {
int _t = [_type intValue];
switch (_t) {
case DXDatasource:
return [NSNumber numberWithInt:DXDatasource];
case DXGroup:
return [NSNumber numberWithInt:DXGroup];
default:
return [NSNumber numberWithInt:DXTypeUnknown];
}
}
The very first check I would to implement is if the id can be converted to an int, then see if it falls in the two relevant categories group or datasource, or return a default value if not. Could you tell me if the switch/case I implemented is a proper solution or not ?
I would like also this method not to causing crash of an application, so what could be advisable to check, keeping in mind that in any case the default value is to be returned.
thanks
[EDIT]
I forgot to say that this value is going to be stored in a field of a NSManagedObject, which by CoreData restriction can be an NSNumber, so probably there's a better solution instead of an enum.
It might be a good idea to include this code to check if the id can be used:
if (![_type respondsToSelector:#selector(intValue)])
return nil;
However, if you'll always pass a NSNumber go ahead and declare the method as:
- (DXPropertyType)typeFromObject:(NSNumber)_type;
In your code, you're returning a NSNumber. I don't think that's what you really
want, as you'd be doing nothing with the NSNumber passed. Return the enum
item:
-(DXPropertyType)typeFromObject:(id)_type {
if (![_type respondsToSelector:#selector(intValue)])
return nil;
int _t = [_type intValue];
switch (_t) {
case DXDatasource:
return DXDatasource;
case DXGroup:
return DXGroup;
default:
return DXTypeUnknown;
}
}
And then this can be simplified to:
- (DXPropertyType)typeFromObject:(id)_type {
if ([_type respondsToSelector:#selector(intValue)]) {
int t = [_type intValue];
DXPropertyType property_t;
if (t >= 1 && t <= 2)
property_t = t;
else
property_t = DXTypeUnknown;
return property_t;
}
return nil;
}
Your switch statement is a good solution and will not cause a crash.
However, your method returns a NSNumber when it expects a different return. I suggest changing the method to
-(NSNumber)typeFromObject:(id)_type
You specify that your method returns an enum, but you return objects. So either return the enum values or specify the return type to be NSNumber *.
A different solution could be using singleton objects instead of an enum, but that's probably more work than it's worth. Think [NSNull null].