I just created a new class in my project, subclass of UITableViewController and noticed that in the method tableView:cellForRowAtIndexPath: template, Apple still provide a static local NSString to use as a cell identifier.
I know that for static global/local variable we need to assign nil cause it's considered as strong.
So I asked myself the question : Where should I assign nil to static global variable ?
And static global variable ?
Thanks for the answers guys
A short answer to the "where should static global variables be released" is "nowhere".
Long answer goes like this: when you make a variable static or global, you want it to exist regardless of any instances of your classes coming into existence or being released. Simply speaking, you want your statics to always be there for you. Therefore, the only reason to release them would be if your program is about to exit. But if your program is exiting anyway, you might as well let the operating system handle the cleanup for you, and forget about releasing your global and static variables.
Note, however, that the use of static and global variables should be an exception, not a norm. You use them for a good reason, and exercise your best judgement to decide what should be static. Moreover, you should avoid referencing collections of non-static variables from static ones through a strong reference, because otherwise you may create hard-to-find memory leaks.
There is nothing wrong with a static local for the NSString used as your cell identifier: it takes very little memory, and it does not grow, so it's not a big deal that it is not released at the end of your program's run.
You don't need to do it, it will never be released and its ok since it is a global.
In ARC will be treated as strong for default and its lifetime it is equal to the application lifetime.
Static strings are a special case, and don't need to be released.
static variable, means it holds a strong reference to the object it points to.
static MyClass *var;
var = [MyClass instance];
Now var always holds strong reference to the above allocated object.so it will never be removed from memory.
But after some condition you no longer need that object,then simply
var =nil would work.
because now var points to nil and no longer points to created object.so that object will be deleted from memory.
Related
I've seen code examples of variables and constants created outside classes as a way to avoid hard-coding.
Are they a good practice in terms of memory allocation?
For example:
private let cellId = "myCellId"
class ViewController : UIViewController {
...
let cell = tableView.dequeueReusableCellWithIdentifier(cellId)
...
}
When are these constants/variables allocated/deallocated in an iOS application?
Top level global variables like this are lazily initialised. Also, they are implicitly allocated within a dispatch_once so they are thread safe.
The lazy initializer for a global variable (also for static members of structs and enums) is run the first time that global is accessed, and is launched as dispatch_once to make sure that the initialization is atomic. This enables a cool way to use dispatch_once in your code: just declare a global variable with an initializer and mark it private.
Reference: Swift blog
In general, Abizern is correct. However, constant strings are a bit of special case. They're never allocated. They live in your binary image, which is memory mapped, which is about as close to "free" as you can get. Since structs are exactly their contents (i.e. there's no header on a struct), your string costs exactly 9 bytes in the binary (the characters plus a trailing 0). It is never allocated; it just is.
Since cellId is let, the compiler can replace references to it with the actual memory location in the binary that holds the data. There's not even a need for a pointer for cellId itself.
In my ViewController I have created some objects that I need to use throughout various places in the controller itself, but nowhere outside of it. I have done it like this:
#implementation MyController1
NSString *myString;
- (void)myFirstMethod {
myString = #"hello world";
}
...
#end
I haven't put them in the header file nor have I defined them with #property in an interface declaration that would look like this:
#interface MyController1 ()
// could define myString with #property here
#end
I'm not having any problems with my code, but I wanted to make sure that I'm not violating safe practices. I know I could put them in the header or implementation file and use #private, but for the sake of code brevity I haven't. Is this okay to do? Does no longer having to use #synthesizehave any impact on this?
Thanks,
It's perfectly fine, just as long as you are aware of the difference between an instance variable (a.k.a. "member variable" or "ivar") and a static variable. For example, there will only be one string object associated with your myString variable in your example here (#"hello world"), no matter how many MyController1 objects you create, not one per instance of the class MyController1. So in this way, myString is not behaving like a property nor an instance variable.
Furthermore, the static variable's life cycle is longer -- it will outlive all instances of your MyController1 objects, only being deallocated when the program exits or if you explicitly do so, say if you allocated it on the heap to begin with (which you are not doing in the case of #"hello world", but of course could potentially do with other static variables).
There are pros and cons to both types/approaches. For example, ivars can keep track of object state, but this means each instance of your objects are bigger because they must each have memory allocated for that state. So if memory performance matters in your app, ivars shouldn't be used unless you need them. On the other hand, static variables are good for "one offs" -- things that are not associated with the object state, but often have to be protected if they can be written to by more than one object on more than one thread. These are just some contrasts... there are many others depending on what you're trying to do.
Re your final question about #synthesize, not using it just means that there won't be any auto-generated accessors for the variable, which is fine because the variable isn't an ivar and not associated with instances of the MyController1 object anyway.
This question already has answers here:
What makes a static variable initialize only once?
(4 answers)
Singleton objective c clarification
(5 answers)
Closed 8 years ago.
The code below is from the Big Nerd Ranch iOS programming book, 3rd edition. It's a class method that checks whether the singleton class BNRItemStore has been instantiated. If it has, it returns the singleton instance, and if it hasn't it creates it. The part I don't understand is the static variable. I know that static variables keep state, however, wouldn't calling the method a second time reset the *sharedStore back to nil? i.e. isn't this an assignment which would erase the creation of the singleton instance once the method was called again?
static BNRItemStore *sharedStore = nil;
Method
+(BNRItemStore *)sharedStore
{
static BNRItemStore *sharedStore = nil;
if (!sharedStore)
sharedStore = [[ super allocWithZone:nil ] init ];
return sharedStore;
}
Unfortunately, C terminology is really confusing. static has nothing to do with singletons, standing still, not changing, or anything like that. It has to do with the level at which storage takes place.
A variable declared inside a method/function is normally an automatic variable, meaning that it goes out of existence when the scope ends (i.e. execution reaches the end of the surrounding curly braces). A variable declared static, however, is stored at the level of the file that holds the code; once the file is loaded, this variable persists, even though it is declared inside a method/function.
Now we come to the question of how you will know whether this variable has ever been assigned a value, because you only want to assign it once. In theory, a static variable has a zero value when it is initially declared. Thus, if you said merely
static BNRItemStore *sharedStore;
...the code might work, because zero is nil for an instance, so we could test against nil and assign a value only in that case. However, it does no harm to make assurance double sure. Thus, we typically initialize the variable to nil when we declare it, just so we can be sure our nil test will work the first time.
That initializer, as you've already been told, will then take effect only once, because after that, the value persists and so the variable never needs to be initialized again (and never is).
The code is fine, the initialiser only gets called the first time.
Static initializers are guaranteed by the language specification to only be executed one time, (and that's actually done at application start time, not as a part of function execution) so the static variable will only be nil the first time the function is executed.
I was wondering how you would release a singleton
+ (DSActivityView *)activityViewForView:(UIView *)addToView withLabel:(NSString *)labelText width:(NSUInteger)labelWidth;
{
// Not autoreleased, as it is basically a singleton:
return [[self alloc] initForView:addToView withLabel:labelText width:labelWidth];
}
When analysing this using the analyse tool i get the following error :
Potential leak of object on line 90. which is the line that returns.
I have tried autorelease that solves the error message problem but im not convinced its the right solution since i read that autoreleasing singletons is not good. Would someone be able to assist me in identifying how best to release this object?
Thanks
The reason why the analyzer gives you the warning is, basically, the method name:
+ (DSActivityView *)activityViewForView:(UIView *)addToView withLabel:(NSString *)labelText width:(NSUInteger)labelWidth;
according to Objective-C conventions, all method names starting with "create"/"new"/... return a retained object; your method falls under the category of convenience constructors, which are expected to return autoreleased objects, hence the warning.
On the other hand, you say this is a singleton, but in fact it is not. So, you could possibly end up calling this method more than once and thus have an actual leak. A basic way to make your method safer (and more singleton-like) is:
+ (DSActivityView *)activityViewForView:(UIView *)addToView withLabel:(NSString *)labelText width:(NSUInteger)labelWidth;
{
static DSActivityView* gDSActivityViewSingleton = nil;
if (!gDSActivityViewSingleton)
gDSActivityViewSingleton = [[self alloc] initForView:addToView withLabel:labelText width:labelWidth];
return gDSActivityViewSingleton;
}
This would both make the analyzer relax and give you more safety in front of the possibility of misuse of the method.
Use autorelease. There's no reason not to. Basically ownership of the object belongs to the object, so you're never going to be able to manually release it. As its a singleton it doesn't matter if you don't own it because presumably next time you call it and need it in scope you'll use another convenience method and it will get instantiated again.
If you want to have ownership of the object then you will need to instantiate it as normal and then you will be able to retain and release it.
Also, read sergio's edit about it not being a "proper" singleton. :p
Also, if you can, convert to ARC and you won't have to worry about this!
U are doing it wrong. Consider:
If you calling activityViewForView multiple times, you won't get get the same object over and over again. It only would initialize a new object and give you the pointer to it!!!
To make this thing a singleton, you have to store the created object in a constant variable and make sure, you have a reference to this object all the time your app is running (for instance declare your pointer to this object in appDelegate).
Then every time you call activityViewForView you have to check the constant variable if it is pointing to a valid object. If so, return the valid object, if not, create it and store it in your constant static variable (creation is done only once).
If you do use ARC you're all set. If not, release your object (use dealloc method)
Say, I want to create a singleton which has some data inside. The data is dynamically allocated only once, as it expected on singleton.
But I would like to now under when and how this data can be is released. Should I establish special method which will destroy the singleton? To be more specific - when the method 'dealloc' for this singleton will be executed? who is responsible for that?
You can declare a method/function you call explicitly.
The simplest way is to have a static C++ class hold it, then release it in its destructor. If you have multiple singletons, then this approach does not extend very well because the destruction order is implementation defined.
Another alternative (and better design) would be to avoid the singleton approach, and just use it as a regular instance in another class which lives for the duration of your app (an app delegate is a commonly known example).
As to 'when', it depends on its dependencies and how it's used. It's also good to try to minimize external influence in destruction.
In general, a singleton is not different to a normal object. It is freed, if there is no (strong) reference to it anymore. Usually, you control that there is one object only by a static variable. This variable is created at compile time; therefore it can not be freed. But all the 'real' object stuff can.