So I have the following code that causes a runtime error in XCode
NSString* temp = [[param objectforkey#"firstParam"] stringValue];
int tempNum = [[param objectforkey#"secondParam"] intValue];
param loads from a plist. firstParam is as string, secondParam is a number
First line crashes the program.
Now what's interesting is it works if I do a hard caste i.e:
NSString* temp = (NSString*)[param objectforkey#"firstParam"];
int tempNum = [[param objectforkey#"secondParam"] intValue];
Just wondering why the id would have inconsistent implementation in that I have to use intValue to cast to int, but have to do hard cast to get NSString? Why not stringValue?
Your first call to objectForKey returns an object which is an NSString. NSString doesn't have a stringValue method which is why a runtime error is generated. It doesn't make sense to get the stringValue of something that is already a string.
The second call to objectForKey returns an NSNumber. NSNumber does have an intValue method so it doesn't cause an error.
In the second case you are changing the type of the returned value from NSNumber to int. In the first case the object returned is already an NSString and there is no point trying to get the stringValue of a string.
The call [param objectforkey#"firstParam"] DOES return a NSString, so there's no need to call stringValue. Furthermore, NSString does not have a method called "stringValue", so that's the source of your problem.
Just call this: NSString *temp = (NSString *)[param objectForKey:#"firstParam"];
Also note that the selector is objectForKey:, not objectforkey: (capitalization matters).
And, answering your question, NSNumber is a class, so any object is not an "int", but a NSNumber pointer. intValue returns an actual "int", as floatValue returns a "float" (NSNumber can represent any type of number). In the case of the NSString that's not necessary, because there is only one type of NSString (there is, though, a method for returning a const char *, and that would be used like char *string = [[param objectForKey:#"firstParam"] cString];... not very useful for Objective-C apps anyway).
Lets say you call a web service that returns JSON
Then you process data
NSDictionary *json_response = [NSJSONSerialization JSONObjectWithData:data
options:0
error:NULL];
now you try something like this
NSString *name = [[object objectForKey:#"Name"] stringValue];
then you get the error....
As mttrb mentions you get the error because of stringValue, objectForKey default return value is String so a potential fix in this case would be:
NSString *name = [object objectForKey:#"Name"];
Hope this hints some one!
If you can not be sure that the returned value is a NSString you should do this:
id value = [param objectForKey#"firstParam"];
if ([value isKindOfClass:[NSString class]]) {
NSString *temp = (NSString *)id;
//Handle string
}
else {
//Handle other case
}
Completing the answer of #Torge, I add my solution to get always an NSString from objectForKey method:
NSObject * value = [param objectForKey#"firstParam"];
NSString *stringValue;
if ([value isKindOfClass:[NSString class]]) {
//Handle string
stringValue = (NSString *)value;
}
else if([value isKindOfClass:[NSNumber class]]){
//Handle NSNumber
stringValue = [((NSNumber *) value) stringValue];
}
else {
//Handle other case
}
Related
I need to replace a word like DFT with the registered trademark symbol everywhere in a string from a plist.
My code works but always messes up the second one in the same string:
- (NSAttributedString *)addRegisteredTrademarkTo:(NSString*)text
{
NSMutableAttributedString *rawAttString=[[NSMutableAttributedString alloc] initWithString:text];
UIFont *boldFont = [UIFont boldSystemFontOfSize:8];
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:#"®"
attributes:#{NSFontAttributeName:boldFont,
NSForegroundColorAttributeName:[UIColor blackColor],
NSBaselineOffsetAttributeName : #4,
NSFontAttributeName:[UIFont fontWithName:#"Helvetica" size:5]
}];
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"DRT" options:kNilOptions error:nil];
NSRange range = NSMakeRange(0,rawAttString.length);
[regex enumerateMatchesInString:text options:kNilOptions range:range usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
NSRange subStringRange = [result rangeAtIndex:0];
[rawAttString replaceCharactersInRange:subStringRange withAttributedString:attributedString];
}];
NSAttributedString *t = [[NSAttributedString alloc] initWithAttributedString:rawAttString];
return t;
}
String is:Fake name™ with Another FakeDRT building access. SionDRT elevators size
Output is:
The second symbol is always misplaced - and I can't figure out why. Any pointers?
Recently, I encountered a problem: in my tableview, I retrieve data from web request, after received response from the network, I need to decode the data and store the data in a C++ object.
However, the tableview datasource, NSArray cannot store C++ object.
I have tried some solutions, like using CFMutableArrayRef or save the C++ object pointer in a NSValue and then put the NSValue into the NSArray. But when I called [tableview reloadData],the data in the CFMutableArray or the NSValue don't have the right data.
Could anybody help me with this problem? Thanks!
Here are some code:
std::list<ImageTextContent> msgs = body->getMsgs();
std::list<ImageTextContent>::iterator itmsgs0;
for(itmsgs0 = msgs.begin();itmsgs0 != msgs.end();itmsgs0++)
{
ImageTextContent *tmpmsgs = &(*itmsgs0);
CFArrayAppendValue(_dataSourceRef, tmpmsgs);
}
and
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
ImageTextContent *itc = (ImageTextContent *)CFArrayGetValueAtIndex(_dataSourceRef, 0);
NSString *title = [NSString stringWithCString:(itc->getSubmitTime()).c_str() encoding:NSUTF8StringEncoding];
cell.contentLabel.text = title;
....
}
in cellForRowAtIndexPath method I can't get the right data, why?
The pointers in your _dataSourceRef array become invalid as soon as the lifetime of msgs ends.
Dereferencing any of them is undefined at that point and anything can happen.
(Very common is that the data has been overwritten and you just find some random stuff there.)
Either make getMsgs return a list of pointers, or dynamically allocate a copy the data when you populate the array, like this:
for(itmsgs0 = msgs.begin();itmsgs0 != msgs.end();itmsgs0++)
{
CFArrayAppendValue(_dataSourceRef, new ImageTextContent(*itmsgs0));
}
This is NSLog of my NSArray
[{"id":16,"venueId":16,"street":"171 - 3401 Dufferin St","city":"Toronto","zipcode":"M6A 2T9","province":"ON","country":"Canada"}]
NSDictionary *dict = [myarray objectAtIndex:i]
//myarray is your array of dictionary
//if the array has just one element like in your example, i will be 0
NSNumber *venueId = [dict objectForKey:#"venueId"];
finally I found solution
NSError *error;
NSArray* jsonArray = [NSJSONSerialization JSONObjectWithData:[[venue objectForKey:#"address"] dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&error] ;
NSDictionary *dict = [jsonArray objectAtIndex:0];
//myarray is your array of dictionary
NSString *street = [dict objectForKey:#"street"];
NSLog(#"street: %#", street);
Note: I used below code to check data type to make sure it returns valid kind of class.
if ([[venue objectForKey:#"address"] isKindOfClass:[NSArray class]]) {
NSLog(#"%#", #"It is NSArray");
} else if ([[venue objectForKey:#"address"] isKindOfClass:[NSString class]]) {
NSLog(#"%#", #"It is NSString");
}
So what I want to accomplish is to make a NSArray out of a txt file and each word would be an object in that array. Below is some code that doesn't work. No crashes but doesn't do anything.
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"badwords" ofType:#"txt"];
if (filePath) {
NSString *fileContents = [NSString stringWithContentsOfFile:#"badwords.txt" encoding:NSUTF8StringEncoding error:nil];
lines = [fileContents componentsSeparatedByString:#"\n"];
}
lines is a NSArray.
Any reason why this shouldn't work? Each word is separated by a line break.
A good reason: [NSString stringWithContentsOfFile: ...] should be taking the filePath you derived in the preceding statement as an argument and not #"badwords.txt", the literal string filename. That's the whole reason for deriving the filePath in the first line -- you then want to use it in the second.
In other words I'm simply saying you should change this:
NSString *fileContents = [NSString stringWithContentsOfFile:#"badwords.txt" encoding:NSUTF8StringEncoding error:nil];
to this:
NSString *fileContents = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
I am trying to implement the following method in Objective-C:
- (NSString*) getGuidWithCid: (int) cid;
This method must retrieve a GUID from a database using a C++ API and then convert this GUID into a string representation of the GUID. The structure GUID returned by the C++ API has the following definition:
typedef struct _GUID {
ul_u_long Data1;
ul_u_short Data2;
ul_u_short Data3;
ul_byte Data4[ 8 ];
} GUID;
Here is my attempt to implement this method:
- (NSString*) getGuidWithCid: (int) cid
{
GUID ulguid;
((ULResultSet *) ulresultset)->GetGuid([cname UTF8String], &ulguid);
NSString* data4 = [[[NSString alloc] initWithBytes:ulguid.Data4
length:8
encoding: NSUTF8StringEncoding] autorelease];
return [NSString stringWithFormat:#"%u-%uh-%uh-%#",
ulguid.Data1,
ulguid.Data2,
ulguid.Data3,
data4];
}
The first two lines of this method are working fine, so the variable ulguid contains a valid guid. The problem I am having is with the conversion of the byte array portion of the GUID (ie. Data4 in the GUID structure). What I am getting back from this method currently is three numeric values separated by hyphens, so Data1, Data2 and Data3 seem to be represented correctly, but NULL is being shown for Data4. What am I doing wrong here?
You are calling release on data4 immedaitely after you create it. The contents of the string, therefore, are invalid at the point you try to use it. Consider calling autorelease instead.
It's possible that the bytes in ulguid.Data4 don't form a valid UTF8 string, so you get nil back when you try to create a string with those bytes.
I have successfully implemented this method as follows:
- (NSString*) getGuidWithCid: (int) cid
{
GUID ulguid;
((ULResultSet *) ulresultset)->GetGuid(cid, &ulguid);
char buffer[37];
sprintf(buffer, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
ulguid.Data1, ulguid.Data2, ulguid.Data3,
ulguid.Data4[0], ulguid.Data4[1],
ulguid.Data4[2], ulguid.Data4[3],
ulguid.Data4[4], ulguid.Data4[5],
ulguid.Data4[6], ulguid.Data4[7]);
return [[[NSString alloc] initWithBytes:buffer
length:sizeof(buffer)
encoding:NSASCIIStringEncoding] autorelease];
}
Thanks goes to Ferdinand Beyer (http://stackoverflow.com/users/34855/ferdinand-beyer) for helping me get to this solution.