Releasing static resources in Objective-C [duplicate] - ios

This question already has answers here:
Objective-C/iPhone Memory Management Static Variables
(3 answers)
Closed 10 years ago.
If I use a static resource in an Objective-C class, will I create a memory leak by not ever releasing it? Something like the following:
#interface MyClass : NSObject
+ (MyClass *)sharedInstance;
#end
#implementation MyClass
+ (MyClass *)sharedInstance
{
static MyClass * inst;
if (!inst)
inst = [MyClass new];
return inst;
}
#end
A) Is there any scenario where the application using this class closes and this static declaration creates a memory leak?
B) Is there any class method, such as + (void)unloadClassDefinition, that is called when class definitions are being purged from memory? (Does that even happen?)

A leak is a chunk of memory to which you have lost all pointers. You always have a pointer to this object, because the variable exists for the duration of your process. As long as you don't reassign a new object to this pointer without destroying the old object, you will never have a leak.
A) All of your process's memory is reclaimed when it terminates. There's no such thing as a leak that can persist past your application's end.
B) Classes are never unloaded once loaded in Apple's ObjC runtime.
If you want to be able to destroy this object, you will have to move the variable out of that method so that you can access it from another, and do something along these lines:
static MyClass * inst;
+ (MyClass *)sharedInstance
{
if (!inst)
inst = [MyClass new];
return inst;
}
// Under ARC; under MRR you might monkey around with retain and release
// This won't actually immediately destroy the instance if there are other
// strong references to it.
+ (void)destroySharedInstance
{
inst = nil;
}
but generally, if you're using a singleton, you probably want it around for the life of your application.

It doesn't technically constitute a leak, because you still have a reference to the memory (a static one). The memory will remain claimed until you set inst = nil. Best practice would be to do so when you know that you are finished using the object.

Related

Best way to pass CGFloat by reference to another class

