In my iOS project i am creating an NSArray that can contains integer values. There are several functions in this class that do their task on that NSArray. So i thought to create NSArray as private attribute of that class. In viewDidLoad i am allocating memory to this array i.e
myArray = [[NSArray alloc] init];
myArray will be used in several method of this class. When i analyze my code it shows memory leak as i am allocating myArray and not releasing it.
If i write [myArray release] in dealloc or viewDidUnload warning still there. If i release myArray in last method of class that is using this array, xCode wont allow me to do.
Here is How i am declaring it in my class
.h file
#interface FightVC : UIViewController
{
NSArray *myArray;
}
I want to know what is possible solution of this. other then using autorelease . I don't want to make it public so i am not writing this array as property.
Thanks in advance
Using a private #property as mentioned in the other answer is probably the nicest and cleanest way to do this. Raw instance variables aren’t a very modern way of doing things. However, if you are going down that road, you can implement a getter for your ivar in which you release the old ivar and retain the new one:
- (void)setMyArray:(NSArray *)array {
[myArray release];
myArray = [array retain];
}
That’s the typical pattern anyway (which is what having an #property does for you automatically).
After that, you can create the array, use the setter, and then release the object:
NSArray *newArray = [[NSArray alloc] init];
[self setMyArray:newArray];
[newArray release];
That should keep the analyzer from squawking at you. A few things stick out to me though:
1) [[NSArray alloc] init] isn’t likely to do what you want it to do. It’s going to create an empty, immutable array. You probably either want an NSMutableArray, or you want to instantiate it with objects already in it using a different initializer.
2) NSArrays aren’t really suited for holding integers themselves, they hold objects. You can either use an NSPointerArray or you can put the integers into NSNumbers and put them into an NSArray.
To make a property private, you have to create an anonymous category.
In your .m file:
#interface myClass ()
#property (nonatomic, retain) NSArray *myPrivateArray;
#end
#implementation myClass
// Class code here
#end
To release your array, simply set the property to nil.
self.myPrivateArray = nil;
Related
This question already has answers here:
Objective-C declared #property attributes (nonatomic, copy, strong, weak)
(4 answers)
Closed 6 years ago.
I was trying to pass a custom object to the next view controller and I encountered this error -[ClassName copyWithZone:] unrecognized selector sent to instance
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"attemptDetails"])
{
ResultsVC *vc = segue.destinationViewController;
vc.selectedEntry = selectedEntry;
}
}
#property (nonatomic, retain) ClassName *selectedEntry; //Why is it retain and not copy?
I'm still very confused with property attributes and why certain types use certain attributes, like NSString uses (nonatomic, copy) and CLLocationCoordinate2D uses (nonatomic, readonly).
Could someone explain or link a reference to me how each property attribute works? Much thanks!
There are lots of descriptions for property attributes explanation,
Reference links,
Objective-C ARC: strong vs retain and weak vs assign
https://stackoverflow.com/a/4511004/4294543
#property and retain, assign, copy, nonatomic in Objective-C
Short & simple my understanding is like,
retain : It's working on the created object, and it just increase the reference count.
Here in your case you have already model class object so not need to copy in the second vc property,you just need to retain it to second vc property.
copy : The value you assigned to property can be copied & used for other purposes too(create shallow copy of object & need when object is mutable & need to release after finish with it).
nonatomic : Thread access is faster but you can't simultaneously access & change your property.
readonly : You can't directly assign the property new value.
Even i have run your case in the my project,
#import "ViewController.h"
#import "TestViewController.h"
#import "CustomClass.h"
#interface ViewController (){
CustomClass *classT;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
classT = [[CustomClass alloc]init];
classT.test = YES;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)btn:(id)sender {
TestViewController * vc = [self.storyboard instantiateViewControllerWithIdentifier:#"TestViewController"];
vc.className = classT;
[self presentViewController:vc animated:YES completion:nil];
}
#end
#import <UIKit/UIKit.h>
#import "CustomClass.h"
#interface TestViewController : UIViewController
#property (nonatomic,retain) CustomClass *className; // Work as i said
//#property (nonatomic,copy) CustomClass *className; // Makes a copy of an object, and returns it with retain count of 1. If you copy an object, you own the copy. This applies to any method that contains the word copy where “copy” refers to the object being returned thats why here you will get crash
#end
I have read couple of good article for memory management. According to rypress
Retain Attribute : The retain attribute is the Manual Retain Release version of strong, and it has the exact same effect: claiming ownership of assigned values. You shouldn’t use this in an Automatic Reference Counted environment.
Copy Attribute : The copy attribute is an alternative to strong. Instead of taking ownership of the existing object, it creates a copy of whatever you assign to the property, then takes ownership of that. Only objects that conform to the NSCopying protocol can use this attribute.
Even I went through some good link of stackoverflow as well. Joshua Nozzi's answer gave good explanation for retain vs copy.
Retain vs. Copy - Declared properties use retain by default (so you can simply omit it altogether) and will manage the object's reference count automatically whether another object is assigned to the property or it's set to nil; Use copy to automatically send the newly-assigned object a -copy message (which will create a copy of the passed object and assign that copy to the property instead - useful (even required) in some situations where the assigned object might be modified after being set as a property of some other object (which would mean that modification/mutation would apply to the property as well).
Also found good example here.
Code :
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:#"First",#"Second", nil];
NSMutableArray *copiedArray = [array mutableCopy];
NSMutableArray *retainedArray = [array retain];
[retainedArray addObject:#"Retained Third"];
[copiedArray addObject:#"Copied Third"];
NSLog(#"array = %#",array);
NSLog(#"Retained Array = %#",retainedArray);
NSLog(#"Copied Array = %#",copiedArray);
Output :
array = (
First,
Second,
"Retained Third"
)
2013-12-19 17:15:49.380 RetainVsCopy[2876:c07] Retained Array = (
First,
Second,
"Retained Third"
)
2013-12-19 17:15:49.381 RetainVsCopy[2876:c07] Copied Array = (
First,
Second,
"Copied Third"
)
See, both array and Retained Array are having same contents. This is because both are pointing to same memory/instance/object. Where as contents of Copied Array are different. This is because copy created a separate instance.
In Objective C you will find that each class actually has a structure behind it. The properties are shortcuts which create the value in structure, a getter and a setter. For instance:
#interface MyClass
#property id myValue;
#end
Will create:
#interface MyClass {
id _myValue;
}
#property id myValue;
#end
#implementation
- (id)myValue {
return _myValue;
}
- (void)setMyValue:(id)myValue {
_myValue = myValue;
}
#end
Now these flags such as retain and copy add additional logic to the setters and getters. Using copy will actually create a setter as:
- (void)setMyValue:(id)myValue {
_myValue = [myValue copy];
}
Which means that the value must have the copy method implemented. Since your object does not it crashes.
Why to use copy is for safety. This is rarely important for something as strings but it is important for something like an array. So for instance you create a property #property NSArray *myArray; which expects an un-mutable array but the problem is that you can set a mutable array as well: myClassInstance.myArray = [[NSMutableArray alloc] init];. Now 2 modules have the access to the same mutable array. So if the first object starts modifying the array while the other one expects the array to always be the same you may find some issues. For instance MyClass instance may use it as a data source for the table view and at some point the array is mutated but the cells are not added/removed and the table view will cause a crash.
To be honest you can simply leave all of these as default and modify them only when you really need to. The case like above is highly unlikely anyway.
I've declared a property in the .h file called cellTitles. In my .m file, I have a method as follows:
-(NSArray *)cellTitles
{
if(!_cellTitles){
_cellTitles = [[NSArray alloc] initWithObjects:#"several strings", nil];
NSLog(#"Home Array Created");
}
return _cellTitles;
}
But the array is not created when I refer to _cellTitles or self.cellTitles. I have several NSLogs that all say the array has 0 objects. Do I need more than this. Some answers have said I need to synthesize, but as I understand it, that is no longer necessary.
Make sure your property is assigned strongly.
#property (nonatomic, strong) NSArray *cellTitles;
I have a NSMutableArray is my delegate that I am using in one of my view controllers as well.
So in viewDidLoad I make a mutable copy of my NSMutableArray like this
#implementation ItemsViewController{
AppDelegate *mydelegate;
NSMutableArray* allItems;
}
In viewDidLoad
allItems = [mydelegate.array mutableCopy];
Now whatever changes I make in my allItems MutableArray also cause changes in my mydelegate.array. Am I doing something wrong?
Also my array in the delegate is defined as follows
#property (nonatomic, strong) NSMutableArray *array;
You should do a deepCopy, i use this one and works perfectly, made by Sherm Pendley †.
I assume you did not implemented the mutableCopyWithZone: correctly.
You need to implement the NSMutableCopying protocol for the objects you put in the array, this way you could pass a new instance of that object for that case.
- (id)mutableCopyWithZone:(NSZone *)zone
{
YourCustomModel *aCopy = [[[self class] allocWithZone:zone] init];
if (aCopy) {
// set properties
}
return aCopy
}
That's because the mutable copy of the array is referencing the same objects as mydelegate.array is referencing, so if you change one object property, it's changed in both arrays, as it's the same object.
You could implement NSCopying protocol in your objects and you can then call initWithArray:copyItems: NSArray method.
Hope that helps.
Try this.
allitems =[NSMutableArray arrayWithArray:mydelegate.array];
I've a theoretical doubt about two type of declaration of a mutable object in iOS (and MacOSX I think) with ARC.
What's the difference between a declaration of an NSMutableArray in the Class Extension, like the code below:
#interface MyViewController ()
#property (copy) NSMutableArray* myMutableArray;
#end
//Class implementation
#implementation MyViewController
...
- (void)viewDidLoad
{
_myMutableArray = [#[] mutableCopy];
}
and a declaration of the same array in this way
#interface MyViewController ()
#property (nonatomic, strong) NSMutableArray* myMutableArray;
#end
//Class implementation
#implementation MyViewController
...
- (void)viewDidLoad
{
_myMutableArray = [#[] mutableCopy];
}
Which one is better? I've seen both versions around and apparently both work fine. However I'd like to know which one is the best option.
I know that the "copy" keyword is to use copy for classes that are part of a class cluster that have mutable/immutable pairs. So in this case, it appear to be the right choice. But the use of the "copy" keyword and the "mutableCopy" property (like the first example) seems a duplicate to me. Am I wrong?
Thanks!
The strong property is the one to use. Since its a mutable object (and is declared as such) then you wouldn't want a copy making, since then things like [self.myArray addObject:object] wouldn't work. You'd use copy properties for immutable objects that may have mutable versions passed in (so an NSString would often be a copy property).
The way the arrays are assigned (making a mutable copy of an empty array made using objective-c literals) is pretty clumsy and would be better written as self.myMutableArray = [NSMutableArray array];
Also, don't access the instance variable directly, use the property accessor.
I would like to store a zeroing weak reference to an object in a NSDictionary. This is for a reference to a parent NSDictionary, so I can crawl back up a large structure without searching.
I can not use __weak here; even if my local reference is weak, the NSDictionary will store a strong reference to the object that was weakly referenced. And, of course, NSDictionary can't have nil objects.
I'm on iOS, not Mac, so NSHashTable isn't available. And I only want one object to be weak; the rest should still be strong.
(I'm going to post my answer, so I have something to mark as accepted if there's no better answer. But I'm hoping someone has a better answer.)
In iOS 6+ you can use NSMapTable and choose if you want objects and/or keys to be weak or strong.
I've settled on defining a "container" class with a single member, like this:
#interface Parent : NSObject
#property (nonatomic, weak) id parent;
#end
#implementation Parent
#synthesize parent = _parent;
- (id)initWithParent: (id)parent;
{
if (( self = [super init] )) {
_parent = parent;
}
return self;
}
#end
And using it:
id parentRef = [[Parent alloc] initWithParent: parent];
[newElement setObject: parentRef forKey: ParentKey];
I think this will work for me, but it seems crazy that there's no better way built in to Foundation.
There is a built-in way; just use:
[array addObject:[NSValue valueWithNonretainedObject:object]];
Then to access the object later, use:
id object = [[array objectAtIndex:i] nonretainedObjectValue];
If the value has been released since you added it then "object" will be an invalid pointer under iOS 4.x, and (I'm assuming) will be nil under 5.x with ARC enabled.
EDIT: my assumption was wrong - it's not weak under ARC (see discussion below).