How to pass ivar into a function and set it without losing the reference to the original object - objective-c

I am passing an ivar (NSMutableArray) into some method. I was expecting that if I modify the object inside the function, it would be reflected outside the function, but in this case I need to set the object; something like the following:
- (void) someMethod:(SMResponseObject *)response onData:(NSMutableArray *)imAnIvar {
imAnIvar = [response objects];
//Some other stuff
}
But I noticed that the memory reference of imAnIvar inside the function changes when I set it, and given that, the actual ivar doesn't change. I understand that the problem is that I'm changing the reference of the object inside the method, so it stops pointing to the ivar and then it points to some other random memory direction.
I thought about one solution to this problem, and it can be to ensure that the ivar is not nil before calling the function and do something like this:
- (void) someMethod:(SMResponseObject *)response onData:(NSMutableArray *)imAnIvar {
NSMutableArray *data = [response objects];
[arrayForTableView removeAllObjects];
for(id element in data){
[imAnIvar addObject:element];
}
//Some other stuff
}
So I use the original object instead of setting it directly. The problem is that in order for this to work I need to ensure that the ivar is not nil, which I think is not clean, because I'll need to do something like this on every call to the method:
if(!_ivar){
//alloc it
}
So my question is: Is there a way to force the local scope variable to point to the original variable even if I'm setting it? if not, is there any cleaner way to make this work?

