Below is my Response
geolocation = {
loc = {
lat = "22.4409980000000004451976565178";
long = "70.0686230000000023210304789245";
};
};
My app crashes when I try below code:
NSNumber* n = [userPin valueForKeyPath:#"geolocation.loc.lat"];
NSLog(#"num is class %#", NSStringFromClass([n class]));
float fCost = [n floatValue];
When I print my NSStringFromClass I get __NSSingleObjectArrayI.
Any suggestion how to fix this?
At a guess the (runtime) type of userPin is array and it contains one element. When applied to an array valueForKey:, on which valueForKeyPath: is based, returns an array produced by applying itself to every element of the array.
If this is the case either index userPin before the call or handle the array resulting from the call.
Addendum
Could you give me an example?
Trivial example:
// An array of strings
NSArray *test = #[ #"The", #"quick", #"brown", #"fox"];
// Trivial keypath...
NSArray *result = [test valueForKeyPath:#"length"];
// Print
NSLog(#"%#", result);
Produces:
(
3,
5,
5,
3
)
showing result is an array of the result of applying length to each element of `test. HTH
Related
in response, i am getting gas_cylinders key as single array object
"gas_cylinders":["[{\"quantity\":\"2\",\"name\":\"Medium Blue\",\"price\":\"100.0\",\"total_price\":\"200.0\"},{\"quantity\":\"3\",\"name\":\"Green\",\"price\":\"100.0\",\"total_price\":\"300.0\"},{\"quantity\":\"1\",\"name\":\"Dark Green\",\"price\":\"100.0\",\"total_price\":\"100.0\"}]"]
Note:- tripDictionary contain below data..
(lldb) po tripDictionary
{
"gas_cylinder_total" = 600;
"gas_cylinders" = (
"[{\"quantity\":\"2\",\"name\":\"Medium Blue\",\"price\":\"100.0\",\"total_price\":\"200.0\"},{\"quantity\":\"3\",\"name\":\"Green\",\"price\":\"100.0\",\"total_price\":\"300.0\"},{\"quantity\":\"1\",\"name\":\"Dark Green\",\"price\":\"100.0\",\"total_price\":\"100.0\"}]"
);
}
i am taking gas_cylinders like below way..
NSArray *arr = [tripDictionary valueForKey:#"gas_cylinders"];
if (arr && arr.count > 0) {
NSLog(#"first obj = %#",arr[0]);
}
output of above NSLog like..
first obj = [{"quantity":"2","name":"Medium Blue","price":"100.0","total_price":"200.0"},{"quantity":"3","name":"Green","price":"100.0","total_price":"300.0"},{"quantity":"1","name":"Dark Green","price":"100.0","total_price":"100.0"}]
how can i get this object in NSMutableArray ?
The data is not what you think it is. The value of the gas_cylinders key is an array of JSON string.
NSArray *cylinders = tripDictionary[#"gas_cylinders"];
NSString *firstCylinder = cylinders[0];
At this point, firstCylinder is a JSON string. You need to parse that JSON string to get the desired array of dictionaries contained in the JSON string.
so I have this method that returns a letter (from A-Z) by creating a random number between 1-26 and then indexing a string array to pull out the letter. The only problem is that it does not generate a new letter when the method is called. How can I generate a new letter every time the method is called, like in a while loop. Here is my code:
-(NSString *)alphaGenerator{
NSUInteger randomLetterInteger = arc4random_uniform(26);
NSArray *alphabet = #[#"A",#"B",#"C",#"D",#"E",#"F",#"G",#"H",#"I",#"J",#"K",#"L",#"M",#"N",#"O",#"P",#"Q",#"R",#"S",#"T",#"U",#"V",#"W",#"X",#"Y",#"Z"];
NSString *alpha = alphabet[randomLetterInteger];
return alpha;
}
Also, how do I convert a number that is returned from the count method into a number that I can plug into the arc4random_uniform method? I receive the 'incompatible integer to pointer inversion initializing...' error. This is what I have for this:
-(NSUInteger)numOfDictions{
NSString *alpha = [self alphaGenerator];
NSUInteger numb = [cuisines[alpha] count];
NSUInteger *randomNumOfDictions = arc4random_uniform(numb);
return *randomNumOfDictions;
}
These two lines:
NSUInteger *randomNumOfDictions = arc4random_uniform(numb);
return *randomNumOfDictions;
should be:
NSUInteger randomNumOfDictions = arc4random_uniform(numb);
return randomNumOfDictions;
NSInteger is not an object type. It's a primitive type.
I was trying a piece of code from CS193P course (Objective-C). I noticed something in the way that the compiler works. An NSMutableArray called photos was added to an NSMutableDictionary, photosByPhotographer. Later on, a change was made to photos without any changes to photosByPhotographer. When I logged photosByPhotographer, the change was automatically applied to it and it did not need any extra lines of code!
I wonder how the compiler makes this work? Any materials to read from?
The code is as follows:
- (void)updatePhotosByPhotographer
{
NSMutableDictionary *photosByPhotographer = [NSMutableDictionary dictionary];
for (NSDictionary *photo in self.photos) {
NSString *photographer = [photo objectForKey:FLICKR_PHOTO_OWNER];
NSMutableArray *photos = [photosByPhotographer objectForKey:photographer];
if (!photos) {
photos = [NSMutableArray array];
[photosByPhotographer setObject:photos forKey:photographer];
NSLog(#"photosByPhotographer in if: %#", photosByPhotographer);
}
[photos addObject:photo];
NSLog(#"photosByPhotographer after if: %#", photosByPhotographer);
}
self.photosByPhotographer = photosByPhotographer;
}
The NSLog() result is as follows:
2012-07-20 20:05:57.618 Shutterbug[453:f803] photosByPhotographer in if: {
Dowbiggin = (
);
}
2012-07-20 20:05:57.620 Shutterbug[453:f803] photosByPhotographer after if: {
Dowbiggin = (
{
accuracy = 16;
context = 0;
dateupload = 1342836026;
description = {
"_content" = "";
};
farm = 9;
"geo_is_contact" = 0;
"geo_is_family" = 0;
"geo_is_friend" = 0;
"geo_is_public" = 1;
id = 7612787270;
isfamily = 0;
isfriend = 0;
ispublic = 1;
latitude = "37.307085";
longitude = "-121.900395";
originalformat = jpg;
originalsecret = 052e70d412;
owner = "22751315#N05";
ownername = Dowbiggin;
"place_id" = cils8sJUV7MeXHwt9A;
secret = 4437007c99;
server = 8161;
tags = "square squareformat iphoneography instagramapp uploaded:by=instagram foursquare:venue=49f13597f964a5209c691fe3";
title = "My little goofball";
woeid = 55971033;
}
);
}
That's because in Cocoa, you are using objects and pass by reference.
Imagine this code:
NSMutableArray *a, *b;
a = [NSMutableArray new];
[a addObject:#"A"]; // a contains #"A"
b = a; // b is assigned to the same object
[b addObject:#"B"]; // a and b contain #"A", #"B"
NSLog(#"a = %p and b = %p", a, b); // same values
The variables a and b point to the same object. You can also see that by comparing the pointer values.
However, if we do the following:
NSMutableArray *a, *b;
a = [NSMutableArray new];
[a addObject:#"A"]; // a contains #"A"
b = [[a mutableCopy] autorelease]; // b is assigned to a COPY of the object
[b addObject:#"B"]; // b contains #"A", #"B", while a still contains #"A"
NSLog(#"a = %p and b = %p", a, b); // NOT the same values
b is assigned to a copy of a (not the original), so b points to an other object. You can check by comparing the addresses of the objects.
The photos arrays is stored by reference in the NSDictionary, not as a copy. Therefore, if you change the underlying array, you will see that when you access the dictionary.
This is why it can be dangerous to provide some mutable types by reference instead of storing copies of them.
You need to understand how pointers and references work. Basically rather than variables in your code being actual full structures and objects, generally they are references or pointers to those structures. You can visualise the concept in a number of ways, but perhaps one that's useful is to think of a variable such as:
NSDictionary *myDict;
being really just a number which is the memory address of the myDict object. Here's a visualisation of how it works:
Your NSDictionary reference points to an object in memory which itself holds multiple references to other objects, which can be changed without affecting the dictionary itself. In this example I've shown an NSArray having a new object added to it. The reference to the array from the dictionary remains the same. There is only ever one instance of the array and the objects in it at any time.
When you call NSLog on an NSDictionary object then its method description is called.
In the implementation of the method description, NSDictionary is calling the description method of each value (object) of all its keys.
So when a value (object) changes so does the output of its description method change.
That is why it is reflected when calling NSLog on an NSDictionary object again.
Returning an array (Warning: Function returns address of local variable) ?
interface
int* decimalConversion(int iX);
implementation
int* decimalConversion(int iX){
int iMult[10] = {0,0,0,0,0,0,0};
...
return iMult; // <-- Warning: Function returns address of local variable
}
You should allocate space for the array, you're returning the address of an array that was created on the stack (hence local variable warning) if you're using C in that function use malloc(my_arr_size) if not use obj-c's alloc.
Example:
int *my_arr = calloc(10, sizeof(int)); //make sure we get zeroed memory
//fill array
return my_arr; //should no longer give a warning
When done with it just use free(my_arr) same as release. Reason I did this in C is because I can see that you're returning an int* type and using C style declarations so if you're doing it in Obj-c let me know and I can change my answer's example.
The reason you are getting this error is because local arrays get put on the stack, when you return that array you return an address in a stack frame. The problem is that when that method finishes execution that stack frame is no longer valid and therefore you cannot expect any data that was on that frame to be valid (although there are cases when this does work but it is considered bad practice). By allocating that array on the heap you can return a heap address where your data is assured to exist until you call free() on the pointer to that data.
If you are doing this for an app written in Objective-C, I would suggest using NSArray. NSArray is an Objective-C class for immutable arrays, and doesn't require that you manually allocate memory. The only turnoff is that you have to encapsulate your integers in NSNumber objects. An example would be:
NSArray * getNums (int num) {
NSArray * result = [NSArray arrayWithObjects:[NSNumber numberWithInt:num-1], [NSNumber numberWithInt:num], [NSNumber numberWithInt:num+1], nil];
return result;
}
...
NSArray * myList = getNums(10);
NSLog(#"First: %d", [[myList objectAtIndex:0] intValue]);
NSLog(#"Second: %d", [[myList objectAtIndex:1] intValue]);
NSLog(#"Third: %d", [[myList objectAtIndex:2] intValue]);
You can alternatively do this:
NSArray * getNums (int num) {
NSMutableArray * array = [NSMutableArray array];
[array addObject:[NSNumber numberWithInt:num-1]];
[array addObject:[NSNumber numberWithInt:num]];
[array addObject:[NSNumber numberWithInt:num+1]];
return array;
}
...
NSArray * myList = getNums(10);
for (int i = 0; i < [myList count]; i++) {
NSLog(#"myList[%d] = %d", i, [myList objectAtIndex:i]);
}
The only difference is that NSMutableArray allows you to add/remove elements after the fact.
I want to get the type of NSNumber instance.
I found out on http://www.cocoadev.com/index.pl?NSNumber this:
NSNumber *myNum = [[NSNumber alloc] initWithBool:TRUE];
if ([[myNum className] isEqualToString:#"NSCFNumber"]) {
// process NSNumber as integer
} else if ([[myNum className] isEqualToString:#"NSCFBoolean"]) {
// process NSNumber as boolean
}
Ok, but this doesn't work, the [myNum className] isn't recognized by the compiler.
I'm compiling for iPhone.
I recommend using the -[NSNumber objCType] method.
It allows you to do:
NSNumber * n = [NSNumber numberWithBool:YES];
if (strcmp([n objCType], #encode(BOOL)) == 0) {
NSLog(#"this is a bool");
} else if (strcmp([n objCType], #encode(int)) == 0) {
NSLog(#"this is an int");
}
For more information on type encodings, check out the Objective-C Runtime Reference.
You can get the type this way, no string comparisons needed:
CFNumberType numberType = CFNumberGetType((CFNumberRef)someNSNumber);
numberType will then be one of:
enum CFNumberType {
kCFNumberSInt8Type = 1,
kCFNumberSInt16Type = 2,
kCFNumberSInt32Type = 3,
kCFNumberSInt64Type = 4,
kCFNumberFloat32Type = 5,
kCFNumberFloat64Type = 6,
kCFNumberCharType = 7,
kCFNumberShortType = 8,
kCFNumberIntType = 9,
kCFNumberLongType = 10,
kCFNumberLongLongType = 11,
kCFNumberFloatType = 12,
kCFNumberDoubleType = 13,
kCFNumberCFIndexType = 14,
kCFNumberNSIntegerType = 15,
kCFNumberCGFloatType = 16,
kCFNumberMaxType = 16
};
typedef enum CFNumberType CFNumberType;
If all you want is to differentiate between booleans and anything else, you can make use of the fact that boolean NSNumbers always return a shared instance:
NSNumber *num = ...;
if (num == (void*)kCFBooleanFalse || num == (void*)kCFBooleanTrue) {
// num is boolean
} else {
// num is not boolean
}
NSNumber explicitly doesn't guarantee that the returned type will match the method used to create it, so doing this at all is probably a bad idea.
However, you could probably do something like this (you could also compare to objc_getClass("NSCFNumber") etc., but this is arguably more portable):
Class boolClass = [[NSNumber numberWithBool:YES] class];
/* ... */
if([myNum isKindOfClass:boolClass]) {
/* ... */
}
In Swift:
let numberType = CFNumberGetType(answer)
switch numberType {
case .charType:
//Bool
case .sInt8Type, .sInt16Type, .sInt32Type, .sInt64Type, .shortType, .intType, .longType, .longLongType, .cfIndexType, .nsIntegerType:
//Int
case .float32Type, .float64Type, .floatType, .doubleType, .cgFloatType:
//Double
}
Use the method -[NSNumber objCType] method to get the type.
If the type's equal to #encode(BOOL), or the number itself is kCFBooleanFalse, or kCFBooleanTrue, it's a boolean.
If it's anything else but 'c', it's a number.
If it's 'c', what appears to be the only way supported way, without checking against private class names, or comparing against undocumented singletons, is to turn make an array of one element, the number, and then use NSJSONSerialization to get the string representation. Finally, check if the string representation contains the string "true" or "false". Here is the full code for checking if an NSNumber is a BOOL:
-(BOOL)isBool
{
if(!strcmp(self.objCType, #encode(BOOL)) ||
self == (void*)kCFBooleanFalse ||
self == (void*)kCFBooleanTrue)
{
return YES;
}
if(strcmp(self.objCType, "c"))
{
return NO;
}
NSString * asString = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:#[self] options:kNilOptions error:nil] encoding:NSUTF8StringEncoding];
return [asString containsString:#"true"] || [asString containsString:#"false"];
}
Note that using NSJSONSerialization is slow and if #NO/#YES ever stops always equalling kCFBooleanFalse/kCFBooleanTrue, then this method probably shouldn't be used in a tight loop.
The reason the compiler warns you and it doesn't work is because -[NSObject className] is declared in a category on NSObject on Mac OS X (in NSScriptClassDescription.h) and not declared on iPhone. (It doesn't support AppleScript, obviously.) NSStringFromClass([myNum class]) is what you should use to be safe across all platforms. Odds are that -className is declared as a simple wrapper around NSStringFromClass() anyway...
NSString *classString = NSStringFromClass([myNum class]);
That should ger the string you want.
To check that NSNumber contains a bool value Try this:
if (strcmp([myNumber objCType], [#(YES) objCType]) == 0)
NSLog(#"%#", [myNumber boolValue] ? #"true" : #"false");
objCType documentation states that The returned type does not necessarily match the method the number object was created with
Secondly, other methods of comparing the class of number to a given class type or assuming boolean number instances to be shared singletons are not documented behaviour.
A more(not completely though) reliable way is to depend on NSJSONSerialisation as it correctly recognises number instances created with bool and outputs true/false in json. This is something we can expect Apple to take care of while moving with new SDKs and on different architectures. Below is the code:
+(BOOL) isBoolType:(NSNumber*) number {
NSError* err;
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:#{#"key":number}
options:0
error:&err];
NSString* jsonString = [[NSString alloc]
initWithData:jsonData
encoding:NSUTF8StringEncoding];
return [jsonString containsString:#"true"]
|| [jsonString containsString:#"false"];
}
Swift Version
NSNumber is a class-cluster so each underlying type can be figured from the instance. This code avoids hard-coding the different NSNumber types by creating an instance of the expected type, and then comparing it against the unknown type.
extension NSNumber {
var isBool: Bool {
return type(of: self) == type(of: NSNumber(booleanLiteral: true))
}
}
check object is of NSNumber type :
if([obj isKindOfClass:NSClassFromString(#"__NSCFNumber")])
{
//NSNumber
}