I am trying to add a GLKVector3 object into an NSMutableArray. I understand that NSMutableArrays will only accept certain objects so what would be the best way for me too add a GLKVector3 to an array.
Here is a sample of code:
for(id basenormal in [jsnmvtx objectForKey:#"baseNormals"]){
[basenormalsVectorArrays addObject:GLKVector3MakeWithArray(basenormal)];
}
Thanks
The issue is that GLKVector3 is a C-style struct, not an object. So it doesn't know how to respond to retain or release and therefore won't work with an NSArray.
What you can do is wrap each one into an NSValue as that's an object type and it knows how to keep arbitrary C types inside it. It's not especially neat because you're straddling the border between C and Objective-C but e.g.
GLKVector3 someVector;
[array addObject:[NSValue valueWithBytes:&someVector objCType:#encode(GLKVector3)]];
...
GLKVector3 storedVector;
NSValue *value = ... something fetched from array ...;
[value getValue:&storedVector];
// storedVector now has the value of someVector
That'll copythe contents of someVector into the NSValue and then copy them out again into storedVector.
You can use valueWithPointer: and pointerValue if you'd prefer to keep a reference to someVector in your array rather than copying contents, though then you'll need to be careful about manual memory management, so a better solution might be to use NSData as in:
// we'll need the vector to be on the heap, not the stack
GLKVector3 *someVector = (GLKVector3 *)malloc(sizeof(GLKVector3));
[array addObject:[NSData dataWithBytesNoCopy:someVector length:sizeof(GLKVector3) freeWhenDone:YES]];
// now the NSData object is responsible for freeing the vector whenever it ceases
// to exist; you needn't do any further manual management
...
GLKVector3 *storedVector = (GLKVector3 *)[value bytes];
Related
i have one array this array contain Question Objects so here i need to change the positions for array
Question *que=[[Question alloc]init];
que=[myarray objectAtIndex:1];
Question *que1=[[Question alloc]init];
que1=[myarray objectAtIndex:2];
here i need to inter change objects each other some
[que1 setValue: que.name forKey:#"Name"];
[myarray relplaceObjectAtIndex:2 withObject:que1];
is it right way to set value same objectValues
Please guide me hoe can inter change value.
Thanks for advance
There are significant issues with your code here:
This statement:
Question *que = [[Question alloc] init];
Allocates a new Question instance and assigns it to the variable que. When you do:
que = [myarray objectAtIndex:1];
You are overwriting the Question instance that you just allocated, effectively leaking memory (because you never released it). This won't be a problem if you are using ARC but nevertheless it is something to be mindful of because with or without ARC it is pointless. You did this twice, once for que and once for que1. Since you don't actually need to allocate and initialise a new Question instance, you can just do:
Question *que = [myarray objectAtIndex:1];
You obtain a reference to a Question object and assign it to que1. Then you mutate it and want to put it back into the array. This is pointless because the array already holds a reference to the same Question instance that you obtained with objectAtIndex:.
You haven't really explained what you are trying to do. Your entire code basically boils down to:
[[[myarray objectAtIndex:2] setValue:[[myarray objectAtIndex:1] name] forKey:#"Name"];
Your code should work how you intend with what you have shown. Just a few points to be aware of:
You need myarray to be an NSMutableArray
You have a typo here: relplaceObjectAtIndex:2 it should be replaceObjectAtIndex
Arrays start at index 0, which I'm sure you are aware of.
First use NSMutableArray object to hold it not NSArray
then.
you need to understand one main thing you are holding only a pointer to an object. array is managing it. You have created an object before accessing object inside array, dont do that it creates memory leak. You have to access the object from array only.
Question * que1=[myarray objectAtIndex:1];
[que1 retain];
[myarray removeObjectAtIndex:1];
Question * que2=[myarray objectAtIndex:2];
[que2 retain];
[myarray removeObjectAtIndex:2];
its possible you are not using ARC and your array is the only owner of the object. So If you remove object from array the it might release the whole object
[myarray insertObject:que2 atIndex:1];
[myarray insertObject:que1 atIndex:2];
this is a sample to put object in any position.
Read class references NSMutableArray
I'm new to cocoa / objective-c and i'm struggeling with the releases of my objects. I have the following code:
gastroCategoryList = [[NSMutableArray alloc] init];
for (NSDictionary *gastrocategory in gastrocategories) {
NSString *oid = [gastrocategory objectForKey:#"id"];
GastroCategory *gc = [[GastroCategory alloc] initWithId:[oid intValue] name:[gastrocategory objectForKey:#"name"]];
[gastroCategoryList addObject:gc];
}
The analyzer shows me that the "gastrocategory" defined in the for is a potential memory leak. But i'm not sure if i can release this at the end of the for loop?
Also at the following code:
- (NSArray *)eventsForStage:(int)stageId {
NSMutableArray *result = [[NSMutableArray alloc] init];
for (Event *e in eventList) {
if ([e stageId] == stageId) {
[result addObject:e];
}
}
return result;
}
The Analyzer tells me that my "result" is a potential leak. But where should I release this?
Is there also a simple rule to memorize when i should use assign, copy, retain etc. at the #property ?
Another problem:
- (IBAction)showHungryView:(id)sender {
GastroCategoriesView *gastroCategoriesView = [[GastroCategoriesView alloc] initWithNibName:#"GastroCategoriesView" bundle:nil];
[gastroCategoriesView setDataManager:dataManager];
UIView *currentView = [self view];
UIView *window = [currentView superview];
UIView *gastroView = [gastroCategoriesView view];
[window addSubview:gastroView];
CGRect pageFrame = currentView.frame;
CGFloat pageWidth = pageFrame.size.width;
gastroView.frame = CGRectOffset(pageFrame,pageWidth,0);
[UIView beginAnimations:nil context:NULL];
currentView.frame = CGRectOffset(pageFrame,-pageWidth,0);
gastroView.frame = pageFrame;
[UIView commitAnimations];
//[gastroCategoriesView release];
}
I don't get it, the "gastroCategoriesView" is a potential leak. I tried to release it at the end or with autorelease but neither works fine. Everytime I call the method my app is terminating. Thank you very much again!
In your loop, release each gc after adding it to the list since you won't need it in your loop scope anymore:
gastroCategoryList = [[NSMutableArray alloc] init];
for (NSDictionary *gastrocategory in gastrocategories) {
NSString *oid = [gastrocategory objectForKey:#"id"];
GastroCategory *gc = [[GastroCategory alloc] initWithId:[oid intValue] name:[gastrocategory objectForKey:#"name"]];
[gastroCategoryList addObject:gc];
[gc release];
}
In your method, declare result to be autoreleased to absolve ownership of it from your method:
NSMutableArray *result = [[[NSMutableArray alloc] init] autorelease];
// An alternative to the above, produces an empty autoreleased array
NSMutableArray *result = [NSMutableArray array];
EDIT: in your third issue, you can't release your view controller because its view is being used by the window. Setting it to autorelease also causes the same fate, only delayed.
You'll have to retain your GastroCategoriesView controller somewhere, e.g. in an instance variable of your app delegate.
BoltClock's answer is spot-on as to the first part of your question. I'll try to tackle the rest.
Assign is for simple, non-object types such as int, double, or struct. It generates a setter that does a plain old assignment, as in "foo = newFoo". Copy & retain will, as their names imply, either make a copy of the new value ("foo = [newFoo copy]") or retain it ("foo = [newFoo retain]"). In both cases, the setter will release the old value as appropriate.
So the question is, when to copy and when to retain. The answer is... it depends. How does your class use the new value? Will your class break if some other code modifies the incoming object? Say, for example, you have an NSString* property imaginatively named "theString." Other code can assign an NSMutableString instance to theString - that's legal, because it's an NSString subclass. But that other code might also keep its own reference to the mutable string object, and change its value - is your code prepared to deal with that possibility? If not, it should make its own copy, which the other code can't change.
On the other hand, if your own code makes no assumptions about whether theString might have been changed, and works just as well whether or not it was, then you'd save memory by retaining the incoming object instead of unnecessarily making a copy of it.
Basically, the rule, which is unfortunately not so simple sometimes, is to think carefully about whether your own code needs its own private copy, or can correctly deal with a shared object whose value might be changed by other code.
The reason you can release gc after it is added to the gastroCategoryList is that when an object is added to an array, the array retains that object. So, even though you release your gc, it will still be around; retained by the gastroCategoryList.
When you are returning a newly created object from a method, you need to call autorelease. This will cause the object to be released only after the runtime leaves the scope of the calling method, thereby giving the calling method a chance to do something with the returned value.
Note that if your method starts with the word copy or new, then you should not autorelease your object; you should leave it for the calling method to release.
As for copy vs retain vs assign... as a general rule, copy objects that have a mutable version, such as NSArray, NSSet, NSDictionary, and NSString. This will ensure that the object you have a pointer to is not mutable when you don't want it to be.
Otherwise, use retain whenever you want your class to be ensured that an object is still in memory. This will apply to almost every object except for objects that are considered parents of your object, in which case you would use assign. (See the section on retain cycles here).
Also note that you have to use assign for non-object types such as int.
Read through the Memory Management Programming Guide a bit; it's quite helpful.
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.
I am creating an NSArray with CGRects using the following line:
[self setMyArray:[NSArray arrayWithObjects:[NSValue valueWithCGRect:CGRectMake(x,y,z,a)], [NSValue valueWithCGRect:CGRectMake(x,y,z,a)], nil]]
I am then trying to update the CGrects in the Array every so often like this:
for (NSValue *bound in myArray)
{
CGRect myRect = [bound CGRectValue];
myRect.origin.y += 2;
}
However this is not working, when the loop runs again, the origin is still the same. I am assuming this has something to do with the NSValue wrapper?, What can I do so the value is actually updated in the array?. Thank you.
-Oscar
NSValue objects are immutable so there is nothing you can do. You should use a mutable array and replace the existing object with a new NSValue instance containing the new rect.
As others mentioned, NSValue instances are not mutable so you will have to recreate them and then replace them in an NSMutableArray.
Another option is to use more 'classic' C memory management (malloc/free) and manage your array that way. There is nothing wrong with going that route. You just have to be more careful as it is not has high level as the Objective-C/Foundation APIs.
// Create an array to hold 100 rectangles
CGRect* rectangles = (CGRect*) malloc(100 * sizeof(CGRect));
// Change the rectangle at index 2 (remember arrays are 0 based, so this is the 3rd)
CGRect* rect = &rectangles[2];
rect->size.width /= 2.0;
// Shortcut for accessing rectangles
rectangles[2].size.width = 100.0;
// Get rid of the array
free(rectangles);
Might be faster too if you work on for example a game.
I want to keep a mutable collection of CGImageRefs. Do I need to wrap them in NSValue, and if so how do I wrap and unwrap them properly? Can I get away with using a C array? If so how do I construct it and how do I add elements to it later? Is it significantly more costly to use UIImages instead of CGImageRefs as the elements of the collection?
You can directly add CGImage to NSMutableArray. You will need to cast to (id) to avoid compiler warnings.
CFType is bridged to NSObject. You can send any message NSObject responds to to any CFType. In particular, -retain and -release work as normal.
2011: just in case someone's still looking
You can wrap CGImageRef in NSValues by using
+ (NSValue *)valueWithBytes:(const void *)value objCType:(const char *)type
hence:
CGImageRef cgImage = [self cgImageMethod];
NSValue *cgImageValue = [NSValue valueWithBytes:&cgImage objCType:#encode(CGImageRef)];
[array addObject:cgImageValue];
to retrieve:
CGImageRef retrievedCGImageRef;
[[array objectAtIndex:0] getValue:&retrievedCGImageRef ];
hope this helps somebody
Getting the CGImageRef out of an UIImage via image.CGImage can be costly. From the documentation:
If the image data has been purged because of memory constraints, invoking this method forces that data to be loaded back into memory. Reloading the image data may incur a performance penalty.
If you feel comfortable with mixing C++ and Objective-C, you can use a std::vector for storing the CGImageRef. Rename your source file from .m to .mm and try this:
#include <vector>
...
CGImageRef i;
...
std::vector<CGImageRef> images;
images.push_back(i);
If you want to keep the vector as a member of a Objective-C class, you should allocate it on the heap, not the stack:
Header file:
#include <vector>
using std;
#interface YourInterface : ...
{
vector<CGImageRef> *images;
}
and in the implementation file:
images = new std::vector<CGImageRef>();
images->push_back(i);
...
//When you're done
delete images;
images = NULL;