I am getting a casting error. My app is reading a text file from a webpage using 'stringWithContentsOfURL' method. I want to parse the individual lines into separate components. This is a snippet of the code.
int parameterFive_1 = 0;
parameterFive_1_range = NSMakeRange(0,10)
lines = [response componentsSeparatedByString:#"\r"];
parameterFive_1 = CFStringGetIntValue([[lines objectAtIndex:i] substringWithRange:parameterFive_1_range]);
I am getting the following error message:
" Implicit conversion of an Objective-C pointer to 'CFStringRef' (aka 'const struct __CFString *') is disallowed with ARC"
I thought it might be the compiler option but changing it to the default is not making a difference. Can anyone provide any insight?
Just cast the NSString* to CFStringRef to satisfy ARC:
parameterFive_1 = CFStringGetIntValue((__bridge CFStringRef)[[lines objectAtIndex:i] substringWithRange:parameterFive_1_range]);
The __bridge keyword here lets ARC know that it doesn't need to transfer ownership of the string.
Related
I'm a little bit confused about the syntax of NSLog. For example,
NSString *nameString = #"Name";
NSLog(#"nameString is: %#", nameString);
If my understanding is correct (which it very well may not be), then nameString is defined to be a pointer to a String. I thought then that this would print the memory address that nameString holds, not the value of that address. So, if that is true, then in the NSLog statement, to get the value of the pointer, shouldn't we need to use the asterisk notation to access what nameString points to like this:
NSLog(#"nameString is: %#", *nameString);
?
It has been a little while since programming in C, but since Objective-C is a superset of C I thought they would behave similarly.
An explanation would be greatly appreciated! Thanks!
The command %# is like "shortcut" that calls the method -description on the receiver. For an NSString it simply display the string itself, since is inherited from NSObject you can override it, very usefull if you create for own class. In that case the default behaviur is print the value of the pointer. If you want to print the address of the pointer in the string just replace with :
NSLog(#"nameString is: %p", nameString)
I think that you use an asterisk only to declare a pointer. Then, you only use the name you decided. For example:
NSString *foo = [[NSString alloc] initWithString:#"Hello"];
NSLog(#"%#", foo);
Correct me if I am wrong :)
It's an object and NSLog is a function that uses its format specifiers to determine what to do with the argument. In this case the specifier is %# which tells NSLog to call a method on an object.
Normally this will call the method "description" which returns an NSString but it probably does respondsToMethod first and falls through to some other string methods.
I have an NSMutableArray that was downloaded via FTP. The elements in the array are CFFTPStream resource constants that are of type CFStringRef.
I would like to create a String from the "kCFFTPResourceName" constant. However being new to Objective C and iphone development I am struggling.
Everything that I have done has resulted in ARC throwing a fit or errors like:
2013-01-03 15:31:44.874 Street Light Reporter[1382:11603] -[__NSCFDictionary objectAtIndex:]: unrecognized selector sent to instance 0x6e1e930
2013-01-03 15:31:44.875 Street Light Reporter[1382:11603] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary objectAtIndex:]: unrecognized selector sent to instance 0x6e1e930'
My most recent attempt is:
CFStringRef *c = [ar objectAtIndex:4];
which doesnt work for the following two reasons:
Incompatible pointer types initializing 'CFStringRef *' (aka 'const struct __CFString **') with an expression of type 'id'
AND
Implicit conversion of an Objective-C pointer to 'CFStringRef *' (aka 'const struct __CFString **') is disallowed with ARC
I have tried all sorts of typecasting and messing around with (__bridge) and whatnot and I have had no luck.
Can anybody help me out here? Any help will be appreciated.
CFStringRef is a pointer already, you don't need the star. Also, you can cast CFStringRef to NSString and it will work fine and will be easier to work with. This is called toll free bridging. If you still need the CFStringRef:
ARC:
CFStringRef c = (__bridge CFStringRef)([ar objectAtIndex:4]);
Non arc
CFStringRef c = (CFStringRef)([ar objectAtIndex:4]);
You have two errors here: the first and the most severe one is that your ar object is a NSDictionary not a NSArray. That's why performing
CFStringRef *c = [ar objectAtIndex:4];
you are getting a NSInvalidArgumentException. objectAtIndex: is a method of NSArray that you are sending to a NSdictionary instance.
The second error is the cast. As Fernando already pointed out, you need to cast it using the __bridge keyword like follows.
CFStringRef c = (__bridge CFStringRef)([ar objectAtIndex:4]);
so that ARC will know that you are now treating that object as a C pointer.
Note also that CFStringRef is defined as
typedef const struct __CFString * CFStringRef;
so it's already a pointer and you have to get rid of the *.
It seems that you get an CFDictionary back and not an array.
The constants you linked to are keys for the dictionary, with which you can access the values.
This is probably pilot error on my part, but I am a little confused why this does not return an int (as thats the type of the property identified by the key path). Does valueForKeyPath: return an object instead, can anyone explain.
// Simple Object
#interface Hopper : NSObject
#property(nonatomic, assign) int mass;
#end
// Test
Hopper *hopper = [[Hopper alloc] init];
[hopper setMass:67];
NSLog(#"HOPPER: %d", [hopper valueForKeyPath:#"mass"]);
.
WARNING: Conversion specifies type 'int' but the argument has type 'id'
Yes, it returns an objc object:
- (id)valueForKeyPath:(NSString *)keyPath;
Details for automatic conversions from non-objc objects to objc objects (e.g. NSNumber and NSValue) is covered in Accessor Search Patterns for Simple Attributes.
Therefore, you would use the objc object format specifier %#:
NSLog(#"HOPPER: %#", [hopper valueForKeyPath:#"mass"]);
valueForKeyPath returns an object. int and char types are not objects. Access the property via the . operator or similar.
NSLog(#"HOPPER: %d", [hopper mass]);
NSLog(#"HOPPER: %d", hopper.mass);
Edit: Didn't fully read example code, updated answer
I have some code added in viewWillAppear;
curr_rep_date = [tmpRptDt
stringByReplacingOccurrencesOfString:[NSString
stringWithFormat:#"%d",tmpYrVal]
withString:[NSString
stringWithFormat:#"%d",(tmpCurrYearInt-2)]];
When I build, I get the following warning;
warning: incompatible Objective-C types assigning 'struct NSArray *', expected 'struct NSMutableArray * }
Also
warning: assignment makes pointer from integer without a cast for:
replist_rptdt_dict =
PerformXMLXPathQuery(xmlData,
#"//XX/Period[#XX]");
Please let me know the reason.
Thanks.
replist_rptdt_dict = PerformXMLXPathQuery(xmlData, #"//XX/Period[#XX]");
First, the Objective-C standard is to use camel cased english names for variables. replist_rptdt_dict is confusing (it almost sounds like you have a list dictionary something what huh?).
warning: incompatible Objective-C
types assigning 'struct NSArray *',
expected 'struct NSMutableArray *' }
This will happen if you have:
- (NSArray *) foo;
...
{
NSMutableArray *bar = [someObject foo];
}
That is, bar is a more specific type -- a subclass -- than foo's return value. The compiler is complaining because your code is quite likely going to crash if you send, say, removeObjectAtIndex: to what is quite likely an immutable array.
I have an sqlite string column that is assigned to a string. I need to make sure it isn't nil before assigning. I'm doing this:
char *isNil = sqlite3_column_text(selectstmt, 2);
if(isNil != nil){
myName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 2)];}
which gives the warning:
warning: initialization discards qualifiers from pointer target type
What is the proper way to do it?
You're getting the warning as you're ignoring the const. The API is defined:
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
You're assigning the return to a char*, so you're dropping the const. That is why you get the warning. You should respect the const.
const unsigned char *isNil = ...
I'm not really a huge objective-c guy, but I think stylistically it's common practice to compare primative types against NULL rather than nil. Also there is no need to call column_text twice.
const char *columnText = (const char *)sqlite3_column_text(selectstmt, 2);
if(columnText != NULL)
{
myName = [NSString stringWithUTF8String: columnText ];
}
You can see above I've cast the const unsigned char pointer to a const signed char pointer. You should make sure you know when you cast away a warning that it is the right thing to do. In this case it is safe to cast to an signed char. In general, never cast away const though, as whoever made that API could be doing something that requires you to treat the data as const.