I have a Objective C function that takes any type of object by reference. But when i pass a NSMutableArray My function does not recognise It - iphone

I have a function That takes by reference any kind of object
-(BOOL)RemoteCall:(id**)DataClass;
in the implementation i use [*DataClass isMemberOfClass:[NSMutableArray class] to find out the type of the object. The problem is it does not work with NSMUtableArrays Does anybody have a solution to this problem ? Here is the relevant code:
Implementation:
-(BOOL)RemoteCall:(id**)DataClass
{
if([*DataClass isMemberOfClass:[NSMutableArray class] ] == YES)
{
NSMutableArray * SW =(NSMutableArray *)*DataClass;
//do something with SW
DataClass= (id**)SW;
return TRUE;
}
}
Any help and I mean anything at all will be appreciated, I'm stuck.
Method Call:
NSMutableArray * channelArray = [[NSMutableArray alloc]init]
Services * serv = [[Services alloc] init];
return [serv RemoteCall:&channelArray];

Pass by reference in Objective-C is almost never the right way.
There are a number of problems with that code.
(id**) is a pointer to a pointer to a pointer to an object. Probably not at all what you want.
YES and NO are BOOL return types; not TRUE
there is no reason in that code to be returning something by reference.
method names start with lower case letters. Arguments do, too.
There will never be an instance of NSMutableArray in an application; just subclasses
You can't tell the difference between a mutable and immutable array in the first place; check for isKindOfClass: or isMemberOfClass: for an NSMutableArray won't do you much good (it is useful, but misleading).
This is better:
-(BOOL)remoteCall: (id) dataThing
{
if([dataThing isKindOfClass:[NSMutableArray class]] == YES)
{
NSMutableArray *swArray = dataThing; // not strictly necessary, but good defensive practice
//do something with swArray
return YES;
}
return NO;
}
To be called like:
NSMutableArray * channelArray = [[NSMutableArray alloc]init]; // you'll need to release this somewhere
Services * serv = [[Services alloc] init];
return [serv remoteCall:channelArray];
Since you don't return a different array in remoteCall:, channelArray's contents will be manipulated by the method and the YES/NO return value.
If there is some reason why the above seemingly won't work for you, please explain why.
Note: The code obviously requires an NSMutableArray if you are going to muck with the contents. The isKindOfClass: could be checking for NSMutableArray or NSArray and it wouldn't matter either way. When using arrays in your code and requiring a mutable array, it is up to you to make sure the data flow is correct such that you don't end up w/an immutable array where you need a mutable array.

If you don't need to reassign your variable, then don't use this. id or NSObject * is just fine and works by reference anyway. id * or NSObject ** would be references. id ** doesn't make sense at all here.
Also, learn naming conventions (like upper/lowercase).

NSArray is a class cluster. That means that every NSArray instance is actually an instance of some subclass. Only isKindOfClass: is useful for class-membership testing with class clusters.
Also... thats horrible code - please accept this:
-(BOOL)remoteCall:(id)dataClass {
if([dataClass isKindOfClass:[NSMutableArray class]]) {
NSMutableArray *sw =(NSMutableArray *)dataClass;
return YES;
}
}
that should work.
Constructive critisism of coding: You need to adhere to coding conventions. Although your code will work... its not brilliant to read and theres a lot of unnecessary *s and such.
Function names should be camel coded with a preceeding lower-case letter as should variable names. Passing (id) into a function doesn't require *s at all. Objects you pass into a function only available throughout the scope of the method anyway and that method doesn't own it, I'm not sure what you're trying to do with all the extra *s, but just treat objects you pass into the method as if you don't own them. :)

As Eiko said before, i'd use just id and not double pointers to ID.
I'm also pretty sure that isMemberOfClass is your Problem. isMember does not check for inheritance, so you're only asking for Top level Classes. isKindOfClass is probably the better choice, as there is no guarantee that Apple doesn't use an internal subclass of NSMutableArray internally. Check the Apple Docs.
i'd write it as such:
-(BOOL)RemoteCall:(id)dataClass
{
if([dataClass isKindOfClass:[NSMutableArray class] ] == YES)
{
NSMutableArray * SW =(NSMutableArray *)dataClass;
//do something with SW
return TRUE;
}
}

Related

Check if something exists in an NSMutableArray

I have an NSMutableArray which can hold several objects. I would like to check if an object exists, and if so, alter it. I was wondering about checking it. I thought this would work:
if ([[[self.myLibrary objectAtIndex:1] subObject] objectAtIndex:1]) // do something
However, this will crash if there aren't any subObjects at index 1.
So I guess the problem is that the above does not return nil if there isn't anything at this Index.
Is there another easy way to check or will I have to count through the array etc.? I know there are other posts on stackoverflow on this, but I haven't found a simple answer yet.
Any explanations / suggestions welcome. Thanks!
No check simply using :
[myArray indexOfObject:myObject];
or
[myArray containsObject:myObject];
These methods check every object using isEqual.
For example:
NSUInteger objIdx = [myArray indexOfObject: myObject];
if(objIdx != NSNotFound) {
id myObj = [myArray objectAtIndex: objIdx];
// Do some alter stuff here
}
If this is a pattern you use a lot, you could add a category to NSArray called something like safeObjectAtIndex:, which takes an index, does the bounds checking internally:
-(id)safeObjectAtIndex:(NSUInteger)index {
if (index >= [self count])
return nil;
return [self objectAtIndex:index];
}
Assuming the object you are using to search with and the actual object in the array are the exact same instance, and not two different objects that are equal according to an overridden isEqual: method, you can do this:
if ([array containsObject:objectToSearchFor]) {
// modify objectToSearchFor
}
If the two objects are different instances which are equal according to isEqual:, you will have to use code like this:
NSUInteger index = [array indexOfObject:objectToSearchFor];
if (index != NSNotFound) {
id objectInArray = [array objectAtIndex:index];
// modify objectInArray
}
NSArray (which is the NSMUtableArray superclass) has lots of methods for finding objects. Have a look at the documentation.
You can either rely on the equals method (e.g. indexOfObject:) or provide a block (e.g indexOfObjectPassingTest:) which is pretty funky.
It's fairly common in Objective C to be using the Mutable version of a class but rely on methods in the non mutable superclass so it's always a good idea when checking the online documentation to look at the superclass.

Objective-C method to nullify object

i have some trouble writing a method in Objective-C to make an object nil. Here is some example :
#interface testA : NSObject
{
NSString *a;
}
#property (nonatomic, retain) NSString *a;
+(testA*)initWithA:(NSString *)aString;
-(void)displayA;
-(void)nillify;
#end
#implementation testA
#synthesize a;
+(testA*)initWithA:(NSString *)aString{
testA *tst=[[testA alloc] init];
tst.a=aString;
return [tst autorelease];
}
-(void)displayA{
NSLog(#"%#",self.a);
}
-(void)nillify{
self=nil;
}
- (void)dealloc {
[a release];
[super dealloc];
}
#end
int main(int argc, char **argv){
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
testA *test=[testA initWithA:#"some test"];
[test displayA];
test=nil;
//[test nillify];
NSLog(#"after setting to nil");
[test displayA];
[pool release];
return 0;
}
Apparently , when I set test object to nil and then call some method on it nothing happens , but if i call nillify instead of directly setting it to nil , displayA method works normally like test object is still there. Is there a workaround for nillify method to function properly ?
Your help is much appreciated !
You can't actually do something like this, because setting 'self' to nil only has any effect within the scope of that method (in your case, 'nilify'). You don't have any actual way to effect the values of pointers located on other parts of the stack or in random places in the heap, for example.
Basically any code that holds a reference to some object is responsible for maintaining and clearing those references itself. If you have some use case where random sections of code may need references to "live" objects of some kind, but where you'd want those object references to go away in response to some external event (maybe a user tracking system or something), you could do something with notifications, but the various modules tracking those "live" objects would still be responsible for listening for notifications and cleaning up references when they received them.
The 'nilify' thing, however, can't possibly work.
You cannot do what you're trying to do. self is just a local reference to an object that actually exists elsewhere. Setting it to nil doesn't mean anything. An object doesn't, in general, own itself, and it certainly doesn't control other objects' references to it. It's up to the owning objects to manage its lifetime.
There are a few things wrong with your code.
First, by convention, class names start with an uppercase letter. Please stick to these naming conventions as it will make it harder for other developers to work with your code (and even confuse you).
Next, your initWithName:... According to the naming conventions, a method with init in its name should be an instance method, not a class method. So either name it newWithName: or turn it into an instance method like this:
-(testA*)initWithA:(NSString *)aString{
self = [super init];
if (!self) return nil;
tst.a=aString;
return self;
}
If you keep it as class method (and name it newWithName:) you should not return a autoreleased object since according to the naming conventions method that start with init... or new... return a retained object. If you do not follow these conventions, the static analyzer will give you "false" warnings and it will become useless for you.
Now for the reason your nillify doesn't work: the self is in fact an argument to a method. Under the hood, your nillify method actually has two arguments that you do not see: the self pointer and the selector pointer. This means, self is actually a variable on the stack. And if you overwrite it, you only overwrite that stack variable but that doesn't influence your test variable which is somewhere else.
As an example, consider a method - (void)foo:(NSString *)bar;. The compiler turns it into the equivalent of the C function (void) foo(id self, SEL _cmd, NSString *bar).

Returning an NSMutableArray from a method...do I release it prior? - iPhone SDK

I have been very confused on how to handle the releasing of an NSMutableArray when I need to return it from a method. I am not even sure if I am suppose to release it or not.
I have the code:
-(NSArray *)methodToCall {
NSMutableArray *mutArray = [[NSMutableArray alloc] initWithCapacity:10];
//Fill the array with stuff here
[mutArray release]; //Am I suppose to have this to keep the memory down?
return mutArray;
}
My question is whether or not I am suppose to have the [mutArray release]; in the code or not. Could someone explain this? I am at a loss and I want to keep my code as clean and leak free as possible.
The caller of your method is going to expect a valid NSArray, but which it doesn't own.
If you release it the way you're doing in your question, you're returning an invalid object (because you've both allocated and released it.) So that's not what you want.
You should "autorelease" the array before returning it. Then you'll be allocating it, but relinquishing ownership (without forcibly releasing it) before returning it. It will be valid until the end of the current event loop when the autorelease pool gets cleaned up, and your caller can retain it or let it go as appropriate:
-(NSArray *)methodToCall {
NSMutableArray *mutArray = [[NSMutableArray alloc] initWithCapacity:10];
//Fill the array with stuff here
return [mutArray autorelease];
}
Your other alternative, since you don't need to keep the reference around either, is to use one of the "autoreleasing" convenience methods to create it in the first place:
-(NSArray *)methodToCall {
// We're not doing an explicit alloc/init here, so...
NSMutableArray *mutArray = [NSMutableArray arrayWithCapacity:10];
// ...no autorelease necessary.
return mutArray;
}
Short answer - No.
As it is now, you are allocating an array and then releasing (freeing) it before the return. So the when you try accessing the return object from your calling method you're going to get a crash.
My suggestion would be to use autorelease or to have the calling method or class ivar be responsible for this array object if it is used often.
An example of the autorelease:
NSMutableArray *mutArray = [[[NSMutableArray alloc] initWithCapacity:10] autorelease];
I also suggest reading the Memory Management from the Developer Documents.
if you go for explicit object allocation by calling alloc and init you are owner of your object, so you are responsible for its object retain value else you do it by implicit you don't need to care about it. it will take care of itself.
-(NSMutableArray *)getArray
{
NSMutableArray *array=[[NSMutableArray alloc] initWithCapacity:10];
//your code
return [array autorelease];
}
in the above code we are the owner of the object so we need to handle its retain count by passing autorelease the autoreleasepool will take care of it.
-(NSMutableArray *)getArray
{
NSMutableArray *array=[NSMutableArray allocWithCapacity:10];
//your code
return array;
}
in the above code we didn't alloc any object we just call class method to define the size of the array.
if you want more details go for the object ownership in Memory management guide from apple library
In general, instead of using alloc/init to create a temporary array, consider using a convenience creation method (+arrayWithCapacity: in this case):
- (NSArray *)methodToCall
{
NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:10];
// Fill the array with stuff here
return mutableArray;
}
Convenience creation methods such as +arrayWithCapacity: return an object that the caller is not responsible for, relieving the calling code of the burden of managing memory. Since the calling code is simply returning the reference rather than storing it, that'll simplify things.

iphone NSString Array

I declared
NSString *dayinfield[43];
and fill it in
-(void)DrawDemo {
dayinfield[2] = #"hallo";
dayinfield[3] = #"test";
// also i can read it
NSLog (#"show: %#",dayinfield[2]);
//works fine
}
but when i like to read its content in another function (same class)
-(void)ReadData
{
NSLog (#"show: %#",dayinfield[2]);
// I get random infos or “EXC_BAD_ACCESS
}
How do I initialize the NSString Array correct so I can reach its content in each of my functions??
Thanks
chris
If you only assign literals to the array elements, this should not be a problem. But if you use other strings, you have to retain the instances manually when using a C array.
By the way: Objective-C methods start with a lowercase letter.
This would happen if you never initialized the array (or the parts of it you are accessing) - if you haven't called -DrawDemo before -ReadData or used different indices than the ones posted here, the array would simply contain garbage values.
Try to initialize the array contents to nil or #"" in your initializer method and see if the problem persists.
Alternatively consider using a suitable Cocoa container.
It's memory is probably being released before your second call. Assuming you have declared dayinfield as an ivar (and the fact that you don't get bad access all the time) your string aren't properly retained.
Initialise the strings like this:
dayinfield[2] = [[NSString alloc] initWithString:#"hallo"];
dayinfield[3] = [[NSString alloc] initWithString:#"test"];
and you should release them after you're class is being deallocated (See Memory Management Guide).
Also, obviously it depends on what you want to do, but it might be easier if you use NSArray instead of C arrays.
What you have in the OP should work although it is an exercise in sheer masochism to use old school C arrays with objects.
I ran this code:
#interface TestClass : NSObject {
NSString *a[1];
}
- (void) drawDemo;
- (void) readData;
#end
#implementation TestClass
- (void) drawDemo{
a[0]=#"A Zero";
a[1]=#"A One";
}//------------------------------------- (void) drawDemo------------------------------------
- (void) readData{
NSLog(#"a[0]=%#,a[1]=%#",a[0],a[1]);
}//------------------------------------- (void) readData------------------------------------
#end
TestClass *tc=[[TestClass alloc] init];
[tc drawDemo];
[tc readData];
... and got this output:
a[0]=A Zero,a[1]=A One
Your problem is elsewhere in your code. There is no compelling reason to use C arrays with objects. You gain nothing and you have to watch them like a hawk to prevent errors.

Using the value of a string to determine the instance of a class

I have a switch statement similar to this one:
switch (number)
{
case 1:
if (imageView1.hidden == NO)
{
imageView1.hidden = YES;
} else
{
imageView1.hidden = NO;
}
break;
case 2:
if (imageView2.hidden == NO)
{
imageView2.hidden = YES;
} else
{
imageView2.hidden = NO;
}
break;
And so forth and so on.
My question is how do I use a string with a value say "imageView1" and use that to access the instance of my imageView class instead of having a different case for each instance of imageView? I know it muse be similar to creating an NSPath from a string or something like that, but I'm just not sure where to look or what it would be called.
Thanks in advance for any help!
I don't disagree with those who are concerned about the design, if this is actually the code. I will assume, however, that you are only posting a generalized version of your question. And since this is an important concept in Objective-C, so we should talk about it.
You can access an object's properties by name using Key Value coding, and the routine -valueWithKey:.
NSString *nameOfView = #"imageView1";
[[self valueForKey:nameOfView] setHidden:YES];
This will, in order, look for a method called -imageView1, an ivar named imageView1 and finally an ivar named _imageView1. This technique is very heavily used in Cocoa, and is important to understand. This is one of the many reasons we name things carefully, and yet another reason that we make accessors that handle memory management for us. Search the docs for "Key-Value Compliance" for more information.
Now for this specific case, I would tend towards something more like JimG's solution, using an NSArray of views, so I can loop through them and turn on or off the ones I want based on their index. But I can imagine a lot of cases where that wouldn't be appropriate, and KVC may be.
Why not put the instances in an NSArray and index into that?
NSArray *views = [NSArray arrayWithObjects: imageView1, imageView2, nil];
NSImageView *iview = [views objectAtIndex: number];
Also, you could consider something like:
iview.hidden = ! iview.hidden;
[Edit: missing asterisks, oops]