If I've created these two variables:
NSDecimalNumber *myNum;
NSString *myString;
how do I later test whether an object has been assigned to them yet or not?
Thanks
If they aren't in a class, you must assign nil as a default value if you want to use this. In a class, that will be automatic.
To test if they have an object associated with them, compare them against nil: if (myNum != nil) // myNum is an object.
Also note that when an object is deallocated, references to it still exist, so when you release ownership of these objects it is good to set them back to nil: myNum = nil;
Set it to nil to start with:
NSDecimalNumber *myNum = nil;
Then use:
if (myNum == nil) { ... you haven't set it yet ... }
nil is the ObjC way of doing null objects (those that do not refer to an actual object).
Related
I have a NSMutableArray holding a whole bunch of UITextFields which I have created and allocated memory.
In my viewDidUnload method I need to release this memory. How do I do it?
for(int i = 0; i < [arr count]; i++){
UITextField* txtField = [arr objectAtIndex i];
txtField = nil;
}
arr = nil;
Will this work? or do I just need to set arr = nil;?
I am using ARC so i set to nil not release.
If the array is an instance variable of the view controller, as long as you're using ARC it will automatically be deallocated when the view controller leaves memory.
If you need to manually remove the array, set it to nil.
arr = nil;
If you need to reuse the array later, you will need to reallocate it after setting it to nil.
Assuming your array is an #property of your object, a good trick is to allocate the array in the getter:
-(NSMutableArray*)arr {
if (!_arr) {
_arr = [[NSMutableArray alloc] init];
}
return _arr;
}
This way you always get an array when you try to access it, even if it's previously been set to nil.
Let's see what your code does to understand what happens:
UITextField* txtField = [arr objectAtIndex i];
that makes a copy of the value in the array, and values in an NSMutableArray are references, and stores that value in a variable txtField. As txtField is defined, implicitly, to hold strong references ARC will (subject to any optimisations) register an ownership interest in the reference (aka "retain"). Your next line:
txtField = nil;
stores the nil reference value in txtField. As txtField holds strong references any store causes ARC to relinquish ownership interest (aka "release") in the previous reference value stored in the variable.
The array is never changed. You've iterated over its contents, copied each value, retained that value, released that value. Finally you write:
arr = nil;
which stores the nil reference value in arr. As arr holds strong references any store causes ARC to relinquish ownership interest (aka "release") in the previous reference value stored in the variable - and that previous value was your reference to your NSMutableArray. If there are no other owners of the array it is destroyed, and when an array is destroyed it relinquishes its ownership of any values it contains - which in this case are your UITextField instances, and if there is no other owner of those then they are destroyed...
So at most all you need is:
arr = nil
but you may not even need that. As arr holds strong references when its lifetime ends - at the end of the block or method containing its declaration if a local variable, or when the instance is destroyed if an instance variable - then ARC will relinquish its ownership interest, etc...
HTH
When using ARC, you release a variable by setting it to nil just as you have done with arr = nil. Note that the memory will only be freed when all pointers to the object have been set to nil, so make sure you aren't holding on to them anywhere else.
Secondly, if you are running into memory issues you should be handling this in the didReceiveMemoryWarning method, as viewDidUnload is no longer supported on iOS 6.
I'm using a code snippet like
if ([Array count] != 0) {
Array = nil;
}
Array = [[NSMutableArray alloc]init];
Is this allowed when using ARC? Does this cause any kind of crashes? Why I'm doing this is each time when my method gets called Array gets a new set of data. I'm using this kind of snippet in many places of my class.
ARC aside, the operation is pointless. You assign an ivar to nil then immediately assign to something else. This is no different from just assigning it to the something else.
Before ARC this would have given you a memory leak (with or without your assignment to nil) if there variable had a previous value. With ARC there is no leak.
Best solution : test and see by yourself ! This is a really short example !
But yes, this works of course !
ARC means Automatic Reference Counting. It just says you don't have to care about release, retain and so on.
If you want an object to be nil, you still can, as it is a simple pointer assignment !
And about your code, you set Array to nil before re-assigning it oO !
Try to get the logic of your code :
If my Array has objects
Then Array point to a new nil object
But in all case you do:
My Array point to a new NSMutableArray object
So whether or not your condition is evaluated to true, your code is useless as the variable will take another value just after !
The sample code you showed is valid. Here are a few variations:
if ([Array count] != 0) {
Array = [[NSMutableArray alloc] init];
}
Example 2:
if ([Array count] != 0) {
Array = [NSMutableArray array]; //value will be retained
}
Example 3:
if ([Array count] != 0) {
self.Array = [[NSMutableArray alloc] init]; //Will NOT leak under ARC.
}
Example 4:
//if ([Array count] != 0) {
[Array removeAllObjects];
//}
All four examples are valid under ARC.
Another thing: instance variables typically have their first letter lowercase, while still following the CamelCase method. Another way to do it is to have an underscore before the name of the variable: this is done if you don't have a #synthesize method to match your #property value.
I want to know the difference between nil, NIL and null.
I've googled around and found this:
nil -> null pointer to Objective-C object
NIL -> null pointer to Objective-C class
null -> null pointer to primitive type or absence of data
But I'm not able to understand the terms "Objective-C object" and "class" clearly.
Please explain this to me. Also, is there any word like NSNull or NSNil in Objective-C? If so, then please explain for what it is for.
nil is the literal null value for Objective-C objects, corresponding to the abstract type id or any Objective-C type declared via #interface. For instance:
NSString *someString = nil;
NSURL *someURL = nil;
id someObject = nil;
if (anotherObject == nil) // do something
Nil is the literal null value for Objective-C classes, corresponding to the type Class. Since most code doesn’t need variables to reference classes, its use is not common. One example is:
Class someClass = Nil;
Class anotherClass = [NSString class];
NULL is the literal null value for arbitrary C pointers. For instance,
int *pointerToInt = NULL;
char *pointerToChar = NULL;
struct TreeNode *rootNode = NULL;
NSNull is a class for objects that represent null. In fact, there’s only one object, namely the one returned by +[NSNull null]. It is different from nil because nil is a literal null value, i.e., it isn’t an object. The single instance of NSNull, on the other hand, is a proper object.
NSNull is often used in Foundation collections since they cannot store nil values. In the case of dictionaries, -objectForKey: returns nil to indicate that a given key has no corresponding object in the dictionary, i.e., the key hasn’t been added to the dictionary. If you want to make it explicit that you have a certain key but it doesn’t have a value yet, you can use [NSNull null].
For instance, the following throws an exception because dictionaries cannot store nil values:
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:nil forKey:#"someKey"];
On the other hand, the following code is valid since [NSNull null] is a non-nil object:
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:[NSNull null] forKey:#"someKey"];
It’s worth mentioning that Foundation collections have initialisers that use nil as a marker for the end of a list of objects without having to specify the number of elements in the list. This can only happen because nil cannot be stored in a Foundation collection. For instance,
NSArray *array = [NSArray arrayWithObjects:#"one", #"two", nil];
As for NIL or NSNil, there are no such things in Objective-C or Apple Foundation.
I am not sure but i think nil should only be used in place of an id, what Java and C++ programmers would think of as a pointer to an object. Use NULL for non-object pointers.
nil is usually used for an Objective-C object type, while NULL is used for c-style pointers
Nil,Null and nil are used with below
1> Nil for Objective c Class
2> nil for Objective c object
3> Null for C pointer
Example:
1>Class A=Nil;
2>NSString strName=nil;
3>char *pointerChar = NULL;
Suppose you have a class MyClass
then by convention nil is used if you want to initialize its instance to null value (same as null in java)
i.e.
MyClass *obj = nil;
and if you want to initialize a primitive pointer to null value (same as in c) you use
int *ptr = NULL;
and if you want to initialize to Class reference to null value (same as null in java) then use
Class classRefOfMyClass = Nil;
It's just a convention otherwise Nil or nil have same meaning and perhaps NULL , nil or Nil all are same.
Here is the definition for these in objc.h file
#ifndef Nil
# if __has_feature(cxx_nullptr)
# define Nil nullptr
# else
# define Nil __DARWIN_NULL
# endif
#endif
#ifndef nil
# if __has_feature(cxx_nullptr)
# define nil nullptr
# else
# define nil __DARWIN_NULL
# endif
#endif
And in stddef.h
#define NULL ((void*)0)
And the definition of __DARWIN_NULL in _types.h
#define __DARWIN_NULL ((void *)0)
So there is no difference logically. The main idea here is to initialize a pointer whether C or Objective-C to 0. If you have knowledge of C then you can assign
int *ptr = 0;
without type casting 0 to a pointer. As you don't need to typecast 0 to assign it to a pointer.
In short they all are 0 and nothing else.
This will help you to understand the difference between nil,NIL and null.
All three of these values represent null, or zero pointer, values. The
difference is that while NULL represents zero for any pointer, nil is
specific to objects (e.g., id) and Nil is specific to class pointers.
It should be considered a best practice of sorts to use the right null
object in the right circumstance for documentation purposes, even
though there is nothing stopping someone from mixing and matching as
they go along.
The below link may help you in some way:
http://nshipster.com/nil/
Here is some important part from the link:
nil, NIL and null. is depended on your requirement.
NSNull
collections like NSArray and NSDictionary not being able to contain nil values.
NSMutableDictionary *MymutableDictionary = [NSMutableDictionary dictionary];
MymutableDictionary[#"someKey"] = [NSNull null]; // Sets value of NSNull singleton for "someKey"
NSLog(#"Keys: %#", [mutableDictionary allKeys]);
nil
all pointers that object has to other objects begin as nil, so it's unnecessary to, for instance, set self.(association) = nil in init methods.
In other languages, like C++, this would crash your program, but in Objective-C, invoking a method on nil returns a zero value.
if (name != nil)
{
........
}
Symbol Value Meaning
nil (id)0 literal null value for Objective-C objects
Nil (Class)0 literal null value for Objective-C classes
I thought that NSArray/NSDictionary/NSSet and their mutable subclasses just added the pointer to the object, and not the object it self.
So if set my "simple" object to nil after I added it to the container, why isn't the reference nil also in the Array (container)?
Here is the code:
NSMutableArray *array = [[NSMutableArray alloc] init];
Simple *simple = [[Simple alloc] init];
[array addObject:simple];
//Array sends retain, lets release
[simple release], simple = nil;
NSLog(#"Simple = \"<Simple: %p>", simple);
NSLog(#"Array: %#", array);
[array release], array = nil;
Here is the output:
2011-02-16 20:00:03.149 Allocations[5433:207] Simple = <Simple: 0x0>
2011-02-16 20:00:03.150 Allocations[5433:207] Array: (
<Simple: 0x4d3d4e0>
)
NSArray adds a pointer to the object. In order to track changes to variable, the array would have to add a pointer to the variable itself (remember, you're just setting the variable to nil, not the object). There can be many variables all pointing to the same object, and reassigning them won't change any others.
Remember: Pointers aren't magic. They're just ordinary variables whose value is a memory address — in this case, the memory address of an object. Two pointers to the same object aren't "linked" any more than two ints with the value 5. Changing the pointer doesn't affect the object; in order to affect the object, you have to either send it a message that causes it to change (e.g. [object setValue:6]) or dereference the pointer to access the object's members directly (e.g. object->value = 6).
PS: Don't access an object's members directly. It's bad and fragile and very prone to bugs. I just mentioned it here to explain how pointers work.
Setting simple = nil just makes that pointer point to nothing. It doesn't delete the object that the array still has a pointer to. At the point of your NSLog statements, the retainCount of the Simple instance that simple pointed to would be one.
Create simple
simple => (Simple instance: retain count 1)
Add to array
simple => (Simple instance: retain count 2)
[array objectAtIndex:0] => (Simple instance: retain count 2)
Release simple
simple => (Simple instance: retain count 1)
[array objectAtIndex:0] => (Simple instance: retain count 1)
Set simple = nil
simple => nil
[array objectAtIndex:0] => (Simple instance: retain count 1)
Release array
(Simple instance: retain count 0, subsequently destroyed)
NSArray does contain only a pointer to the object that is added, but that's ok -- it's not pointing to the simple pointer itself, but rather to the Simple object that simple pointed to. Thus in your example, after you change what simple points to, the array is still pointing at the original Simple object.
Actually my question here is: are null and nil equivalent or not?
I have an example but I am confused when they are equal when they are not.
NSNull *nullValue = [NSNull null];
NSArray *arrayWithNull = [NSArray arrayWithObject:nullValue];
NSLog(#"arrayWithNull: %#", arrayWithNull);
id aValue = [arrayWithNull objectAtIndex:0];
if (aValue == nil) {
NSLog(#"equals nil");
} else if (aValue == [NSNull null]) {
NSLog(#"equals NSNull instance");
if ([aValue isEqual:nil]) {
NSLog(#"isEqual:nil");
}
}
Here in the above case it shows that both null and nil are not equal and it displays "equals NSNull instance"
NSString *str=NULL;
id str1=nil;
if(str1 == str)
{
printf("\n IS EQUAL........");
}
else
{
printf("\n NOT EQUAL........");
}
And in the second case it shows both are equal and it displays "IS EQUAL".
Anyone's help will be much appreciated.
Thank you,
Monish.
nil and NULL are essentially the same, nil is something like (NSObject *)0, while NULL is more like (void *)0. But both are pointers with an integer value of zero. You can send messages to nil without raising an error.
NSNull and NULL (or nil, of course) are different things, however. You just use NSNull as a helper to add an empty object to an NSArray or another container class, since you can't add nil to them. So instead, you use [NSNull null] as a replacement, and you have to check if an array element is NSNull, not if it's nil (it will never be equal to nil).
From http://www.iphonedevsdk.com/forum/iphone-sdk-development/34826-nil-vs-null.html
nil and NULL are 100% interchangeable.
From:
NULL is for C-style memory pointers.
nil is for Objective-C objects.
Nil is for Objective-C classes.
Whenever you're writing Objective-C code, use nil
Whenever you're writing C code, use NULL
But ultimately they're all defined as the same thing -- (void *)0, I think -- so in practice it doesn't really matter.
The concept is the same, with the difference that it's valid to send messages (call method) to nil.
NSNull is a real (singleton) class, that can be used for arrays or dictionnaries, who don't accept NULL or nil values.
Biggest difference between them: sending a message to an NSNULL object is probably going to cause a crash, whereas it's cool to send any message to nil. For example, if you use a key path to get an array, like so:
NSArray *departmentNames = [departments valueForKey:#"name"];
Then you will have an NSNULL object for any department whose name is nil. So, this is going to cause a crash:
for (NSString *name in departmentNames)
NSLog(#"%#", [name lowercaseString]);
whenever name is NSNull, because you just sent an unknown selector (lowercaseString) to an NSNull.
Lesson: check for the NSNull object in an array before sending any message to its elements.
for (NSString *name in departmentNames)
if (name != [NSNull null])
NSLog(#"%#", [name lowercaseString]);
No, NSNull and nil are not the same. They both represent a lack of value, and you might want to treat them the same, but they are still not equal.
The NSNull object instance represents a null value, for example when you read data from a database that has null values.
The nil value is a null pointer, i.e. it doesn't point to any object instance.
In your second code you don't have any NSNull instance. An NSString pointer that contains a null pointer is not an NSNull instance, it's still just a null pointer. You are comparing one null pointer to another, and they are of course equal.
Make sure you typecast [NSNull null] to object type that you are comparing
NSArray list;
if(list==(NSArray *)[NSNull null])
// do something
otherwise you will receive a warning message saying "Comparison of distinct pointer types('type *' and 'NSNull *')