Simple question [Objective-C]: (Couldn't find any solution till now).
I'm aware of [id intValue];. However this crashes my app because NSString can be <Null> sometimes, in my app. I can easily perform a check whether this is ` or not and then take decision accordingly. However I have many such situations (not recursive to use for or so) and was wondering what is the best possible way to make sure that my app doesn't crash.
Any Help is sincerely appreciated.
EDIT:
In my situation, I get a JSON Response from my server. and I create a NSDictionary from it. However, in my response I may get <NSNull> (Exactly like this, Due to a problem in the server API. Objective-C consider this (id) as NSNull class. What should I look for in this kind of situations?
There is two most common ways:
First method:
Check, wether string can actually respond to intValue. Or check if it's NSString or NSNumber.
NSString *string = ...;
int intValue = ([string respondsToSelector:#selector(intValue)]) ? [string intValue] : 0;
For convenience you can write a macros for this
#define intValueFromAnyObject(obj) ([obj respondsToSelector:#selector(intValue)]) ? [obj intValue] : 0;
int intValue = intValueFromAnyObject(string);
Second way (I like it much more):
Write a category on NSNull so it won't crash when you send it an unrecognized selector (intValue for example)
#interface NSNull (myExtension)
- (int)intValue;
#end
#implementation NSNull (myExtension)
- (int)intValue
{
return 0;
}
#end
From now on any time you'll try to get intValue from an NSNull object, you will get 0.
int value = (string) ? [string intValue] : 0;
0 or other return value when string is nil
Related
void CountlyRecordEventSegmentationCountSum(const char * key, const char * segmentation, int count, double sum)
{
NSString * seg = CreateNSString(segmentation);
NSArray * entries = [seg componentsSeparatedByString:#"`"];
NSDictionary * dict = [NSDictionary dictionary];
for (id entry in entries)
{
NSArray * keyValue = [entry componentsSeparatedByString:#"|"];
[dict setValue:[keyValue objectAtIndex:1] forKey:[keyValue objectAtIndex:0]];
}
[[Countly sharedInstance] recordEvent:CreateNSString(key) segmentation:dict count:count sum:sum];
}
I put "?" in the title because I'm not entirely sure if the problem is in the code above but that's my best guess. I'm integrating Countly iOS plugin with Unity and one of Countly plugin's methods take NSDictionary * as argument. As I don't know how to send a dictionary from C# to Objective-C I'm storing my dict in a string, sending it to Objective-C and then recreating the dictionary (the code above).
But that's probably even not relevant. I know EXC_BAD_ACCESS usually has something to do with unfreed resources or sth so maybe you can see what I'm doing wrong (I don't know Objective-C at all, just writing a few lines needed by the plugin).
Edit:
From Unity sample:
// Converts C style string to NSString
NSString * CreateNSString (const char * string)
{
if (string)
return [NSString stringWithUTF8String: string];
else
return [NSString stringWithUTF8String: ""];
}
The error you've made is that you are trying to modify immutable version of NSDictionary.
One cannot modify contents of the NSDictionary after it's initialization. You should use NSMutableDictionary instead.
Here is a documentation on NSMutableDictionary.
And here is an example of how to create mutable version of an immutable object that conforms to NSMutableCopying protocol.
You need to be using NSMutableDictionary, you can't modify an NSDictionary.
Also, you should use setObject:forKey: because setValue:forKey: is a KVC method. It happens to do the same thing on an NSMutableDictionary for most keys, but it is marginally slower.
Finally, you should check that [keyValue count] >= 2 before trying to access the objects at indexes 0 and 1.
Edit Also, CreateNSString() looks suspicious. It might be either leaking or prematurely releasing the string. But you need to post the code. In any case, I'd use
seg = [NSString stringWithUTF8String: segment];
or, other appropriate method if segment is not encoded in UTF-8.
I have a PList where I load a couple of rows of data in a dictionary. I want to add the a line like
<key>StandardValue</key>
<string>STANDARDVALUEFORCERTAININSTANCE</string>
Now when I read out the values I get a NSString. How can I get the value of the constant that I previously defined with
#define STANDARDVALUEFORCERTAININSTANCE 123
Is there a way to get the constant representation of a string? So essentially to parse it?
What you want to do isn't exactly possible. The constants created with #define only exist at compile-time, and at run time there is no way to access them by name - they have been converted to the constant value already.
One alternative that might exist is to define a number of methods that return constant values, say in a Constants class. Then, at run time, load the name of the method from the plist and call it using NSSelectorFromString() and performSelector:.
However, a possible issue with this is that for safety with performSelector: you'd have to rewrite all your constants as Objective-C objects (since performSelector: returns type id). That could be quite inconvenient.
Nevertheless, here is an example implementation of the Constants class:
#implementation Constants : NSObject
+ (NSNumber *)someValueForACertainInstance
{
return #123;
}
#end
And example usage:
NSDictionary *infoDotPlist = [[NSBundle mainBundle] infoDictionary];
NSString *selectorName = infoDotPlist[#"StandardValue"];
SEL selector = NSSelectorFromString(selectorName);
NSNumber *result = [Constants performSelector:selector];
And how the selector name would be stored in the info plist:
<key>StandardValue</key>
<string>someValueForACertainInstance</string>
You can't do it this way. I suggest a nice alternative: KVC.
You declare this variable as class instance:
#property (nonatomic,assign) int standardValueForCertainInstance;
Then you get the value with valueForKey:
NSString* key= dict[#"StandardValue"];
int value= [[self valueForKey: key] intValue];
I encountered a strange problem regarding CoreData and boolean values:
In my data model I have set an entity's property to BOOL. Later I set theEntity.theBooleanValue = [NSNumber numberWithBool:NO] and save the object. So far so good, but when I try to check for the saved property's value with if ([theObject valueForKey:#"theBooleanValue"] == [NSNumber numberBOOL:NO]){//do something} it never jumps into the if clause. But if I check for == [NSNumber numberWithInt:0] its working... so basically I try to save a bool but it's recognized as an int... Any ideas what's going on there?
It makes more sense to examine [[theObject valueForKey:#"theBooleanValue"] boolValue] for me. i.e.,
if(![[theObject valueForKey:#"theBooleanValue"] boolValue])
{
// Your code
}
I think == operator compares the object pointer, and not the number itself. To compare number there is a separete method [NSNumber isEqualToNumber:].
Note, that'll make your life a lot easier of you declare the properties like
#property (nonatomic) BOOL theBooleanValue;
This will allow you to use
if (!theObject.theBooleanValue) {
// Your code here
}
And you can assign directly with
theObject.theBooleanValue = YES;
This is my first question so please forgive me if it's obvious. I learned to program in Pascal a few years ago, so my terminology may be off. I've looked at a bunch of postings, but nothing seems to address my basic problem.
I have a lookup table that I use to convert decimals back into fractions. I am calling this method...
-(void) convertToFractions:(float *)float2 aString:(NSMutableString *) myString;
...with this..
[self convertToFractions:&float1 aString:outputFraction];
The idea is that float2 is the decimal that I pass to the method, and myString is the fraction returning.
This runs after the lookup:
myString = [NSString stringWithString:[[decimalInchArray objectAtIndex:x]objectAtIndex:1]];
NSLog(#"myString = %#",myString);
The log shows myString is the correct fraction i.e. myString is correctly displaying the fraction I want to return, but outputFraction is null.
I think it's a pointer issue. I tried *myString, but the compiler throws an error (incompatible types).
Any suggestions are really appreciated.
You want to change the output of your convertToFractions method from void to NSString.
It's returning null because the return type of your method, is void, so it returns nothing.
The return type of an Objective-C method is in the parenthesis, at the beginning of the method name.
Here,s an example, but I don't see where you define convertToString so, I'll use pseudocode.
- (NSString *) convertToFractions:(float *)float2{
NSString *fraction = *some code to lookup fraction from table;*
return fraction;
}
myString = [self convertToFractions:(float *)float2];
EDIT:
As others have suggested, you should give Objective-C a fresh look. I suggest you read this Objective-C Primer written by Apple.
Where do you define your outputFraction? Nowhere in the code above you mention it.
At a guess your conversion method is declared as (void) meaning it will not return anything. If you need it to return the result as a NSString declare it like
-(NSString*) convertToFractions:(float *)float2 aString:(NSMutableString *) myString;
And make sure you return an NSString before reaching the end of the method with
return MyNSStringVariable;
[EDIT]
I can see you are hoping that outputFraction will be returned by your method but that is not the case with Objective-C (not sure about Pascal). You are simply passing outputFraction as a second variable in your method.
So the "right" way of doing it would be to have a method
-(NSString*)convertToFraction:(float*)float2 {
...// Do your float to fraction calculation here
...// Make sure fraction is formatted as NSString
return YourFractionVariable;
}
Then you can assign the return value to a variable of your choice, for instance:
NSString *fraction = [self converToFraction:aFloatNumber];
NSLog (#"fraction is %#", fraction);
Cheers,
Rog
Why not just return the string?
- (NSString*)convertToFractions:(float)float {
//Bla bla do everything
return [myString autorelease]; //Autorelease is for memory-management
}
Btw: You seriously need to read into ObjC. Please don't try to use your old pascal-knowledge on ObjC. It's different, and your knowledge isn't really applicable.
I would recommend buying a book about ObjC or reading some good tutorials for it. (Apple itself has some very good ones)
If you don't want to return NSString from your method as others suggested you can pass a pointer to NSString pointer to your function (the same way you pass NSError** to some standard api callsm e.g. in NSFileManager methods). Your code will look something like:
NSString *outputFraction;
[self convertToFractions:&float1 aString:&outputFraction];
-(void) convertToFractions:(float *)float2 aString:(NSMutableString **) myString{
...
if (myString)
*myString = [NSString stringWithString:[[decimalInchArray objectAtIndex:x]objectAtIndex:1]];
}
I am getting confused with how to handle Integers in Objective C.
If I define the following:
NSInteger i = 6;
NSLog(#"%d", i);
I expect it to print 6 to the console.
however I have an NSInteger within an object which is obviously reference by a pointer so I get very difference results.
For example:
#interface Section : NSObject {
NSInteger Id;
}
#property (nonatomic, assign) NSInteger Id;
Please assume this has been synthesized in the implementation.
I create the object set its value and access it again as follows:
Section *section = [[Section alloc] init];
section.Id = 6;
NSMutableArray *sections = [[NSMutableArray alloc] init];
[sections addobject:section];
Section *sectionB = [setions objectAtIndex:0];
NSLog(#"%d", sectionB.Id);
This has the strange effect of printing the memory address ie a number like 5447889. Why can I not just get the value?
I have tried using:
NSInteger sid = [[section Id]integerValue];
But I then get the warning Invalid receiver type 'NSInteger' and sometime get an error Program received signal: “EXC_BAD_ACCESS”.
I would really like to know how to handle Integers, or any values for that matter properly.
Many Thanks
It looks like you're accessing uninitialized memory; 5447889 doesn't look like a pointer value—pointers are usually word-aligned, and 5447889 isn't word aligned.
Maybe you could cut and paste your actual code. This has typos such as addobject instead of addObject and setions instead of sections.
Does it work if you keep things simple and do NSLog(#"%d", section.Id) to skip messing with the array?
Regarding the strange values, see Dominic Cooney's answer.
Regarding the EXC_BAD_ACCESS: [[section Id]integerValue]; doesn't work because it then tries to interpret the NSInteger as an object and tries to send the message integerValue to it, which can't work. It's an integral number, not an object.
Think I found the answer to my own question. Setting the value of an NSInteger to a value of say 6 is fine. The problem I have is I am setting it to the value returned from a Json string using the following:
NSInteger i = [jsonResult objectForKey:#"Id"];
which should be:
NSInteger i = [[jsonResult objectForKey:#"Id"] integerValue];
I have not tested this but makes sense based on what DarkDust said about integerValue taking an object and not an Integer.
Thanks for your input.