Do you mean this?
- (void)setFoo:(SomeClass **)objPtr
{
*objPtr = someOtherObject;
}
// call it as:
SomeClass *foo = someObject;
NSLog(#"Before: %#", foo);
[self setFoo:&foo];
NSLog(#"After: %#", foo);

Why not use a getter for the array so that you need not check for the array being nil while using it?
-(NSMutableArray *)iAmAnIvar {
if(_iAmAnIvar == nil) {
_iAmAnIvar = [NSMutableArray array];
}
return _iAmAnIvar;
}
And when you have to set a value to the array, as you mentioned in your question, you could use
[self.iAmAnIvar removeAllObjects];
[self.iAmAnIvar addObject:someObj];

I believe you can use the - (id)copy; function of NSObject
so your code might look like this:
- (void)someFunction:(NSString *)someArg
{
NSString *str = [someArg copy];
}

Related

Using typecast for (void *) in Objective C

i am using the addToolTipRect: method to set a tooltip rect
- (NSToolTipTag)addToolTipRect:(NSRect)aRect owner:(id)anObject userData:(void *)userData
and method stringForToolTip: to obtain string value for tooltip.
- (NSString *)view:(NSView *)view stringForToolTip:(NSToolTipTag)tag point:(NSPoint)point userData:(void *)data
However the above functions work fine if i send something like
[self addToolTipRect:someRect owner:self userData:#"Tool tip string"];
But doesn't work when i send the following string. Error: BAD_ACCESS
const NSString * tooltipStr = #"Tool tip string";
[self addToolTipRect:someRect owner:self userData:tooltipStr];
In both the cases, the stringForToolTip looks like:
- (NSString *)view:(NSView *)view stringForToolTip:(NSToolTipTag)tag point:(NSPoint)point userData:(void *)data
{
id obj = (id)data;
NSString * str=nil;
if ([obj isKindOfClass:[SomeClass class]]) //This is my system defined class and works fine
{
SomeClass * someClassObj = (SomeClass *) data;
str = someClassObj.title;
}
else if([obj isKindOfClass:[NSString class]])
str = (NSString*)obj;
return str;
}
NOTE: In the stringForToolTip: method I also want to check for some other class example [obj isKindOF:[SomeClass class]] and i don't want to assert that value. The problem here is just in getting the string value by proper cast but I can't figure out how! Please tell me where I am going wrong?
edit:
What should be the right way to get the String value for tooltip in that case? should the point or tag be considered?
(void *) is not an object pointer.
That #"Tool tip string" worked was by coincidence based on the fact that is is a compile-time constant with a (essentially) permanent allocation and permanent address.
But in the code:
const NSString * tooltipStr = #"Tool tip string";
[self addToolTipRect:someRect owner:self userData:tooltipStr];
tooltipStr is an object that is kept in memory by a strong reference (retain count > 0). Since userData: does not handle objects it does not make a strong reference (does not increase the retain count) so it is released, will disappear soon becoming invalid.
Notes from the documentation:
The tooltip string is obtained from the owner. The owner must respond to one of two messages, view:stringForToolTip:point:userData: or description, use the latter. Note that NSString responds to description so you can pass an NSString for the value of owner. So, what you want is: [self addToolTipRect:someRect owner:tooltipStr userData:NULL];. There is still an issue that something must hole a strong reference to the NSString instance.
You can: [self addToolTipRect:someRect owner:#"Tool tip string" userData:NULL];
Probably the best way to go is to pass self as owner and NULL as data and implement the delegate method: view:stringForToolTip:point:userData: in the class.

Objective-C dynamic properties at runtime?

Is it possible to create an Objective-C class that can have an arbitrary number of dynamic properties at runtime?
I want to be able to call mySpecialClass.anyProperty and intercept this inside my class to be able to provide my own custom implementation that can then return an NSString (for instance) at runtime with raising an exception. Obviously this all has to compile.
Ideal would be if I could refer to my properties using something similar to the new literal syntax, e.g. mySpecialClass["anyProperty"].
I guess in a way I want to create something like a dynamic NSDictionary with no CFDictionary backing store, that executes 2 custom methods on property getting and setting respectively, with the property name passed in to these accessor methods so they can decide what to do.
There are at least two ways to do this.
Subscripting
Use objectForKeyedSubscript: and setObject:forKeyedSubscript:
#property (nonatomic,strong) NSMutableDictionary *properties;
- (id)objectForKeyedSubscript:(id)key {
return [[self properties] valueForKey:[NSString stringWithFormat:#"%#",key]];
}
- (void)setObject:(id)object forKeyedSubscript:(id <NSCopying>)key {
[[self properties] setValue:object forKey:[NSString stringWithFormat:#"%#",key]];
}
Person *p = [Person new];
p[#"name"] = #"Jon";
NSLog(#"%#",p[#"name"]);
resolveInstanceMethod:
This is the objc_sendMsg executed by the runtime for all methods:
If you look at the bottom, you have the opportunity to resolveInstanceMethod:, which lets you redirect the method call to one of your choosing. To answer your question, you need to write a generic getter and setter that looks-up a value on a dictionary ivar:
// generic getter
static id propertyIMP(id self, SEL _cmd) {
return [[self properties] valueForKey:NSStringFromSelector(_cmd)];
}
// generic setter
static void setPropertyIMP(id self, SEL _cmd, id aValue) {
id value = [aValue copy];
NSMutableString *key = [NSStringFromSelector(_cmd) mutableCopy];
// delete "set" and ":" and lowercase first letter
[key deleteCharactersInRange:NSMakeRange(0, 3)];
[key deleteCharactersInRange:NSMakeRange([key length] - 1, 1)];
NSString *firstChar = [key substringToIndex:1];
[key replaceCharactersInRange:NSMakeRange(0, 1) withString:[firstChar lowercaseString]];
[[self properties] setValue:value forKey:key];
}
And then implement resolveInstanceMethod: to add the requested method to the class.
+ (BOOL)resolveInstanceMethod:(SEL)aSEL {
if ([NSStringFromSelector(aSEL) hasPrefix:#"set"]) {
class_addMethod([self class], aSEL, (IMP)setPropertyIMP, "v#:#");
} else {
class_addMethod([self class], aSEL,(IMP)propertyIMP, "##:");
}
return YES;
}
You could also do it returning a NSMethodSignature for the method, which is then wrapped in a NSInvocation and passed to forwardInvocation:, but adding the method is faster.
Here is a gist that runs in CodeRunner. It doesn't handle myClass["anyProperty"] calls.
You're asking different things. If you want to be able to use the bracket syntax mySpecialClass[#"anyProperty"] on instances of your class, it is very easy. Just implement the methods:
- (id)objectForKeyedSubscript:(id)key
{
return ###something based on the key argument###
}
- (void)setObject:(id)object forKeyedSubscript:(id <NSCopying>)key
{
###set something with object based on key####
}
It will be called everytime you use the bracket syntax in your source code.
Otherwise if you want to create properties at runtime, there are different ways to proceed, take a look at NSObject's forwardInvocation: method, or look at the Objective-C Runtime Reference for functions to dynamically alter a class...
Guillaume is right. forwardInvocation: is the way to go. This answer gives some more details: method_missing-like functionality in objective-c (i.e. dynamic delegation at run time)
This has even more details: Equivalent of Ruby method_missing in Objective C / iOS
And these are some other lesser known Obj-C features that might help you: Hidden features of Objective-C
Enjoy!

Creating objects in a loop, but ivar / instance variable not keeping state

I have a method that creates a dictionary from NSJSONSerialization class. I then enumerate the json, and create objects to store state for each instance.
- (void)fetchedData:(NSData *)responseData {
NSError* error;
NSDictionary *json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error];
NSArray *moviesJson = [json objectForKey:#"movies"];
for(NSDictionary *element in moviesJson)
{
RABMovie *myMovie = [[RABMovie alloc] initWithJson:element];
// RABMovie *myMovie = [RABMovie new];
// myMovie.json = element;
[_myMovieNames addObject: myMovie];
myMovie = nil;
}
[self.movieTableView reloadData];
}
Problem: I want to create my object by passing in element in the allocator, however when I do this, my UITTableView rows all contain the same movie data. It is always the last item, leading me to believe I am working with only one memory address, and the last update affects the whole collection.
If I uncomment the code to use the json as a property instead of a alloc param, I no longer have the issue and all works well. I've also tried creating a completely new NSDictionary via a deep copy of element to no avail.
Does someone know why this is happening? BTW, I am using ARC. -Thanks for the time.
Edit: Added more code. I've included a property movieName to illustrate how I use the ivar _json.
#implementation RABMovie
NSDictionary *_json;
- (id) initWithJson: (NSDictionary*) jsonAsDictionary
{
if (self = [super init])
{
_json = jsonAsDictionary;
}
return self;
}
- (NSString*) movieName
{
return [_json objectForKey:#"title"];
}
I think you meant to declare _json as an instance variable. Instead it's a globally visible (at least within that class) variable - not 100% sure on the scoping rules, but regardless, it's not an instance variable - it's a single variable shared by all instances! Try this instead:
#implementation RABMovie {
NSDictionary *_json;
}
/* ...rest of class */
#end
Putting it inside the curly braces after the #implementation directive makes it an instance variable. Hope this helps!
EDIT: Do you have a property called json on RABMovie already? Then you can skip the instance declaration altogether and the compiler will generate the an instance variable for you. That's probably happening already actually, which is why it works when you go through the property - it's accessing the ivar rather than the "global".

Issue with NSMutableArray visibility / retain

Alright so I am a little new to the NSMutableArray class and I think I am missing something obvious. I have an object pass a NSMutable Array to my window controller like so in my.m:
summaryWindow = [[SummaryWindowController alloc] init];
[summaryWindow setGlobalStatusArray:globalStatusArray];
I have the receiver method in the summaryWindow object as so:
-(void)setGlobalStatusArray:(NSMutableArray *)myArray
{
if ([myArray count] >0) {
if (globalStatusArray) {
[globalStatusArray release];
}
globalStatusArray = [[NSMutableArray alloc] initWithArray:myArray];
NSLog(#"Summary Window Init with new array: %#",globalStatusArray);
I see the NSLog no problem, and in that same object (summaryWindow) I have the following method:
- (NSMutableArray *)getGlobalStatusArray
{
return globalStatusArray;
}
Now I have globalStatusArray declared in my .h file as
NSMutableArray *globalStatusArray;
So shouldn't This be retained because I am using: initWithArray?
When I try to access this value in an another IBAction method:
- (IBAction)refreshButtonClicked:(id)sender
{
NSLog(#"The user has clicked the update button");
[ aBuffer addObjectsFromArray: globalStatusArray];
NSLog(#"Buffer is currently:%#",aBuffer);
[tableView reloadData];
}
The NSMutable array is null
2011-08-18 10:40:35.599 App Name[65677:1307] The user has clicked the update button
2011-08-18 10:40:35.600 App Name[65677:1307] Buffer is currently:(
)
I have tried using my own method to get the value i.e. [ self getGlobalStatusArray] to but I am missing something huge. FYI aBuffer is also declared in my .h ,
As albertamg noted, that looks like an empty array rather than nil, and a released object doesn't magically become nil under normal circumstances anyway.
This smells strongly of two different objects. Try logging self in your methods and see if one instance is getting the array and another is interacting with the UI.
This code isn't doing anything useful:
if ([myArray count] >0) {
if (globalStatusArray) {
[globalStatusArray release];
}
globalStatusArray = [[NSMutableArray alloc] initWithArray:myArray];
If the count of the old array is zero, it's leaking the actual array object. If the count is not zero, then it's releasing it properly. Just do the release and don't bother counting.
Are you sure there's actually something in myArray?
joe

Obj-c, how do I create function which will populate an NSDictionary and gain a value from the function?

I've been reading about NSArrays and NSDictionaires and I think I need the later. I'm trying to populate an object from a small database table. So I can access the string values via a record id. I have to do this several times so putting it into an object makes sense.
I have the basics...
- (void)viewDidLoad {
// WORKING START
NSMutableDictionary *dictCategories = [[NSMutableDictionary alloc] init];
[dictCategories setValue:#"Utility" forKey:#"3"];
[dictCategories setValue:#"Cash" forKey:#"5"];
NSString *result;
result = [dictCategories objectForKey:#"3"];
NSLog(#"Result=%#", result);
// WORKING END
// Can't get this bit right, current error Request for member
// 'getCategories' in something not a structure or union
NSMutableDictionary *dictCategories2 = self.getCategories;
NSLog(#"Result2=%#", [dictCategories2 objectForKey:#"5"]);
[super viewDidLoad];
}
-(NSMutableDictionary*)getCategories {
NSMutableDictionary *dictCategories = [[NSMutableDictionary alloc] init];
[dictCategories setValue:#"Utility" forKey:#"3"];
[dictCategories setValue:#"Cash" forKey:#"5"];
return dictCategories;
}
you are calling the method wrong,try [self getCategories]
You're not being clear on what isn't working, but a few things that are obviously wrong (JonLOo might be spot on though) ...
Firstly. You're using the wrong methods, or at least there's a better one -- setValue:forKey: should/could be setObject:forKey: instead. This might be one of the reasons for your issue.
Secondly. You're over-allocating and not releasing properly. dictCategories2 in your viewDidLoad will vanish into the void and bring with it the allocated memory for dictCategories defined in the getCategories method. An easy standard fix for this is to change
NSMutableDictionary *dictCategories = [[NSMutableDictionary alloc] init];
in getCategories into
NSMutableDictionary *dictCategories = [NSMutableDictionary dictionary];
It will be autoreleased using the latter method by the system.
Thirdly. You want to read up on #property. Instead of getFoo, setBar, the Ob-C standard is to use #properties to (pre)define setters and getter methods. You can then override these to populate default data into your methods when appropriate. You also (probably) want to store the dictionary in your interface as an instance variable, rather than letting it be deallocated all the time. Example of a #property implementation that does this:
#interface foo {
NSMutableDictionary *ingredients;
}
#property (nonatomic, retain) NSMutableDictionary *ingredients;
#end
// ....
#implementation foo
#synthesize ingredients;
// ...
// the #synthesize command above will create getter and setter methods for us but
// we can override them, which we need to do here
- (NSMutableDictionary *)ingredients
{
if (ingredients != nil) {
// we've already got an ingredients variable so we just return it
return ingredients;
}
// we need to create ingredients
ingredients = [[NSMutableDictionary alloc] init];
[ingredients setObject:#"foo" forKey:#"bar"]
return ingredients;
}
In the viewDidLoad method (or anywhere else where you think ingredients might not have been initialized yet), you would do e.g.
NSMutableDictionary *dict = self.ingredients;
Anywhere else you can opt to use just ingredients without self, but if it's nil, your method will never be called, and you will get nil thrown at you.
This is useful in many cases, and is necessary if we want to ever read or write the ingredients variable from outside of our class. It's outside of what you're asking about, but I brought it up because you're trying to do something similar with self.getCategories.
Hope that helps.