In my project i have implemented multiple service and getting response. Among that one WSDL service that returns one data set as a response,
+ (id)deserializeAsDictionary:(CXMLNode*)element {
NSLog(#"deserializeAsDictionary = %#, children: %d", element.stringValue, [element childCount]);
if([element childCount] == 1) {
CXMLNode* child = [[element children] objectAtIndex:0];
if([child kind] == CXMLTextKind) {
NSLog(#"child %# added", [child stringValue]);
return [[[element children] objectAtIndex:0] stringValue];
}
}
NSMutableDictionary* d = [NSMutableDictionary dictionary];
NSInteger i = 1;
NSString *objKey;
for(CXMLNode* child in [element children]) {
id v = [Soap deserialize:child];
if(v == nil) {
v = [NSNull null];
} else {
if([[child name] isEqualToString:#"(null)"]) {
objKey = [NSString stringWithFormat:#"%#",[child stringValue]];
} else if([[child name] isEqualToString:#"key"] || [[child name] isEqualToString:#"value"]) {
objKey = [NSString stringWithFormat:#"%#",[child name]];
} else {
objKey = [NSString stringWithFormat:#"%#%d",[child name],i++];
}
}
[d setObject:v forKey:objKey];
NSLog(#"child %# added", objKey);
}
return d;
}
soap class will use this method to convert that data set into dictionary. Its working perfectly in IOS 5 but its not working in ios 6. Application will crash in ios 6 and through error as " CXML copy with zone "Please help me to fix this issue.
I think u get the soap classes with ARC enabled for ios6.If so you need to update the soap request class.Please refer this link Sudzc with iOS 5 and ARC
I think it may useful to you
Related
I've been searching for answers for this but still haven't been able to solve how to correct the problem. This -[NSNull length]: unrecognized selector sent to instance and this [NSNull length]: unrecognized selector sent to instance 0x43fe068 did not help.
I'm working on a chat app with a Parse back-end and I was having a timestamp problem with a chat message showing up out of order so I deleted the rows that were out of order from my Parse database using the Databrowser. When I tested the app, that seemed to fix the problem on my iPhone 6 Plus and on the iPhone 6 simulator both running iOS 8. However, when opening up the same chat room on my iPhone 5s running iOS 7, the app crashes consistently with the following error.
-[NSNull length]: unrecognized selector sent to instance
I have no idea why deleting a row would cause this to happen and why only on iOS 7? I set an All Exceptions Breakpoint and here is the offending line along with a screenshot.
self.lastMessageLabel.textColor = [UIColor redColor];
I still get the NSNull length crash even when I comment out the above line, but it breaks at the generic main.m.
Any suggestions on how to solve this would be appreciated. Thanks.
EDIT 1: Here's the code from my ChatView.m that's being loaded by my PrivateInbox.
- (void)loadMessages {
if (isLoading == NO)
{
isLoading = YES;
JSQMessage *message_last = [messages lastObject];
PFQuery *query = [PFQuery queryWithClassName:PF_CHAT_CLASS_NAME];
[query whereKey:PF_CHAT_ROOM equalTo:chatroomId];
if (message_last != nil) {
[query whereKey:PF_CHAT_SENTDATE greaterThan:[self.dateFormatter stringFromDate:message_last.date]];
}
[query includeKey:PF_CHAT_USER];
[query orderByAscending:PF_CHAT_SENTDATE];
[query addAscendingOrder:PF_CHAT_CREATEDAT];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error)
{
if (error == nil)
{
for (PFObject *object in objects)
{
PFUser *user = object[PF_CHAT_USER];
[users addObject:user];
if(![object[PF_CHAT_TEXT] isKindOfClass:[NSNull class]]) {
NSDate* sentDate;
if(object[PF_CHAT_SENTDATE] != nil)
sentDate = [self.dateFormatter dateFromString:object[PF_CHAT_SENTDATE]];
else
sentDate = object.createdAt;
JSQTextMessage *message = [[JSQTextMessage alloc] initWithSenderId:user.objectId senderDisplayName:user.objectId date:sentDate text:object[PF_CHAT_TEXT]];
[messages addObject:message];
} else if(object[PF_CHAT_PHOTO] != nil) {
NSDate* sentDate;
if(object[PF_CHAT_SENTDATE] != nil)
sentDate = [self.dateFormatter dateFromString:object[PF_CHAT_SENTDATE]];
else
sentDate = object.createdAt;
PFFile* photoFile = object[PF_CHAT_PHOTO];
JSQPhotoMediaItem *photoItem = [[JSQPhotoMediaItem alloc] init];
JSQMediaMessage *photoMessage = [[JSQMediaMessage alloc] initWithSenderId:user.objectId
senderDisplayName:user.objectId
date:sentDate
media:photoItem];
[messages addObject:photoMessage];
{
[photoFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
photoItem.image = [UIImage imageWithData:data];
[self.collectionView reloadItemsAtIndexPaths:[NSArray arrayWithObjects:[NSIndexPath indexPathForItem:[messages indexOfObject:photoMessage] inSection:0], nil]];
}];
}
} else if(object[PF_CHAT_VIDEO] != nil) {
NSDate* sentDate;
if(object[PF_CHAT_SENTDATE] != nil)
sentDate = [self.dateFormatter dateFromString:object[PF_CHAT_SENTDATE]];
else
sentDate = object.createdAt;
PFFile* videoFile = object[PF_CHAT_VIDEO];
JSQVideoMediaitem *videoItem = [[JSQVideoMediaitem alloc] initWithFileURL:[NSURL URLWithString:[videoFile url]] isReadyToPlay:YES];
JSQMediaMessage *videoMessage = [[JSQMediaMessage alloc] initWithSenderId:user.objectId
senderDisplayName:user.objectId
date:sentDate
media:videoItem];
[messages addObject:videoMessage];
}
}
if ([objects count] != 0) {
[JSQSystemSoundPlayer jsq_playMessageReceivedSound];
[self resetUnreadCount];
[self finishReceivingMessage];
}
}
else [ProgressHUD showError:#"Network error."];
isLoading = NO;
}];
}
}
EDIT 2: I tried NSNullSafe from Nick Lockwood https://github.com/nicklockwood/NullSafe and that allowed the Private Inbox to open without crashing and gets me past the NSNull Length error but I think that just masks the problem and I still don't know why it didn't crash on iOS 8 but did crash on iOS 7.
I don't think that this could be related to the differences between the 2 operative systems.
The crash is pretty clear, you are sending a message to an object of class NSNUll that can't handle it.
The fact you are using parse or a web services in general makes me think that this object was generated by the back end as a null in a JSON and translated into a NSNull object by the JSON parsing.
You should find a way to handle NSNull object probably at parsing level.
#Andrea is correct, if you can't figure it out from your API (server) side then, here's categories of NSDictionary and NSArray which removes any NSNull object and your app wouldn't crash.
#interface NSDictionary (NullReplacement)
- (NSDictionary *)dictionaryByReplacingNullsWithBlanks;
#end
#interface NSArray (NullReplacement)
- (NSArray *)arrayByReplacingNullsWithBlanks;
#end
#implementation NSDictionary (NullReplacement)
- (NSDictionary *)dictionaryByReplacingNullsWithBlanks {
const NSMutableDictionary *replaced = [self mutableCopy];
const id nul = [NSNull null];
const NSString *blank = #"";
for (NSString *key in self) {
id object = [self objectForKey:key];
if (object == nul) [replaced setObject:blank forKey:key];
else if ([object isKindOfClass:[NSDictionary class]]) [replaced setObject:[object dictionaryByReplacingNullsWithBlanks] forKey:key];
else if ([object isKindOfClass:[NSArray class]]) [replaced setObject:[object arrayByReplacingNullsWithBlanks] forKey:key];
}
return [NSMutableDictionary dictionaryWithDictionary:[replaced copy]];
}
#end
#implementation NSArray (NullReplacement)
- (NSArray *)arrayByReplacingNullsWithBlanks {
NSMutableArray *replaced = [self mutableCopy];
const id nul = [NSNull null];
const NSString *blank = #"";
for (int idx = 0; idx < [replaced count]; idx++) {
id object = [replaced objectAtIndex:idx];
if (object == nul) [replaced replaceObjectAtIndex:idx withObject:blank];
else if ([object isKindOfClass:[NSDictionary class]]) [replaced replaceObjectAtIndex:idx withObject:[object dictionaryByReplacingNullsWithBlanks]];
else if ([object isKindOfClass:[NSArray class]]) [replaced replaceObjectAtIndex:idx withObject:[object arrayByReplacingNullsWithBlanks]];
}
return [replaced copy];
}
#end
Caution : Only appropriate if you're parsing small amount of data.
Source : https://stackoverflow.com/a/16702060/1603234
The other two answers are correct - this is not an issue of OS version, but rather that you are being passed a NULL value and are not catching it.
The line you caught in the Exception:
self.lastMessageLabel.textColor = [UIColor redColor];
Is indicating a symptom, not the cause. I am not 100% sure how _setTextColor actually works, but I would make a strong bet that it works by using the length attribute of NSString/NSAttributedString to make a NSRange so that it knows where to start applying the color and end applying the color. If the data is NULL, then as the other users mentioned, you are trying to access the length attribute of the wrong class, causing your crash.
Judging from your stack trace, lines 5 (setMessage:forUser) and 6 (cellForRow...) are where you should be trying to catch the NULL value. Either that, or you should modify your data controller so that when a NULL value is passed back in the JSON, you replace it with a placeholder, such as "No Message".
At either rate, your crash is probably happening when you assign a value to self.lastMessageLabel.text when you are building your tableView cells in cellForRow.... Check the NSString that you use there for class type (isKindOfClass[NSNULL class]) and see if that helps.
I'm working on iOS application with foursquare iOS api , I want to get the recommended near venues. I have used following code & it giving me an empty result .. Where have I done the mistake ? ? ?
NSArray* venues;
//get the foursquare locations
- (void)getTipsForLocation:(CLLocation *)location {
//NSLog(#"lat %f",location.coordinate.latitude);
[Foursquare2 venueExploreRecommendedNearByLatitude:#(location.coordinate.latitude)
longitude:#(location.coordinate.longitude)
near:nil
accuracyLL:nil
altitude:nil
accuracyAlt:nil
query:nil
limit:nil
offset:nil
radius:#(1500)
section:nil
novelty:nil
sortByDistance:1
openNow:0
venuePhotos:0
price:nil
callback:^(BOOL success, id result){
if (success) {
NSDictionary *dic = result;
venues = [dic valueForKeyPath:#"response.venues"];
FSConverter *converter = [[FSConverter alloc]init];
self.nearbyVenues = [converter convertToObjects:venues];
//NSLog(#"venues %#",venues);
//NSLog(#"near by places %#",self.nearbyVenues);
}
else{
NSLog(#" foursquare connecting error");
}
}];
NSLog(#"recommended place array %#",venues);
}
You Can Not pass Nil,In NSNumber & NSString.
NSNumber *emptynumber=[[NSNumber alloc] init];
[Foursquare2 venueExploreRecommendedNearByLatitude:lan longitude:lon near:#"" accuracyLL:emptynumber altitude:emptynumber accuracyAlt:emptynumber query:#"" limit:emptynumber offset:emptynumber radius:#(1500) section:#"" novelty:#"" sortByDistance:YES openNow:YES venuePhotos:YES price:#"" callback:^(BOOL success, id result) {
if (success) {
NSLog(#"secondResult: %#",result);
NSDictionary *dic = result;
NSArray *venues = [dic valueForKeyPath:#"response.venues"];
FSConverter *converter = [[FSConverter alloc] init];
self.venues = [converter convertToObjects:venues];
[self.tableView reloadData];
NSLog(#"Data: %#",venues);
}
}];
It Works For me.
This is the method when my app complete the downloading with contact which is coming from server. In for loop I am using AIContactParsarModal class and using dictionary I am setting the objects, but every time object value is null.
Thanks for the help and any help will be appreciable. Here is my code.
- (void)donewithContact {
self.allPersonDetailsDict = [[NSMutableDictionary alloc]initWithCapacity:1];
NSMutableArray *allKeysArray = [[NSMutableArray alloc] init];
NSString *prefix;
NSString *searchContactString = [[NSUserDefaults standardUserDefaults] objectForKey:#"AdvanceSearch"];
if ([searchContactString isEqualToString:#"SpecialSearch"]) {
[self.allPersonDetailsDict removeAllObjects];
}
if (getContactArray.count == 0 ){
[noContactLabel setHidden:NO];
} else {
for (AIContactParsarModal *contact in getContactArray) {
NSLog(#"contact LAST NAMES ARE %#",contact.lastName);
prefix = [[contact.lastName substringWithRange:NSMakeRange(0, 1)] uppercaseString];
if ([allKeysArray containsObject:prefix]) {
NSMutableArray *conatctsWithPrefix = [_allPersonDetailsDict objectForKey:prefix];
[conatctsWithPrefix addObject:contact];
} else {
[allKeysArray addObject:prefix];
NSMutableArray *conatctsWithPrefix = [[NSMutableArray alloc] initWithObjects:contact,nil];
[self.allPersonDetailsDict setObject:conatctsWithPrefix forKey:prefix];
NSLog(#"conatctsWithPrefix %#",conatctsWithPrefix);
}
}
[noContactLabel setHidden:YES];
}
NSLog(#"All Names First characters are:%#", allKeysArray);
[self.contactTableView reloadData];
[HUD hide:YES];
}
May be you are getting null value in contact by which you are getting null in conatctsWithPrefix
first print values stored in contact.
I need to convert XML response to JSON and sand to the json To javaScript code.
My XML response:
<cell>
<Result>True</Result>
<sguid>02291c402-2220-422b-b199-f92f22e56d2f</sguid>
</cell>
I am using XMLReader supporting file from this site:
XMLReader
I am using this code to convert XML to JSON :
+ (NSString*) XMLToJson:(CXMLDocument *)xmlDocument
{
NSError *error = nil;
NSArray *resultNodes = [xmlDocument nodesForXPath:#"//cell" error:&error];
if(error)
NSLog(#"%#",error.description);
CXMLNode *cellNode = [resultNodes objectAtIndex:0];
NSLog(#"%#",cellNode.XMLString);
NSError *parseError = nil;
NSDictionary *xmlDictionary = [XMLReader dictionaryForXMLString:cellNode.XMLString error:&parseError];
NSLog(#"%#", xmlDictionary);
//{print this.
// cell = {
// Result = {
// text = True;
// };
// sguid = {
// text = "0391c402-1120-460b-b199-f92fffe56d2f";
// };
// };
//}
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:xmlDictionary
options:NSJSONWritingPrettyPrinted // Pass 0 if you don't care about the readability of the generated string
error:&error];
if(error)
NSLog(#"%#",error.description);
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(#"%#", jsonString);
return jsonString;
}
I got JSON response like this:
{
"cell" : {
"Result" : {
"text" : "True"
},
"sguid" : {
"text" : "0391c402-1120-460b-b199-f92fffe56d2f"
}
}
}
I need JSON response like this:
{
"cell": {
"Result": "True",
"sguid": "02291c402-2220-422b-b199-f92f22e56d2f"
}
}
Because then I send this json to javascript code I get that exception jquery mobile dont know parser this and throws an exception of syntax error.
I've seen programmers use this solution and is helping them but I still get the same result in this solution.
XML into JSON conversion in iOS
thanks
I just wrote a function for your problem, I tried it on with a couple of XMLs. Let me know if you find any issues
- (NSMutableDictionary *)extractXML:(NSMutableDictionary *)XMLDictionary
{
for (NSString *key in [XMLDictionary allKeys]) {
// get the current object for this key
id object = [XMLDictionary objectForKey:key];
if ([object isKindOfClass:[NSDictionary class]]) {
if ([[object allKeys] count] == 1 &&
[[[object allKeys] objectAtIndex:0] isEqualToString:#"text"] &&
![[object objectForKey:#"text"] isKindOfClass:[NSDictionary class]]) {
// this means the object has the key "text" and has no node
// or array (for multiple values) attached to it.
[XMLDictionary setObject:[object objectForKey:#"text"] forKey:key];
}
else {
// go deeper
[self extractXML:object];
}
}
else if ([object isKindOfClass:[NSArray class]]) {
// this is an array of dictionaries, iterate
for (id inArrayObject in (NSArray *)object) {
if ([inArrayObject isKindOfClass:[NSDictionary class]]) {
// if this is a dictionary, go deeper
[self extractXML:inArrayObject];
}
}
}
}
return XMLDictionary;
}
And use it like this
NSDictionary *clearXML = [[self extractXML:[yourParsedXMLDictionary mutableCopy]] copy];
Your problem in using XMLReader. For resolve this problem you can use XMLConverter instead of the XMLReader.
I need to Post data in XML format. The server accepts a specific xml format. I don't want to write the xml by hand, what i want to do is create a NSMutableDictionary populate it and from NSMutableDictionary convert it XML.
I use this:
[NSPropertyListSerialization dataWithPropertyList:data format:NSPropertyListXMLFormat_v1_0 options:0
The sample return is this:
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0">
<dict>
<key>email</key>
<string>me#n.net</string>
<key>invoice_date</key>
<string>2012-10-11T10:35:09Z</string>
<key>invoice_lines</key>
<array>
<dict>
<key>product_id</key>
<integer>1021493</integer>
<key>quantity</key>
<real>1</real>
<key>retail_price</key>
<real>110</real>
</dict>
</array>
<key>payments</key>
<array>
<dict>
<key>amount</key>
<real>288.5</real>
</dict>
<dict>
<key>payment_type_id</key>
<integer>1</integer>
</dict>
</array>
The above format is not readable from the server.
The server need an xml feed like this.
<invoice>
<invoice_date>2012-10-11T10:35:09Z</invoice_date>
<email>me#n.net</email>
<invoice_lines type="array">
<invoice_line>
<product_id>1021505</product_id>
<quantity>1</quantity>
<retail_price>45</retail_price>
</invoice_line>
</invoice_lines>
<payments type="array">
<payment>
<amount>288.5</amount>
</payment>
</payments>
</invoice>
Is it possible to generate the above xml coming from a NSDictionary?
Thanks!
The short answer is: No, there is no built-in ability to do this in the Cocoa libraries.
Because you're writing rather than parsing, and presumably dealing with a limited universe of possible tags, the code to output XML is actually not that complicated. It should just be a simple method in your Invoice object, something like:
- (NSString*) postStringInXMLFormat
{
NSMutableString* returnValue = [[NSMutableString alloc] init];
if([self email])
{
[returnValue appendString:#"<email>"];
[returnValue appendString:[self email]];
[returnValue appendString:#"</email>"];
}
if([self invoice_date])
...
and so on. At the end return
[NSString stringWithString:returnValue]
There are plenty of third-party projects out there that try to generalize this process; several of them are listed in this answer:
Xml serialization library for iPhone Apps
But if all you're looking to do is create a single, stable format that your server side will recognize, and you don't have a ridiculous number of entities to convert, it's probably less work to roll your own.
Here is a recursive way to convert a dictionary to a string of XML. It handles dictionaries, arrays, and strings. Dictionary keys are the XML tags and the dictionary objects are used as values or child items in the tree. In the case of an array each element in the array is placed on the same child level with the same tag.
- (NSString*)ConvertDictionarytoXML:(NSDictionary*)dictionary withStartElement:(NSString*)startElement{
NSMutableString *xml = [[NSMutableString alloc] initWithString:#""];
[xml appendString:#"<?xml version=\"1.0\" encoding=\"utf-8\"?>"];
[xml appendString:[NSString stringWithFormat:#"<%#>",startElement]];
[self convertNode:dictionary withString:xml andTag:nil];
[xml appendString:[NSString stringWithFormat:#"</%#>",startElement]];
NSString *finalXML=[xml stringByReplacingOccurrencesOfString:#"&" withString:#"&"];
NSLog(#"%#",xml);
return finalXML;
}
- (void)convertNode:(id)node withString:(NSMutableString *)xml andTag:(NSString *)tag{
if ([node isKindOfClass:[NSDictionary class]] && !tag) {
NSArray *keys = [node allKeys];
for (NSString *key in keys) {
[self convertNode:[node objectForKey:key] withString:xml andTag:key];
}
}else if ([node isKindOfClass:[NSArray class]]) {
for (id value in node) {
[self convertNode:value withString:xml andTag:tag];
}
}else {
[xml appendString:[NSString stringWithFormat:#"<%#>", tag]];
if ([node isKindOfClass:[NSString class]]) {
[xml appendString:node];
}else if ([node isKindOfClass:[NSDictionary class]]) {
[self convertNode:node withString:xml andTag:nil];
}
[xml appendString:[NSString stringWithFormat:#"</%#>", tag]];
}
}
If you wouldn't use libraries or need additional customization:
- (NSString*)convertDictionaryToXML:(NSDictionary*)dictionary withStartElement:(NSString*)startElement
{
return [self convertDictionaryToXML:dictionary withStartElement:startElement isFirstElement:YES];
}
- (NSString*)convertDictionaryToXML:(NSDictionary*)dictionary withStartElement:(NSString*)startElement isFirstElement:(BOOL) isFirstElement
{
NSMutableString *xml = [[NSMutableString alloc] initWithString:#""];
NSArray *arr = [dictionary allKeys];
if (isFirstElement)
{
[xml appendString:#"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"];
}
[xml appendString:[NSString stringWithFormat:#"<%#>\n", startElement]];
for(int i=0; i < [arr count]; i++)
{
NSString *nodeName = [arr objectAtIndex:i];
id nodeValue = [dictionary objectForKey:nodeName];
if([nodeValue isKindOfClass:[NSArray class]])
{
if([nodeValue count]>0)
{
for(int j=0;j<[nodeValue count];j++)
{
id value = [nodeValue objectAtIndex:j];
if([value isKindOfClass:[NSDictionary class]])
{
[xml appendString:[self convertDictionaryToXML:value withStartElement:nodeName isFirstElement:NO]];
}
}
}
}
else if([nodeValue isKindOfClass:[NSDictionary class]])
{
[xml appendString:[self convertDictionaryToXML:nodeValue withStartElement:nodeName isFirstElement:NO]];
}
else
{
if([nodeValue length]>0){
[xml appendString:[NSString stringWithFormat:#"<%#>",nodeName]];
[xml appendString:[NSString stringWithFormat:#"%#",[dictionary objectForKey:nodeName]]];
[xml appendString:[NSString stringWithFormat:#"</%#>\n",nodeName]];
}
}
}
[xml appendString:[NSString stringWithFormat:#"</%#>\n",startElement]];
NSString *finalxml=[xml stringByReplacingOccurrencesOfString:#"&" withString:#"&"];
return finalxml;
}
and call this as:
NSString *xmlString = [self convertDictionaryToXML:data withStartElement:startElementName];
Taking the answer from #RemembranceNN ahead and converted it to Swift.
extension Dictionary {
func getXML(withStartElement startElement: String) -> String {
(self as NSDictionary).getXML(withStartElement: "message")
}
}
extension NSDictionary {
func getXML(withStartElement startElement: String, addLeafChildAsAttributes attrFlag: Bool, dontCreateNameSpaceChilds nsFlag: Bool) -> String {
var string = ""
var startTag = "<\(startElement)"
var tagValue = ""
for (key, value) in self {
if let arr = value as? NSArray {
for item in arr {
if let itemDict = item as? NSDictionary {
tagValue.append(itemDict.getXML(withStartElement: "\(key)", addLeafChildAsAttributes: attrFlag, dontCreateNameSpaceChilds: nsFlag))
} else {
tagValue.append("<\(key)>")
tagValue.append("\(item)")
tagValue.append("</\(key)>")
}
}
} else if let nestedDict = value as? NSDictionary {
tagValue.append(nestedDict.getXML(withStartElement: "\(key)", addLeafChildAsAttributes: attrFlag, dontCreateNameSpaceChilds: nsFlag))
} else {
if attrFlag || (nsFlag && "\(key)" == "xmlns") {
startTag.append(" \(key)=\"\(value)\"")
}
if !nsFlag || "\(key)" != "xmlns" {
tagValue.append("<\(key)>")
tagValue.append("\(value)")
tagValue.append("</\(key)>")
}
}
}
startTag.append(">")
string.append(startTag)
string.append(tagValue)
string.append("</\(startElement)>")
return string
}
}