In ClassA, I have a CGFloat value x that I want to pass by reference to ClassB such that if I make a change to the CGFloat in ClassA, it will be reflected in the reference to x in ClassB. Also, when I pass it to ClassB, I want to store it as a property.
I've thought about using a CGFloat pointer, but I'm struggling to figure out the proper syntax to make it a property:
#property(nonatomic) CGFloat *x;
And then to dereference it:
self->x
I thought about using NSNumber but there is no way to set the value using NSNumber such that it will update in ClassB. I thought about giving up and making a wrapper class to store the CGFloat, but this seems like overkill.
What is the best pattern to go about doing this?
I thought about giving up and making a wrapper class to store the CGFloat, but this seems like overkill.
The advantage of this approach is safety, you create an object, both classes reference it, and ARC takes care of the memory management.
The class is easy to define, for example:
#interface ABShare1 : NSObject
#property CGFloat x;
#end
#implementation ABShare1
#end
(in a .h & .m file – same for other examples)
A class using this would be something like:
#implementation ClassA
{
ABShare1 *one;
}
...
one = ABShare1.new; // somewhere in initialisation
...
... one.x = 42; ... z = one.x * 24; ...
Note: the above stores the ABShare1 reference in a private instance variable, you can store it in a property if you wish but there is no need to.
You can call a method on another class passing the object, e.g.:
ClassB *myB;
...
[myB using:(ABShare1 *)sharedVariable];
and that other class can keep the reference as long as it requires, memory management is automatic.
I've thought about using a CGFloat pointer
This is the standard C (a subset of Objective-C) way of "passing by reference".
You can store a CGFloat * in a property, all "object" valued properties in Objective-C just store pointers (e.g. #property NSString *name; stores a pointer to an NSString object).
You must create the variable that the CGFloat * references, the equivalent of new or alloc/init in Objective-C. You can use the address of a variable, e.g. something like:
CGFloat actualX;
CGFloat *x = &actualX;
but you have to manually ensure that the referenced variable, actualX, lives at least as long as its pointer, stored in x, is in use – failure to do that results in a dangling pointer.
The other option is to dynamically allocate the storage, the direct equivalent of new, e.g. something like:
CGFloat *x = malloc(sizeof(CGFloat));
However you are now responsible for determining when the storage is no longer required and releasing it (using free()).
The first solution to you is "overkill" – maybe because while you are freed from concerns over memory management you don't get a "variable" but two functions/methods to get/set a value.
The second solution is closest to feeling like a "variable", you just use *sharedVariable rather than sharedVariable. However while the manual memory management required is standard for C programmers, it is not for Objective-C programmers.
A third approach mixes the two building on how structures (struct) in C can be used: to share a collection of variables rather than share each one individually by address, instead define a struct with a member for each variable, allocate one and share its address, something like:
typedef struct ABShare
{ CGFloat x;
CGFloat y;
} ABShare;
ABShare *one = malloc(sizeof(ABShare));
one->x = 42;
one->y = 24;
The above has the same memory management issues as the second solution, but we can convert it to a very close Objective-C equivalent:
#interface ABShare : NSObject
{
#public // required
CGFloat x;
CGFloat y;
}
#end
#implementation ABShare
#end
Note: Objective-C classes are effectively implemented using structs, indeed the first Objective-C compilers actually translated them into C struct code.
Using this is very close to the C:
ABShare *one = ABShare.new;
one->x = 42;
one->y = 24;
Same "variable" look as C but with automatic memory management.
This last scheme is essentially how Objective-C manages sharing variables when a block is created – all the local variables accessed by the block are moved into a dynamically allocated object/struct and the variables then accessed using ->.
Which is best in Objective-C? The first and the third are both "Objective-C" style, the second is usually avoided accept when interacting with C APIs. Of the first and third pick whichever feels "right" semantically, rather than concerns over performance, to you. HTH
[NSMutableData dataWithLength:sizeof(CGFloat)] and cast mutableBytes to CGFloat*
You can implement getter and setter of property #property(nonatomic) CGFloat x -without pointer

How to manage object when override setter in ARC?

I have question when I override setter for a #property.
that is:
If I set a property like this :
#property (strong) NSString *name;
In 'MRC' it will auto-generate getter and setter, assume setter will implement like this :
- (void)setName:(NSString *)name
{
[_name release]; // Release previous.
_name = name;
[_name retain]; // Remain object.
}
When I override setter in 'MRC', I can manage object by follow 'strong' behavior like code above,
but when in 'ARC', what will setter implement like or how to manage object to make it behavior like 'strong' since it has no 'retain and release' in 'ARC' ?
Thanks for yor time!
Under ARC, the compiler generates this setter:
- (void)setName:(NSString *)name {
_name = name;
}
But since _name is declared __strong (because the property is strong), the assignment turns into a call to objc_storeStrong:
- (void)setName:(NSString *)name {
objc_storeStrong(&_name, name);
}
The objc_storeStrong function takes care of the retain and release, and does so more safely than yours:
id objc_storeStrong(id *object, id value) {
value = [value retain];
id oldValue = *object;
*object = value;
[oldValue release];
return value;
}
(Consider what happens in your setter if name == _name and its retain count is 1 at the start of the setter. The objc_storeStrong function is also carefully written to avoid race conditions when multiple threads try to set the property simultaneously.)
ARC doesn't really require that you do anything special or additional, except for explicit bridging to Core Foundation pointers (which the compiler can auto-fix). It mainly requires that you don't write memory management code (like retain/release calls) yourself. You really don't need to "learn ARC", you only need to learn the memory issues that ARC cannot handle for you, like retain cycles (bad) and the management of C pointers (i.e. Core Foundation types--except when called from Swift, in which case ARC can handle them as well). The whole point of ARC is automating a part of software development that is very tedious and error-prone; it's less for you to worry about, not more. As an analogy, you don't really need to know anything about SQL in order to use Core Data...the finer details are abstracted away for you.
You made the property strong by virtue of declaring it strong, there isn't anything special you have to do in the setter:
-(void)setName:(NSString*)name
{
_name = name;
}
Of course, that is a silly example because there is no reason to override a setter when all you're doing is the default behavior, anyway. But you get the point...

Using a static variable to reference instances of a class in Objective C?

I'm brand new to Objective C, and this may be somewhat of a lame question but:
I'm trying to make an iOS game, in which there is a class 'Monster' which generates a new instance of Monster every second or so, I want to be able to keep track of each Monster in order to use/manipulate it somehow.
Currently I'm trying to issue each Monster an unique ID,
e.g something like this:
//Incorrect Syntax ...
Class Monster extends CCSprite
public static global_id = 0;
public instance_id;
init() {
instance_id = global_id;
global_id ++;
}
How would I manage this in the header/implementation file for class Monster?
It seems like "static" 'doesn't exist' in Objective-C.
You'd normally work around the problem by:
sticking to the one-class-per-source-file rule;
putting a suitable global variable within that file;
marking the global variable as static, which in C terms means "not accessible from outside of this compilation unit" (and one source file is one compilation unit if you don't go out of your way with the preprocessor).
So, interface:
#interface AEMonster: CCSprite
#property (nonatomic, readonly) int instanceID;
#end
Implementation:
static int globalID = 0;
#implementation AEMonster
- (instancetype)init
{
self = [super init];
if(self)
{
_instanceID = globalID;
globalID ++;
}
return self;
}
#end
Your example didn't look like pure Objective-C. Objective-C does support static definitions. What you're describing is a classic Factory/Singleton pattern, and it would look like this:
MyClass.h:
#interface MyClass : NSObject
+ (id)getInstance;
#end
MyClass.m:
#import "MyClass.h"
+ (id) getInstance
{
static MyClass *myClass = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
myClass = [[self alloc] init];
});
return myClass;
}
This is the singleton part of the pattern, where you call MyClass *c = [MyClass getInstance]; to get a reference to the instance. Only one instance will ever exist, and this is great for things where you want something semi-global but with a better pattern (things like network services are great examples).
A Factory pattern is just a step beyond this. You build MyClass exactly the same way, but instead of a getInstance() method you would have a createMonster() method. That would take any parameters required to create the type of Monster you wanted (this pattern is especially useful when you're going to have a Monster base class and then sub-classes of specific Monster types).
That's where you would generate your unique ID. Just add another static member variable inside the factory function and you can increment it each time it's called. That's a really naive unique ID generator, though - you probably want to make sure what you do is thread-safe, too. (That's another story.)

