NSInteger set to 0 but returns nil - objective-c

I have an NSInteger in my class like so
In #interface:
NSInteger currentRow;
#property (assign) NSInteger currentRow;
In #implementation:
#synthesize currentRow;
Doing [self setCurrentRow:0] seems to work fine, but using [self currentRow] just returns null for some reason, not sure why. When using breakpoints I can see that the value for currentRow is 0 so it has set fine, but I can't get the value back.

In Objective-C, it's important that you distinguish between objects and primitive types.
An object is always stored as a pointer, which is the object's location in memory. A pointer is just a number. With NSLog, you can use %p to see this value. You can display it in the debugger too, like this: print myObject. A pointer is displayed as a hexadecimal number, with a 0x prefix. nil is essentially location zero (0x0000). When you allocate any kind of object, you'll get a pointer which isn't zero. When you assign an object to a variable, you are simply copying the memory address, not duplicating the object. With NSLog, you can use %# to print out an object's description. In the debugger, like this: print-object myObject.
Primitive types like NSInteger aren't objects. Instead of storing a pointer, usually you just store the value. When you assign an NSInteger variable, you make a copy of the value. You can see the value in the debugger using print. Or like this: NSLog("%ld", (long)currentRow). When you assign a primitive, you copy its value. Don't use %# or print-object with primitives — they expect objects.
(I say "usually you just store the value," because you can make pointers to primitive types, too. In situations like yours however it's not necessary.)
[self currentRow] returns 0, just like you set it. (Furthermore, because Objective-C guarantees initialization of instance variables, it'll return 0 even if you don't set it.)
The problem is that you're expecting a pointer to an object. How you fix your code depends on how you're using it:
If you're using print-object currentRow, change it to print currentRow.
If you're using NSLog("%#", currentRow), change it to NSLog(%"ld", (long)currentRow).
If you're using currentRow somewhere else, where an object is required, change your instance variable and property types to NSNumber *, an object type. Set it with [self setCurrentRow:[NSNumber numberWithInt:0]].

NSInteger is not object, it's typedef'd to int or something like that. Thus, if you set currentRow to 0 and then try to get it back, null (aka 0) is totally correct value.

The getter method will be synthesized as - (NSInteger)currentRow so it should work just fine. But how do you check if it works? With NSLog(#"%#", ...)? Than you should use %d.
If you want it to be an object you should use NSNumber and a retain property.

Related

NSMutableDictionary and mutableCopy

I'm confused by the code, below. Before I added the mutableCopy line, it didn't work. After I added the line, it did.
Why isn't aDict mutable to begin with? I declared aDict as an NSMutableDictionary.
- (void) myRoutine: (NSMutableDictionary *) dictOfDicts
{
NSMutableDictionary * aDict = dictOfDicts[dictOfDictsKey];
int data = [aDict[aDictKey] intValue];
aDict = [aDict mutableCopy];
aDict[aDictKey] = #(++data);
}
The declaration of dictOfDicts says it's a pointer to a mutable dictionary. However, it does not use Objective-C generics syntax to say what the types of the keys or values are. So, the most we (and the compiler) can assume is that the keys are id<NSCopying> and the values are id, completely generic object pointers.
You then initialize your aDict variable with a value obtained from dictOfDicts. You've declared that aDict is also a pointer to a mutable dictionary. That's its "static type", but the real type of the object it points to is determined at runtime by whatever object is held in dictOfDicts under that key. It might be a mutable dictionary or it might be something else. It compiles just find because the compiler can't know what type of object that value is.
However, the real type (a.k.a. "dynamic type") of the object governs what operations succeed or fail/crash/whatever. In your case, it sounds like it's an immutable dictionary. So, when you attempt to mutate it, "it didn't work" (you don't specify what actually happened).
You make a mutable copy and you're allowed to mutate that. However, that's now a separate object that the one in dictOfDicts. So, you're not modifying what you think you are.
The solution is to put mutable dictionaries into dictOfDicts in the first place. Or, even better, put objects of a custom class of your own design into it, and operate on real properties.

Int set to 0 but displaying nil [duplicate]

I have an NSInteger in my class like so
In #interface:
NSInteger currentRow;
#property (assign) NSInteger currentRow;
In #implementation:
#synthesize currentRow;
Doing [self setCurrentRow:0] seems to work fine, but using [self currentRow] just returns null for some reason, not sure why. When using breakpoints I can see that the value for currentRow is 0 so it has set fine, but I can't get the value back.
In Objective-C, it's important that you distinguish between objects and primitive types.
An object is always stored as a pointer, which is the object's location in memory. A pointer is just a number. With NSLog, you can use %p to see this value. You can display it in the debugger too, like this: print myObject. A pointer is displayed as a hexadecimal number, with a 0x prefix. nil is essentially location zero (0x0000). When you allocate any kind of object, you'll get a pointer which isn't zero. When you assign an object to a variable, you are simply copying the memory address, not duplicating the object. With NSLog, you can use %# to print out an object's description. In the debugger, like this: print-object myObject.
Primitive types like NSInteger aren't objects. Instead of storing a pointer, usually you just store the value. When you assign an NSInteger variable, you make a copy of the value. You can see the value in the debugger using print. Or like this: NSLog("%ld", (long)currentRow). When you assign a primitive, you copy its value. Don't use %# or print-object with primitives — they expect objects.
(I say "usually you just store the value," because you can make pointers to primitive types, too. In situations like yours however it's not necessary.)
[self currentRow] returns 0, just like you set it. (Furthermore, because Objective-C guarantees initialization of instance variables, it'll return 0 even if you don't set it.)
The problem is that you're expecting a pointer to an object. How you fix your code depends on how you're using it:
If you're using print-object currentRow, change it to print currentRow.
If you're using NSLog("%#", currentRow), change it to NSLog(%"ld", (long)currentRow).
If you're using currentRow somewhere else, where an object is required, change your instance variable and property types to NSNumber *, an object type. Set it with [self setCurrentRow:[NSNumber numberWithInt:0]].
NSInteger is not object, it's typedef'd to int or something like that. Thus, if you set currentRow to 0 and then try to get it back, null (aka 0) is totally correct value.
The getter method will be synthesized as - (NSInteger)currentRow so it should work just fine. But how do you check if it works? With NSLog(#"%#", ...)? Than you should use %d.
If you want it to be an object you should use NSNumber and a retain property.

Obj-c let me change the class of a variable, and its bad: How hunt it?

Well, in obj-c have the ability of change the class of a declared var. So if I declare myVar as a NSString, is possible to get back later a NSNUmber.
I have this problem now, but I can't find where in my code is the identity swap... exist a way to find it? For example is possible to set a breakpoint where [myVar class] == [NSString class] and when change know it?
You may be confused about the static type of a pointer, and the actual type of the object it points to. Consider this code:
NSString *test = #"test";
NSNumber *notReallyANumber = (NSNumber *)test;
This is valid code, but it didn't "transform" test into an NSNumber. It's still a string, just with an incorrect type on the pointer.
Basically, no, you don't have the ability to change the class of a variable (you do, but it's deep deep magic and almost never occurs).

Objective-c dealloc of boolean value

How would I dealloc a boolean value?
Deallocing it this way below gives me a warning: Incompatible pointer to integer conversion assigning to 'BOOL' (aka 'signed char') from 'void *'
- (void)dealloc {
self.booleanVar = nil;
[super dealloc];
}
Perhaps I should clarify, this is from a simple class inherited from NSObject.
I'm using the self.var = nil pattern that you see in Cocoa Touch classes. Let's say if it was an NSString* instead should I use self.var = nil or [var release] in the deallocmethod? I'm a little confused here.
You don't need to do it. It is not an object. This also explains the warning, as you're trying to assign a nil pointer (that's a NULL for objects basically) to a non-object.
Regarding your second question, yes. You can think of primitive variables as being part of the object, so when it's deallocated the vars will not exist anymore.
But when you have a NSString * in an object, it's just a pointer to another object. If you dealloc the former, the pointer will be deleted, not the NSString. No one might point to it, it's kind of lost in the air, occupying memory. So, before deleting the pointer, if you won't need the object anymore, you send it a release message. That's done in the dealloc method, since it's called to "delete" and object and thus is a good place to delete also every other object that has no use anymore.
You dont need to dealloc a BOOL, since BOOLs are really just a byte, which is a primitive data type. You only need to dealloc objects which have been allocated to memory.
First of all, if booleanVar is just a plain BOOL value, as in it is declared like so:
BOOL booleanVar;
then you do not need to free up any memory associated with it, since that memory is allocated and freed when the class that holds it is allocated and deallocated. So no code for booleanVar in dealloc will be fine.
However, if you are talking about a pointer for a BOOL, defined like so:
BOOL *booleanVar;
and what you want is to set this variable to a non-value, you should set it equal to NULL instead of nil, since NULL is for value pointers and nil is for object pointers (see: NULL vs nil in Objective-C).
However, if what you want is to free up the memory that the BOOL pointer points to, allocated with malloc or realloc, etc, then try the free() C function (see: http://www.cplusplus.com/reference/clibrary/cstdlib/free/).
What would really clear all this up is if you showed us the property declaration for booleanVar in the class interface, which would tell us exactly what you want to do and you would get an answer with complete certitude.

How to convert an pointer to become a object?

I using something like this : [tmpArray insertObject:something[i] atIndex:i];
But I got a MSG : passing argument 1 of "insertObject:atIndex:" makes pointer from integer without a cast.
What should I do to fix it?
I guess your something[] array is a C array of int, if this is the case you cannot pass its value at that position into an NSArray since it contains objects (and objects in obj-C are referenced by pointers).
What you could do is wrap the int into a NSNumber this way:
[tmpArray insertObject:[NSNumber numberWithInt:something[i]] atIndex:i];
You can't magically make random pointer into an object, you need to understand what the type of the pointer is and do something semantically reasonable with that type. Also, that is not what the error you are seeing is about. The error is because the type expected is a pointer (and an object in ObjC is also a pointer type), and the type info of the thing you are passing is a scalar.
Taking a wild guess, something is probably an array of ints, if so what you want to do is wrap is the integer in an NSNumber in order to store it in a collection:
//assuming this:
int something[100];
//then your line should be this:
[tmpArray insertObject:[NSNumber numberWithInt:something[i]] atIndex:i];
Obviously you will need to unbox the value anywhere you access it. If it is not an array of integers then you will need to do something else (though probably similiar), but without more info I can't tell you exactly what.