Parsing XML not working, why? - iphone

- (void)parserDidStartDocument:(NSXMLParser *)parser
{
nestedChannels = [ [ NSMutableArray alloc ] init ];
....
}
- (void)parser:(NSXMLParser *)parser didStartElement....
{
Channel *channel = [ [ Channel alloc ] init ];
[ nestedChannels addObject:channel ];
....
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string....
{
Channel *channel = [ nestedChannels lastObject ];
channel.thumbnail = string;
....
}
#interface Channel : NSObject {
NSMutableString *thumbnail;
}
#property (nonatomic, retain) NSMutableString *thumbnail;
Error: * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[NSCFString thumbnail]: unrecognized selector sent to instance 0x381c350'
It's like is not able to recognize the type of the object. Am I missing something
**nestedChannels is a NSMutableArray*

Seems like this is causing the problem.
channel.thumbnail = string;
What type is thumbnail in channel and what mutators are available?
To me it looks like it is trying to set string to thumbnail but there's no setter that accepts string on thumbnail. Is thumbnail NSString?

It's unclear what you're asking; are these different methods? Your code formatting is a little odd. One thing to note is that, if the second snippet is indeed a method (though there are no brackets), you need to append the data passed in, as it may not be a complete element:
if (channel.name == nil) channel.name = [NSMutableString string];
[channel.name appendString: string];

Related

Splitting NSString not working

