Converting __block NSString to NSString (and eventually to std::string) - objective-c

+(std::string)somefunc{
__block NSString *vals = nil;
[[Something somecall] completion:^(some params){vals=#"yay"}];
return std::string([vals UTF8String]);
}
This function call throws an error "-[__NSMallocBlock__ UTF8String]: unrecognized selector sent to instance 0x------"
Based on the way I've converted NSStrings in the past, I'm assuming this is something to do with my need to declare the NSString as a __block to modify it inside the []. But I could not find an answer anywhere.
What is the "best" way to convert it?

Related

How to get classname in objective c Like 'NSString'

I want to get the class name of an object as what we are using.
That means now if I write this code
NSString *s = [NSString string];
NSLog(#"%#",[s class]);
The output is __NSCFConstantString
How can I get it as NSString itself ?
Note : NSString is just an example
I know __NSCFConstantString is correct. But my intention is to get like NSString. Is there any way to acheive this?
Give these a try, they'll output NSString. Keep in mind, the second set requires importing the Objective-C runtime header.
#import <objc/runtime.h>
NSString *string = #"I'm a string.";
NSLog(#"%#",NSStringFromClass([string classForCoder]));
NSLog(#"%#",NSStringFromClass([string classForKeyedArchiver]));
NSLog(#"%s",class_getName([string classForCoder]));
NSLog(#"%s",class_getName([string classForKeyedArchiver]));
Now, this won't work in all cases. For example, trying to get the class of NSConstantString, in this manner will output NSString. If you require checking the class name as a string in this way, you probably should reconsider your approach to solving the problem.
NSString is a so-called "class cluster". That means that the init methods will return
an instance of some subclass (such as __NSCFConstantString or __NSCFString).
You will never get an instance with the class equal to NSString.
If your intention is to check whether an object is a NSString or not then
use isKindOfClass:
if ([s isKindOfClass:[NSString class]]) {
// this is a string …
}
Other examples of class clusters are NSNumber, NSDictionary, NSArray
and their mutable variants.
NSLog(#"%#", NSStringFromClass([s class]));

Why does this typecast not apply itself?

I've been working on this problem for a while and can't seem to find the solution. In my app, I uniquely identify contacts from ABAddressBook by their creation date, as no two contacts can be created at the same time. In my app, the creation date is stored in a string called uid, as you can see below. I am checking to see if two contacts are the same, and I do this by performing the following conditional statement:
NSString *uid = #"some string";
if([(__bridge_transfer NSString *)ABRecordCopyValue(currentPersonRef, kABPersonCreationDateProperty) isEqualToString:uid]) {
//Do some code
}
However, when I run this code, I get the following error:
[__NSDate isEqualToString:]: unrecognized selector sent to instance 0x8c7c770
I'm pretty sure the problem is that ABRecordCopyValue() is returning an NSDate object that is not being casted to NSString by (__bridge_transfer NSString *), so when I compare it to uid using isEqualToString, it crashes. The thing is, I thought that by casting it to an NSString object, isEqualToString: would work. My question is:
Why is the (__bridge_transfer NSString *) not casting the NSDate object?
EDIT:
The answers provided have been useful, but they do not completely address my problem (well actually they do, but I have a follow-up question). In another part of my code, I run this:
NSString *uid = (__bridge_transfer NSString *)ABRecordCopyValue(currentPerson, kABPersonCreationDateProperty);
And if I NSLog uid I get this:
2012-10-28 21:55:29 +0000
So how would I compare uid in the above conditional statement if isEqualToString: doesn't work?
A cast never changes the class or type of an object. It just tells the compiler, that you are certain about the fact, that this object is of another type, than the compiler might assumes.
So if you cast a date object to a string, it will still be a date object.
In OOP you usually needs up-casting: a method wants you to pass in a object, but actually you pass in an object of a subclass. If you then need to access a property or method that is defined by the subclass, you will tell the compiler, that you have an object of the subclass by casting.
A very common example in iOS is tableview:cellForRowAtIndexPath: with subclassed cells.
In cocoa(-touch) you also know casting from toll-free bridging. see this documentation for valid casts.
The answers provided have been useful, but they do not completely
address my problem (well actually they do, but I have a follow-up
question). In another part of my code, I run this:
NSString *uid = (__bridge_transfer NSString *)ABRecordCopyValue(currentPerson, kABPersonCreationDateProperty);
And if I NSLog uid I get this:
2012-10-28 21:55:29 +0000
You are creating a variable, that you declare to be an NSString, but actually the object you assign to it, is a date object.
NSDate *uidDate = (__bridge_transfer NSDate *)ABRecordCopyValue(currentPerson, kABPersonCreationDateProperty);
NSString *uid = [NSString stringWithFormat:uidDate];
Well, I don't know the answer to your question, but why don't you just convert the ABRecordCopyValue() to NSString, then do the isStringEqual:?
Like -
NSString *string = [NSString stringWithFormat:#"%#", ABRecordCopyValue(currentPersonRef, kABPersonCreationDateProperty)];
if([string isEqualToString: uid]){
//do your thing
}

Too many arguments to method call

I am trying to set the initial text for what the twitter message should say in my app using a NSString from my appDelegate. Check out the code here:
NSString *tweet;
tweet=[MyWebFunction tweet:appDelegate.stadium_id];
if([deviceType hasPrefix:#"5."]){
// Create the view controller
TWTweetComposeViewController *twitter = [[TWTweetComposeViewController alloc] init];
[twitter setInitialText:#"#%",tweet];
The problem is, is there is an error at the twitter setInitialText that there are Too many arguments to method call, expected 1, have 2. ?!?!?
Any help is greatly appreciated. :)
The TWTweetComposeViewController method setInitialText only takes one argument, being of type NSString*. You cannot simply format any and all NSString variables passed to a method as you can with the NSString method stringWithFormat (which is, I imagine, where you've seen the syntax [NSString stringWithFormat:#"%#", myString]).
In your case, you either need to simply call:
[twitter setInitialText:tweet];
or call:
[twitter setInitialText:[NSString stringWithFormat:#"%#", tweet]]
EDIT
I feel it necessary to add, to further your understanding, that a method only takes a variable number of arguments (such as stringWithFormat) when its declaration ends with ...
For example, looking in the docs for NSString reveals that stringWithFormat is declared as such:
+(id) stringWithFormat:(NSString *)format, ...;
Similarly, arrayWithObjects in NSArray is declared as such:
+(id) arrayWithObjects:(id)firstObj, ...;
which one would use like:
NSString* myString1 = #"foo";
NSString* myString2 = #"bar";
NSNumber* myNumber = [NSNumber numberWithInt:42];
NSArray* myArray = [NSArray arrayWithObjects:myString1, myString2, myNumber, nil];
Try [twitter setInitialText:tweet];
If you really need formatted text for a more complex case, try
[twitter setInitialText:[NSString stringWithFormat:#"%#", tweet]];
"[twitter setInitialText:#"#%",tweet];"
you just got your "#" and your "%" the wrong way round it should be
[twitter setInitialText:#"**%#**",tweet];

Trying to remove a decimal from NSString

This is bizarre.
Developing for the iPhone I have an NSString:
distanceFromTargetString = #"6178266.000000"
// this is not actually code, but a value taken from elsewhere. It is a proper NSString though.
When I use this
NSArray *listItems = [distanceFromTargetString componentsSeparatedByString:#"."];
distanceFromTargetString = [listItems objectAtIndex:0];
or this
[distanceFromTarget setText: distanceFromTargetString];
I get something like this
-[NSDecimalNumber isEqualToString:]: unrecognized selector sent to instance 0x1cac40
2011-07-21 14:29:24.226 AssassinBeta[7230:707] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSDecimalNumber isEqualToString:]: unrecognized selector sent to instance 0x1cac40'
Any ideas?
At some point you are assigning an NSDecimalNumber to distanceFromTargetString rather than an NSString. There is no run-time type checking of assignments in Objective C, so this is totally "legal":
NSDecimalNumber *number = [NSDecimalNumber ....];
[array addObject:number];
NSString *string = [array lastObject];
The above will generate no errors or warnings until you try to send NSString methods to string, at which point you will get an exception (crash) like you show above.
Do an audit of everywhere you assign distanceFromTargetString, and everywhere you use NSDecimalNumber. Somewhere you're crossing the streams.
You could try :
NSInteger i = [distanceFromTargetString integerValue];
NSString s = [NSString stringWithFormat:#"%d", i];
// you got your string
You are somewhere calling isEqualToString with a NSDecimalNumber as the receiver. What is distanceFromTarget? Is this an NSDecimalNumber?
The first thing should work.
You could try to set a breakpoint at the line
[distanceFromTarget setText: distanceFromTargetString];
and see if distanceFromTargetString is actually an NSString.
As mentioned above, somehow an NSNumber has sneaked in somewhere.

Terminating the app due to uncaught exception in Objective-C for iPhone app

i've written a for loop in Objective-C, This is how my code looks like
NSString *string = [NSString stringWithContentsOfFile=#"/Users/Home/myFile.doc"];
NSString *seperator=#"\n";
NSArray *mainarray = [string componentsSeparatedByString:seperator];
// Since i want to parse each element of mainarray
for(NSString *s in mainarray)
{
//again parising the string using a new separator
NSString newseparator = #"=";
NSArray *subarray = [s componentsSeparatedByString : newseparator];
//Copying the elements of array into key and object string variables
NSString *key = [subarray objectAtIndex:0];
NSLog(#"%#",key);
NSString *class_name= [subarray objectAtIndex:1];
NSLog(#"%#",class_name);
// create an instance for the class_name
//dont knw how it ll take the value from file and ???
//Putting the key and objects values into hashtable
NSMutableDictionary = [NSDictionary dictinaryWithObject:class_name forKey:key];
}
Whenever i execute this code this crashes my program saying as, Terminating the app due to uncaught exception NSRangeException
How to know the range of array and how to specify the terminating condition in the for loop???and plz let me knw how to handle this exception???
I'm surprised that code even compiles. If I remember correctly, it can't compile unless you have gone to great lengths to turn off a whole bunch of compiler warnings.
NSString newseparator = #";";
That should give an error write there in that you don't have the *.
NSString *key = [subarray objectAtIndex[0]];
NSString *object = [subarray objectAtIndex[1]];
Neither of these lines of code make any sense.
It would appear that you haven't posted the actual code?
Now, getting back to the exception. A range exception will be tossed if you try to access an item at an index that is outside of the range of indexes available in the array. Thus, if componentsSeparatedByString: returned an array of 0 or 1 elements, then [subarray objectAtIndex: 1]; will cause a range exception to be raised.
What you don't want to do is to try and handle the exception using an #catch block. In Cocoa (and iPhone development), exceptions are treated as non-recoverable errors.
So, instead, use the -count method on NSArray to verify that the array actually contains the # of elements you were expecting. Since you are writing a casual parser, this is probably a good idea as a minimal check of input validity.