I have an app in which I pass an dictionary of type [string:[int]] from a swift file to an objective c file, then as NSDictionary. Through that process, the data formats get all screwed up, but in the end I am able to access each array of ints from a string, as would be expected from an NSDictionary. Unfortunately, somewhere along the line the integers get converted to type 'id', and to change that back to int, I did this:
NSLog(#"%d",(int)theThreeNotes[#"0"][0])
theThreeNotes[#"0"][0] should be 0, but it is logged as 55. How do you fix this?
If the dictionary is passed to Objective-C, all the integers will become NSNumber instances. NSDictionary/NSArray cannot hold primitive values. That means you will have to call integerValue on the number, not cast it blindly to int.
Or just print it using:
NSLog(#"%#", theThreeNotes[#"0"][0])
Related
Plists seem to have a limited number of data types that you can enter in. However, I know there are loopholes, such as storing an int as a Number and then using [x integerValue] to set it back to an int. Is there a similar workaround for storing typedef enums in a property list?
Since they are really just ints, is there some way to store them as Numbers and then casting them as their typedef?
You would have to store the raw enum integer values and then load them out again as integers. Once you've loaded them out again as NSNumbers you can then use [num intValue] to get the integer. Then you can compare it to your enum, for example:
intRep = [loadedNumber intValue];
if (intRep == MY_ENUM_CONSTANT) {
// Do something...
}
// ... etc.
To store the value "MY_ENUM_CONSTANT" as a string inside the plist doesn't have any meaning - and reverse engineering it if -isEqualToString is definitely fighting the system. If you need more flexibility though you may be able to store binary data objects inside the plist, this is probably overdoing it a bit for what you need though.
You will need to translate them into a format suitable for plist, you can use the integer value is the simplest and use NSNumber, but you can alternatively write a couple of functions to convert to and from a string value. If you use the default integers for for enum, 0, 1, 2 etc. You can then use the enum as an index into an array of string, to get from string back to enum/int, use a for loop thru your string array and return the matching index.
When I convert an array element to an integer using this statement
int test=(int)[myArray objectAtIndex:2];
later use of "test" passed to other commands fails.However, this statement works
int test=[[myArray objectAtIndex2]intValue];
What is the difference between these two types of conversion?
The first is a cast. You're taking the object and casting it to an int, which will give you an int that contains the address of the object (and under 64-bit it will only contain the low 32 bits of the address). This isn't at all what you want.
The second is a method call for -intValue, which is implemented by NSNumber (and NSString) to return the int that the NSNumber (or NSString) object represents. This is (presumably) what you actually want.
The first statement is not a conversion. It is a cast of the pointer stored as element 2 in your array. The statement just assigns value of that pointer (casted to an int) to the variable.
The second statement is a converstion. It calls -intValue on object that pointer stored at that index 2 points to (possibly a NSNumber instance).
- intValue works on objects of type NSString * and NSNumber *.
If your object is actually #"123", or an [NSNumber numberWithInt:123] instead of just int 123, then using - intValue will convert it to 123. If you try and cast it directly using (int) and it's one of the above two types, then you'll run into errors accessing it as an int (because it's not, it's a more complex type).
I have a function that sets an entity within a Core Data store. I used to have all values it would be storing as type double, however now I must make it accommodate NSStrings as well. Consequently, I changed the type of the parameter the function takes in, to an id type. However, now I get the error:
error: incompatible type for argument 1 of 'numberWithDouble:'
...at the following lines:
//...
[dfm setTimeStamp:[NSNumber numberWithDouble:value]];
//...
[[fetchedObjects objectAtIndex:0] setValue:[NSNumber numberWithDouble:value] forKey:#"timeStamp"];
//...
Apparently it doesn't like the [NSNumber numberWithDouble:value] segment of each line. I was contemplating making a container class that holds an NSNumber type (doesn't Apple already have a class like this?) to get around this problem, but I thought that there has to be an easier way I am not thinking of (besides duplicating the function and changing the type of the value parameter). Any ideas? Thanks in advance!
EDIT:
Here is the function declaration:
-(void)setItemInDFMWhilePreservingEntityUniquenessForItem:(attribute)attr withValue:(id)value
attribute is merely an enum which specifies which entity to store within. The problem is that the compiler is giving me problems with value being of type id, theoretically I can pass in anything I want, and I believe the way I have it I am implying that I will be passing it as an NSNumber, but the compiler doesn't like that as that is not actually a class instance I suppose?
The problem is that the compiler is
giving me problems with value being of
type id, theoretically I can pass in
anything I want, and I believe the way
I have it I am implying that I will be
passing it as an NSNumber, but the
compiler doesn't like that as that is
not actually a class instance I
suppose?
By declaring value as id, you can pass any object you want. But why do you "suppose" that NSNumber isn't an object, when it's clearly documented as being an object? The warning isn't about passing an NSNumber instance when you've declared value as an id - that's perfectly valid, because id means "any object," and an NSNumber instance is an object. The warning comes from calling +numberWithDouble:, a method that takes a double for its first argument, and passing it value, which is declared as id - i.e. an object. You can't pass an object to a method that expects a double.
Your proposed solution, typecasting value with (NSInteger)value will silence the warning, but it won't fix the problem. The typecast simply converts the memory address the object pointer targets to an integer value. If (as your edit suggests) value is already an NSNumber object, what do you hope to gain by creating another one, or by typecasting its memory address to an integer? Just do:
[dfm setTimeStamp:value];
The problem lies with the value variable. It should be declared as a double (primitive) for this call to succeed.
edit: after rereading your question, do a check in the function on the type of value, if it is an NSString (use [value isKindOfClass:[NSString class]]) store it as such, if its not then its a double (if thats the only two types you are passing) and store it as such.
Can't you just pass the NSNumber instead of double?
Just realized that the call I was making (numberWithDouble:) was having the compiler check for a primitive, i.e. double. Changing it to the following worked like a charm:
[dfm setTimeStamp:[NSNumber numberWithInteger:(NSInteger)value]];
Thanks to those that responded!
In C, C++, C# you can have arrays of a certain type like int[].
In objC a NSArray can have a different type for every element.
If you want to have an NSArray of type x, you now can just treat the type of the element at index 0 as type of the array, meaning if [anArray objectAtIndex:0] is a NSString, you treat all objects as a NSString and throw an error, if any element is of a different type than the element at index 0. It is ugly, but you can simulate typed arrays that way.
Now, in C# it is even possible to have an empty array of type x with 0 elements.
However an empty NSArray of course has no element, not even at index 0, so there is no typeinfo in there.
Now if an objC app gets an array from a C# app or vice versa and the C# app in some situations sends or expects an empty array, the receiving side has to know the type of, how can get/set this typeinfo in objC?
Of course I could use C-arrays instead of NSArrays, but if you want to store a c-array in a NSDictionary, you have to put it into a NSValue first and a NSValue does not offer a possibility to store the size of a dynamically allocated c-array.
Is there any better option than to implement a new class "CArrayValue" for storing C_Arrays with typeinfo and size in a NSDictionary?
Make a wrapper for NSArray, one that contains a type key as instance variable and an NSArray. In that way you should be able to easily control the type of the array. Also what you could do to prevent adding types that are not allowed, is writing some methods that would remove / add items t o the array / initialize it.
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.