I have seen may topics that talk about that but none of them has been useful for me. I am trying to parse GEORSS and the coordinates are given me with the following format:
<georss:point>4613618.31000115 676474.87007986</georss:point>
So I have tried to split it into an NSArray and then assign them to the corresponding XML key, but it always crash with that error:
2013-04-02 12:33:11.234 GeoRss1[2125:c07] * Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayM objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
* First throw call stack:
(0x1959012 0x1275e7e 0x18fb0b4 0x19d23a8 0x3f48 0xd55a37 0x1c96600 0x1ca1a2b 0x1ca0f07 0xd53e02 0x34b8 0xd7b589 0xd79652 0xd7a89a 0xd7960d 0xd79785 0xcc6a68 0x14a1911 0x14a0bb3 0x14decda 0x18fb8fd 0x14df35c 0x14df2d5 0x13c9250 0x18dcf3f 0x18dc96f 0x18ff734 0x18fef44 0x18fee1b 0x18b37e3 0x18b3668 0x1b9ffc 0x1ddd 0x1d05)
libc++abi.dylib: terminate called throwing an exception
(lldb)
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
}else if([elemAct isEqualToString:#"georss:point"]){
componentes = [[string componentsSeparatedByString:#" "] mutableCopy];
if ( componentes != nil){
[xmlLat appendString:componentes[0]];
[xmlLon appendString:componentes[1]];
}
...
...
In the header of that file I have declares both variables correctly and the synthesized them:
...
#property (strong) NSMutableString *xmlLat;
#property (strong) NSMutableString *xmlLon;
...
Thank you everyone for advanced, you already have helped me with some responses in other topics!
I tried following code :
NSString *abc = #"4613618.31000115 676474.87007986";
NSArray *componentes = [[abc componentsSeparatedByString:#" "] mutableCopy];
NSLog(#"componentes : %#",componentes);
NSMutableString *xmlLat = [[NSMutableString alloc]initWithString:#""];
NSMutableString *xmlLon = [[NSMutableString alloc]initWithString:#""];
[xmlLat appendString:componentes[0]];
[xmlLon appendString:componentes[1]];
NSLog(#"xmlLat : %#",xmlLat);
NSLog(#"xmlLon : %#",xmlLon);
It worked perfectly for me. I thin the problem is you are not getting proper data in your string.

Transform String to Core Data by NSValueTransformer

I'm trying to use Core Data NSValueTransformer to transform NSArray to NSString. I'm not sure whether it can be archived, but I saw apple's official doc show a code snippet:
#interface ClassNameTransformer: NSValueTransformer {}
#end
#implementation ClassNameTransformer
+ (Class)transformedValueClass { return [NSString class]; }
+ (BOOL)allowsReverseTransformation { return NO; }
- (id)transformedValue:(id)value {
return (value == nil) ? nil : NSStringFromClass([value class]);
}
#end
It seems it can store data into NSString (maybe I misunderstood..), so I tried like below:
#implementation ArrayToStringTransformer
+ (BOOL)allowsReverseTransformation {
return YES;
}
+ (Class)transformedValueClass {
return [NSString class];
}
- (id)transformedValue:(id)value {
// return NSStringFromClass([value class]);
// return NSStringFromClass([#"11" class]);
NSLog(#"!!!!!! %#, %#", NSStringFromClass([value class]), value);
if ([value isKindOfClass:[NSString class]])
return NSStringFromClass([value class]);
NSMutableString * string = [NSMutableString string];
for (NSNumber * number in value)
[string appendString:[NSString stringWithFormat:#"%#,", number]];
return string;
}
- (id)reverseTransformedValue:(id)value {
NSArray * array = [value componentsSeparatedByString:#","];
return array;
}
#end
However, it crashed with the error below (it includes the NSLog):
[26364:11903] !!!!!! __NSCFString, 0,0
[26364:11903] -[__NSCFString bytes]: unrecognized selector sent to instance 0x905f620
[26364:11903] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString bytes]: unrecognized selector sent to instance 0x905f620'
Any idea? Please!!
EDIT:
Well, I just transform NSArray to NSData, and if it is NSString type, transform it to NSArray first, then to NSData, and it works:
+ (Class)transformedValueClass {
return [NSArray class];
}
- (id)transformedValue:(id)value {
if (! [value isKindOfClass:[NSString class]])
return [NSKeyedArchiver archivedDataWithRootObject:value];
NSLog(#"!!! Convert NSString to NSArray");
NSArray * array = [value componentsSeparatedByString:#","];
NSData * data = [NSKeyedArchiver archivedDataWithRootObject:array];
return data;
}
- (id)reverseTransformedValue:(id)value {
return [NSKeyedUnarchiver unarchiveObjectWithData:value];
}
!!! Attention Here
But I wonder whether it is a right way? As you can see, I return [NSArray class] in transformedValueClass method, but actually return NSData type data value in transformedValue:.
The apple DOC said:
An NSData object containing the encoded form of the object graph whose root object is rootObject
I'm totally confused...
Currently Core Data can only transform to NSData. The default transformer can handle transforming an array of strings to NSData by setting the attribute type to transformable and that's the only configuration required.
Personally I would like Core Data in the future to allow transformation to a string, so for example when using a SQLite browser the record field is human-readable instead of being a binary plist.
One theory why they might not have included this feature, is if you are trying to include an array of strings, then you would likely be better off using a many-to-many relation for implementing what you are trying to store instead.

Save own Class with NSCoder

I'm trying to store some custom class/data to a file in my iPhone/iPad app.
I have a Class RSHighscoreList
#interface RSHighscoreList : NSObject {
NSMutableArray *list;
}
which contains objects of RSHighscore in the list
#interface RSHighscore : NSObject {
NSString *playerName;
NSInteger points;
}
When I try to store all to file
- (void)writeDataStore {
RSDataStore *tmpStore = [[RSDataStore alloc] init];
_tmpStore.highscorelist = self.highscorelist.list;
NSMutableData *data = [[NSMutableData alloc] init];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:tmpStore forKey:kDataKey];
[archiver finishEncoding];
[data writeToFile:[self dataFilePath] atomically:YES];
[archiver release];
[data release];
}
#interface RSDataStore : NSObject <NSCoding, NSCopying> {
NSMutableArray *highscorelist;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:highscorelist forKey:#"Highscorelist"];
}
The app will crash with an error message
-[RSHighscore encodeWithCoder:]: unrecognized selector sent to instance 0x573cc20
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[RSHighscore encodeWithCoder:]: unrecognized selector sent to instance 0x573cc20'
I wonder why the error tells about RSHighscore, even if that is 'wrapped'. Does anyone have a good idea?
RSDataStore has an -encodeWithCoder: method, but (according to the error message) RSHighscore doesn't. You need to implement the NSCoding protocol for every class you're serializing.
#implementation RSHighscore
static NSString *const kPlayerName = #"PlayerName";
static NSString *const kPoints = #"Points";
-(id)initWithCoder:(NSCoder *)decoder {
if ((self=[super init])) {
playerName = [[decoder decodeObjectForKey:kPlayerName] retain];
points = [decoder decodeIntegerForKey:kPoints];
}
return self;
}
-(void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:playerName forKey:kPlayerName];
[encoder encodeInt:points forKey:kPoints];
}
...
If the base class of RSHighscore is ever changed to something other than NSObject, the -initWithCoder: method might need to be changed to call [super initWithCoder:decoder] rather than [super init]. Alternatively, add <NSCoding> to NSObject and change RSHighscore's -initWithCoder: now.
#interface NSObject (NSCoding)
-(id)initWithCoder:(NSCoder*)decoder;
-(void)encodeWithCoder:(NSCoder*)encoder;
#end
#implementation NSObject (NSCoding)
-(id)initWithCoder:(NSCoder*)decoder {
return [self init];
}
-(void)encodeWithCoder:(NSCoder*)encoder {}
#end
#implementation RSHighscore
-(id)initWithCoder:(NSCoder *)decoder {
if ((self=[super initWithCoder:decoder])) {
playerName = [[decoder decodeObjectForKey:kPlayerName] retain];
points = [decoder decodeIntegerForKey:kPoints];
}
return self;
}
...
The class you're going to encode or initWithCoder should conform to <NSCoding> protocol
So you just should add this in your interface, otherwise indeed the runtime will not recognize the selector as it's the part of <NSCoding> protocol

NSMutableString stringWithString:NSString not working for me

This piece of code below is causing my app to crash
EDIT
#interface termsAndConditions : NSObject
{
NSMutableString *titleText;
NSMutableString *bodyText;
NSMutableArray *arrayBodyText;
}
#property (nonatomic, copy) NSMutableString *titleText;
#property (nonatomic, copy) NSMutableString *bodyText;
*EDIT*
else if ([[self.arrayBodyText objectAtIndex:x] isKindOfClass:[NSString class]])
{
if (x == 0)
{
self.bodyText=[NSMutableString stringWithString:[self.arrayBodyText
objectAtIndex:x]];
}
else
{
[self.bodyText appendString:[self.arrayBodyText objectAtIndex:x] ];
}
the arrayBodyText is an array of NSString which I got from a dictionary and that I want to join them altogether in 1 NSMutableString.
When the app crashes it gives the message :
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to mutate immutable object with appendString:'
* Call stack at first throw:
Basically I need help to read this array of NSStrings into 1 NSMutableString.
Thanks
-Code
Do this:
self.bodyText = [[[self.arrayBodyText componentsJoinedByString:#""] mutableCopy] autorelease];

iPhone: -[NSConcreteMutableData fastestEncoding]: unrecognized selector

I am trying to do this:
self.somestring = [#"hardcodedstring" stringByAppendingString:someotherstring];
But I keep getting:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSConcreteMutableData fastestEncoding]: unrecognized selector sent to instance 0x1fb930'
I don't call this method anywhere but I see that stringByAppendingString: calls it in my stack:
Stack: (
808221155,
806100816,
808224837,
807957033,
807851552,
812064725,
812064413,
18085, <== -[NSString stringByAppendingString:] + 109 in section LC_SEGMENT.__TEXT.__text of /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.1.sdk/System/Library/Frameworks/Foundation.framework/Foundation
817945012,
821160740,
821157652,
821149552,
807852041,
812070519,
807836299,
807834407,
827752032,
816118388,
816157144,
8381,
8244
)
How would I fix this so that it appends the string, just like it is supposed to. Thanks,
Isaac
Edit: To access somestring, I do this:
#property (nonatomic,retain) NSString *somestring;
In my ViewController.h and:
#synthesize somestring;
In my ViewController.m.
Edit: someotherstring comes from here:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)img editingInfo:(NSDictionary *)editInfo {
self.somestring = [#"hardcodedstring" stringByAppendingString:[UIImagePNGRepresentation(img) encodeBase64]]; //encodeBase64 encodes it to base64
}
More Edit: I broke it up:
2009-03-20 15:14:21.389 myproject[3467:20b] *** -[NSConcreteMutableData getCharacters:range:]: unrecognized selector sent to instance 0x1fa630
2009-03-20 15:14:21.403 myproject[3467:20b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSConcreteMutableData getCharacters:range:]: unrecognized selector sent to instance 0x1fa630'
2009-03-20 15:14:21.412 myproject[3467:20b] Stack: (
808221155,
806100816,
808224837,
807957033,
807851552,
807660389,
807733601,
807733297,
807891629,
812155873,
812293801,
18081,
817945012,
821160740,
821157652,
821149552,
807852041,
812070519,
807836299,
807834407,
827752032,
816118388,
816157144,
8381,
8244
)
terminate called after throwing an instance of 'NSException'
(gdb) info symbol 18081
-[InternalChoicesController imagePickerController:didFinishPickingImage:editingInfo:] + 73 in section LC_SEGMENT.__TEXT.__text of /Users/isaacwaller/Documents/myproject/build/Debug-iphoneos/myproject.app/myproject
(gdb) info symbol 812293801
NSLog + 25 in section LC_SEGMENT.__TEXT.__text of /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.1.sdk/System/Library/Frameworks/Foundation.framework/Foundation
So I think it is a problem with encoding the Base64 data? The code I am using is:
static const char encodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
#implementation NSData (Base64)
- (NSString *)encodeBase64;
{
if ([self length] == 0)
return #"";
char *characters = malloc((([self length] + 2) / 3) * 4);
if (characters == NULL)
return nil;
NSUInteger length = 0;
NSUInteger i = 0;
while (i < [self length])
{
char buffer[3] = {0,0,0};
short bufferLength = 0;
while (bufferLength < 3 && i < [self length])
buffer[bufferLength++] = ((char *)[self bytes])[i++];
// Encode the bytes in the buffer to four characters, including padding "=" characters if necessary.
characters[length++] = encodingTable[(buffer[0] & 0xFC) >> 2];
characters[length++] = encodingTable[((buffer[0] & 0x03) << 4) | ((buffer[1] & 0xF0) >> 4)];
if (bufferLength > 1)
characters[length++] = encodingTable[((buffer[1] & 0x0F) << 2) | ((buffer[2] & 0xC0) >> 6)];
else characters[length++] = '=';
if (bufferLength > 2)
characters[length++] = encodingTable[buffer[2] & 0x3F];
else characters[length++] = '=';
}
return [[[NSString alloc] initWithBytesNoCopy:characters length:length encoding:NSASCIIStringEncoding freeWhenDone:YES] autorelease];
}
#end
Thanks, Isaac Waller
I would check the code for typos. The error pretty clearly indicates that an instance of NSMutableData is being used where an NSString is expected. It would seem that either encodeBase64 is somehow returning self or else the raw UIImagePNGRepresentation(img) is getting passed to stringByAppendingString:.
If it's not apparent, just break it down and check at each step. (I'm using NSLog for this example, but stepping with a debugger would work fine too, of course.)
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)img editingInfo:(NSDictionary *)editInfo {
NSData *rep = UIImagePNGRepresentation(img);
NSLog(#"Rep: %#", rep);
NSString *base64 = [rep encodeBase64];
NSLog(#"Base 64 is a %#", NSStringFromClass([base64 class]));
self.somestring = [#"hardcodedstring" stringByAppendingString:base64]; //encodeBase64 encodes it to base64
}
My best guess is that you're accidentally passing in the raw NSData instead of an NSString — but failing that, the above code should either work correctly or show exactly where things are breaking down.
#"Some String" isn't an object, it's a string literal. You can't send messages to it. You are going to need to do something else to join those strings.
Something like:
[NSString stringWithFormat:#"%#%#", #"String 1", #"String 2"];
Apparently, this isn't correct. String literals are treated as objects.
As mentioned in the comments, you may also have a problem with self.somestring as well. If you haven't declared a property or synthesized somestring then accessing it through self. is incorrect. You should just use
somestring = [NSString stringWithFormat:#"%#%#", #"String 1", #"String 2"];
If you've done:
#interface myClass {
NSString *somestring;
}
#property(nonatomic, retain) NSString *somestring;
#end
And:
#implementation myClass
#synthesize somestring;
#end
Then you can access the variable using self.somestring, which is really just syntactic sugar for [self somestring].
It is important to note also that #property and #synthesize are actually syntactic sugar bits themselves. They wind up doing something similar to this.
#interface myClass {
NSString *somestring;
}
-(NSString *)somestring;
-(void)setSomestring:(NSString *)value;
#end
And:
#implentation myClass
-(NSString *)somestring {
return somestring;
}
-(void)setSomestring:(NSString *)value {
somestring = value;
}
#end
So if you haven't declared somestring as a property and synthesized it, then you don't have those methods to answer the message being passed.