How to release instance variable in ARC - Objective-C

I know the instance variable in ARC are by default __strong. How can I release an instance variable when the containing class is still retained. In the following example v is __strong
and c is allocated when object of A is created some where and retained. I want to release the
c instance variable. How to should I do that?, What should be in releaseC method that will release the c instance variable.
#interface A {
Obj *c;
}
#implementation A {
- (id)init {
if((self = [super init])){
c = [[Obj alloc] init];
}
return self;
}
- (void)releaseC {
//what should be here?
}
}
Obj *c; = [[Obj alloc] init];
- (void)releaseC {
c = nil;
}
You cannot directly control when an object is released BUT you can indirectly cause it to happen. How? Remember what ARC does EXACTLY. Unlike human coding convention, ARC parses your code and inserts release statements AS SOON AS OBJECTS CAN be released. This frees up the memory for new allocations straight away, which is awesome/necessary. Meaning, setting an object to nil, or simply allowing a variable to go out of scope ... something that CAUSES A 0 RETAIN COUNT forces ARC to place its release calls there. It must ... because it would leak otherwise.
- (void)releaseC {
c = nil;
}
c = nil;
But some would argue it isn't productive from an efficiency standpoint. And while the release will be immediate in the sense it isn't any longer usable, the memory may not be freed immediately.
there is no need to release the variable in ARC. it done automatically
You are probably miss understanding what you want to do. I suppose you want to release the variable for memory issues. All you have to do is nil it. Instance variables are pointers to objects. As long as an object is pointed by something it is kept alive. As soon as you dont need something you can "stop pointing at it" and it will be released automagically.
As for the design, I am not so sure why you would have a public method that releases an instance variable. (I'm assuming its public because if it was not you would just nil it without actually having to write a method). If you do indeed intend to be able to release an instance variable from outside the class, I would simply make the Instance variable public and release it from anywhere setting it as nil.

EXC_BREAKPOINT: Message sent to deallocated instance

I get the above message in XCode 4.6. I've done a pretty thorough search and but nothing seems to match the exact circumstances surrounding my issue. Admittedly, I'm relatively new to iOS dev, and memory-management has never been my strong suit, but this just has me completely miffed.
I have an instance variable theLink which is defined in the class Game as follows:
#interface Game : NSObject
// Class objects
#property(nonatomic,retain) NSMutableArray *queryItems;
#property(nonatomic,retain) NSMutableArray *theArray;
#property(nonatomic,retain) NSString *theLink;
#property(nonatomic,retain) NSString *thePath;
theLink is set in the makeGame method which is called in the method initialiseGame in my view controller:
- (void) initialiseGame
{
bool gameCreated = FALSE;
while (!gameCreated)
{
gameCreated = [theGame makeGame:#"ptl"];
}
[loadingIndicator stopAnimating];
[loading setText:#"Tap to Start"];
[self performSelector:#selector(setLabels) withObject:nil afterDelay:0.0];
}
(Note: the performSelector afterDelay is used to allow the view to update before continuing. Bit of a hack but I couldn't work out a better way!)
The app then loads the game, and when the user taps the screen to start, the next method which is called from the view controller is:
- (void) setupLink
{
...
for(int i=0; i<[theGame.theLink length]; i++) {
...
}
}
It is on this reference to theGame.theLink where I'm am getting the crash.
What has me most confused is that if I call theGame.theLink from inside the initialiseGame method, it is displays correctly, and also calling any other variable from the Game class (such as thePath or theArray works perfectly, so theGame object has not been deallocated in it's entirety, only the variable theLink.
It seems to me that the variable is being deallocated somewhere as the view controller is being updated. I haven't released the variable, and can't work out why only this variable is being deallocated. As I said at the start, memory-management is not my strength!
Any help/ideas would be hugely appreciated. Let me know if you require any more details.
Thanks heaps,
Andrew
EDIT: Setting of theLink within makeGame
- (bool) makeGame:(NSString*)gameType
{
...
[self getLink];
}
- (void) getLink
{
...
if (... && ((arc4random() % 10) > 8))
{
theLink = #"Animals";
}
}
There are many different ways theLink may be set, depending on random numbers and other factors. This is the most basic form which simply sets it to a static string. It doesn't matter how theLink is set or what it is set to, the program always crashes at the same point.
If theLink is being set to the parameter being passed to it ,#"ptl" or some similar temporary string, it will give you a problem, because it is just a pointer pointing at the current location that is holding #"ptl". After the makeGame method is completed, your system will assume that it is all done with #"ptl" and just free it up.
When you make an #"stringwhatever" in your code, it is supposed to be the equivalent of making an NSObject that is an immutable literal instance of #"stringwhataver". It should, in theory handle all the reference counting in a nice way, but when you are doing your own memory management, there are so many ways to lose count of your references.
There's a pretty simple rule to follow. If you've declared properties, access them via the property. To do otherwise (as you are doing above, with theLink = ...) bypasses all of the memory management built into the property accessors.
self.theLink = ...
Would have solved this problem under MRC. Switching to ARC has "solved" your problem without you understanding the root cause.

Resources