I have simple Cocoa application, that parse JSON and pack information of JSON to object of Day class.
Day.h.
#import <Foundation/Foundation.h>
#interface Day : NSObject
#property(retain, nonatomic) NSString *dateString;
#end
main.m
import <Foundation/Foundation.h>
import </Users/Admin/Documents/SimpleJsonParser/SBJSON.h>
#import "Day.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
// source json object
NSString *jsonSource = #"{\"days\":[{\"dateString\":\"10 december\"},{\"dateString\":\"11 december\"}]}";
SBJsonParser *jsonParser = [[SBJsonParser alloc] init];
NSError *error = nil;
NSDictionary *jsonObjects = [jsonParser objectWithString:jsonSource error:&error];
if(error != nil){
NSLog([error description]);
}
// array of days objects
NSArray *days = [jsonObjects objectForKey:#"days"];
// create empty array
NSMutableArray *daysSource = [[NSMutableArray array] retain];
for(int i = 0; i < [days count]; i++){
NSDictionary *day = [days objectAtIndex:i];
// get dateString
NSString *dateString = [day objectForKey:#"dateString"];
// create Day object
Day* dayObject = [[Day alloc] init];
dayObject.dateString = dateString;
NSLog(dayObject.dateString);
[daysSource addObject:day];
}
NSUInteger temp = [daysSource count];
NSLog(#"Temp is %lu", temp);
Day *myDay = [daysSource objectAtIndex:0];
NSString *dateStringTemp = myDay.dateString;
}
}
And when I run this code, I get this error:
2012-12-11 14:09:50.867 SimpleJsonParser[577:303] -[__NSDictionaryM dateString]: unrecognized selector sent to instance 0x10010e4d0
2012-12-11 14:09:50.869 SimpleJsonParser[577:303] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSDictionaryM dateString]: unrecognized selector sent to instance 0x10010e4d0'
*** First throw call stack:
(
0 CoreFoundation 0x00007fff90a2e0a6 __exceptionPreprocess + 198
1 libobjc.A.dylib 0x00007fff8c6713f0 objc_exception_throw + 43
2 CoreFoundation 0x00007fff90ac46ea -[NSObject(NSObject) doesNotRecognizeSelector:] + 186
3 CoreFoundation 0x00007fff90a1c5ce ___forwarding___ + 414
4 CoreFoundation 0x00007fff90a1c3b8 _CF_forwarding_prep_0 + 232
5 SimpleJsonParser 0x0000000100001700 main + 704
6 libdyld.dylib 0x00007fff850b57e1 start + 0
7 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminate called throwing an exception
(lldb)
Why property "dateString" of Day class saved as NSDictionary?
You are adding the dictionary object to array not Day object.
Change:
[daysSource addObject:day];
to
[daysSource addObject:dayObject];
The object returned from [daysSource objectAtIndex:0] is an NSDictionary
NSDictionary *myDay = [daysSource objectAtIndex:0];
NSString *dateStringTemp = [myDay objectForKey:#"dateString"];
day is a dictionary. You store it in daySource and then do Day *myDay = [daysSource objectAtIndex:0];
Related
Recently my app got some crash report when convent NSData to NSString on ios10, the attachment image is the crash stack.The crash is collected by fabric and I can't reproduce it.
Does any one else met the same problem, Please tell me how to avoid the problem?
I have already checked the nsdata and ensure it is not nil.
[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]
#0. Crashed: com.apple.main-thread
0 libsystem_kernel.dylib 0x18b7f3014 __pthread_kill + 8
1 libsystem_pthread.dylib 0x18b8bb450 pthread_kill + 112
2 libsystem_c.dylib 0x18b767400 abort + 140
3 libsystem_malloc.dylib 0x18b837a5c _nano_vet_and_size_of_live + 330
4 libsystem_malloc.dylib 0x18b839028 nano_realloc + 648
5 libsystem_malloc.dylib 0x18b82b240 malloc_zone_realloc + 180
6 CoreFoundation 0x18c7e3958 __CFStringCreateImmutableFunnel3 + 692
7 CoreFoundation 0x18c76d81c CFStringCreateFromExternalRepresentation + 104
8 Foundation 0x18d253f64 -[NSPlaceholderString initWithData:encoding:] + 148
here is the crash detail screenshot
Check if your data is not nil and not Null
if (data && ![data isKindOfClass:[NSNull class]]) {
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]
}
Check condition for NSData is not nil, data.length > 0 means it contains some value.
if(data.length > 0){
NSString *tempString =[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
//Do your tasks here
}
I have tried a few things,
id class = [self.navigationController.viewControllers[1] class];
class *Routeview=(class *)self.parentViewController;
To be more precise,
I have a class A which has a method method1, and I have two more classes class B and class C. so I want to find out at runtime which class is calling the method1 Class B or class C.
try following:
Add this in your method,
NSString *sourceString = [[NSThread callStackSymbols] objectAtIndex:1];
// Example: 1 UIKit 0x00540c89 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1163
NSCharacterSet *separatorSet = [NSCharacterSet characterSetWithCharactersInString:#" -[]+?.,"];
NSMutableArray *array = [NSMutableArray arrayWithArray:[sourceString componentsSeparatedByCharactersInSet:separatorSet]];
[array removeObject:#""];
NSLog(#"Stack = %#", [array objectAtIndex:0]);
NSLog(#"Framework = %#", [array objectAtIndex:1]);
NSLog(#"Memory address = %#", [array objectAtIndex:2]);
NSLog(#"Class caller = %#", [array objectAtIndex:3]);
NSLog(#"Function caller = %#", [array objectAtIndex:4]);
I have had a little search for this problem but cant seem to find a solution so hope you can help.
Basically I have built an app that saves a customers input data to a .csv file. Now I wish to display this information within the app but only the last entered user data (the other data of the users needs to be saved to the .csv but doesnt need to be viewed until later in a database) I can get it to load all the data but I only want the last submitted data displayed in the app... Here is my code so far;
-(IBAction)saveinfo:(id)sender{
NSString *resultLine=[NSString stringWithFormat:#"%# , %# , %# , %# , %# , %#, %#\n\n\n\n\n\n\n",
self.customername.text,
self.houseno.text,
self.customerpostcode.text,
self.catno.text,
_ordervalresult.text,
_reordervalresult.text,
self.date.text
];
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];
//resultview.text = docPath;
NSString *surveys=[docPath stringByAppendingPathComponent:#"customerdata.csv"];
if (![[NSFileManager defaultManager] fileExistsAtPath:surveys]) {
[[NSFileManager defaultManager]
createFileAtPath:surveys contents:nil attributes:nil];
}
NSFileHandle *filehandle = [NSFileHandle fileHandleForUpdatingAtPath:surveys];
[filehandle seekToEndOfFile];
[filehandle writeData:[resultLine dataUsingEncoding:NSUTF8StringEncoding]];
[filehandle closeFile];
self.customername.text=#"";
self.houseno.text=#"";
self.customerpostcode.text=#"";
self.catno.text=#"";
self.date.text=#"";
_orderval.value=0;
_reorderval.value=0;
_ordervalresult.text=#"£0.00";
_reordervalresult.text=#"£0.00";
NSLog(#"surveys path: %#", surveys);
}
-(IBAction)retrieveinfo:(id)sender {
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];
//resultView.text = docPath;
NSString *surveys=[docPath stringByAppendingPathComponent:#"customerdata.csv"];
if([[NSFileManager defaultManager] fileExistsAtPath: surveys])
{
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:surveys];
NSString *surveyResults =[[NSString alloc]initWithData:[fileHandle availableData] encoding:NSUTF8StringEncoding];
[fileHandle closeFile];
self.resultview.text=surveyResults;
}
}
Anyone know how to tackle this? I have tried a few ideas but can either only load all the information or none at all...
Thank you for your time
EDIT: UPDATED CODE
-(IBAction)retrieveinfo:(id)sender {
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];
_resultview.text = docPath;
NSString *surveys=[docPath stringByAppendingPathComponent:#"customerdata.csv"];
if([[NSFileManager defaultManager] fileExistsAtPath: surveys])
self.resultview.text=surveys;
//This is a part of your code from retrieveinfo:sender:
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:surveys];
NSString *surveyResults =[[NSString alloc]initWithData:[fileHandle availableData] encoding:NSUTF8StringEncoding];
[fileHandle closeFile];
//All lines of you CSV file
NSArray *allLines = [surveyResults componentsSeparatedByString:#"\n"];
//To get Last Line
NSString *lastEntry = [allLines lastObject]; //or [allLines firstObject]; depending on the order your build it, but if I understood correctly it should be lastObject
NSArray *lastData = [lastEntry componentsSeparatedByString:#","];
NSString *lastCustomerName = [lastData objectAtIndex:0];
NSString *lastHouseNo = [lastData objectAtIndex:1];
NSString *lastCustomerPostcode = [lastData objectAtIndex:2];
I'd do this:
-(IBAction)pushRetrieveLastInfo:(id)sender
{
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];
NSString *surveys=[docPath stringByAppendingPathComponent:#"customerdata.csv"];
if([[NSFileManager defaultManager] fileExistsAtPath: surveys])
{
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:surveys];
NSString *surveyResults =[[NSString alloc]initWithData:[fileHandle availableData] encoding:NSUTF8StringEncoding];
[fileHandle closeFile];
//All lines of you CSV file
NSArray *allLines = [surveyResults componentsSeparatedByString:#"\n"];
//To get Last Line
NSString *lastEntry = [allLines lastObject]; //or [allLines firstObject]; depending on the order your build it, but if I understood correctly it should be lastObject
self.resultview.text=lastEntry;
}
}
Or:
-(IBAction)pushRetrieveLastInfo:(id)sender
{
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];
NSString *surveys=[docPath stringByAppendingPathComponent:#"customerdata.csv"];
if([[NSFileManager defaultManager] fileExistsAtPath: surveys])
{
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:surveys];
NSString *surveyResults =[[NSString alloc]initWithData:[fileHandle availableData] encoding:NSUTF8StringEncoding];
[fileHandle closeFile];
//All lines of you CSV file
NSArray *allLines = [surveyResults componentsSeparatedByString:#"\n"];
//To get Last Line
NSString *lastEntry = [allLines lastObject]; //or [allLines firstObject]; depending on the order your build it, but if I understood correctly it should be lastObject
NSArray *lastData = [lastEntry componentsSeparatedByString:#","];
NSString *lastCustomerName = [lastData objectAtIndex:0];
NSString *lastHouseNo = [lastData objectAtIndex:1];
NSString *lastCustomerPostcode = [lastData objectAtIndex:2];
NSString *lastCatNo = [lastData objectAtIndex:3];
NSString *lastOrderValResult = [lastData objectAtIndex:4];
NSString *lastReorderValResult = [lastData objectAtIndex:5];
NSString *lastDate = [lastData objectAtIndex:6];
NSString *textResult = [NSString stringWithFormat:#"Name: %#\nHouse Nb: %#\n, Last Postcode: %#\n, Last Cat Nb: %#\n, Last Order: %#\n, Last Reorder: %#\n, Last date: %#", lastCustomerName, lastHouseNo, lastCustomerPostcode, lastCatNo, lastOrderValResult, lastReorderValResult, lastDate];
self.resultview.text=textResult;
}
}
Seems that you could be also playing with the offset of the NSFileHandle, but it seems more complicated to me.
Error Message:
2014-09-10 17:37:53.888 Betterware - Database and Customer Information[15676:60b] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
*** First throw call stack:
(
0 CoreFoundation 0x017f01e4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x0156f8e5 objc_exception_throw + 44
2 CoreFoundation 0x017a48b2 -[__NSArrayI objectAtIndex:] + 210
3 Betterware - Database and Customer Information 0x00002746 -[ViewController retrieveinfo:] + 726
4 libobjc.A.dylib 0x01581880 -[NSObject performSelector:withObject:withObject:] + 77
5 UIKit 0x002313b9 -[UIApplication sendAction:to:from:forEvent:] + 108
6 UIKit 0x00231345 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 61
7 UIKit 0x00332bd1 -[UIControl sendAction:to:forEvent:] + 66
8 UIKit 0x00332fc6 -[UIControl _sendActionsForEvents:withEvent:] + 577
9 UIKit 0x00332243 -[UIControl touchesEnded:withEvent:] + 641
10 UIKit 0x00270ddd -[UIWindow _sendTouchesForEvent:] + 852
11 UIKit 0x002719d1 -[UIWindow sendEvent:] + 1117
12 UIKit 0x002435f2 -[UIApplication sendEvent:] + 242
13 UIKit 0x0022d353 _UIApplicationHandleEventQueue + 11455
14 CoreFoundation 0x0177977f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
15 CoreFoundation 0x0177910b __CFRunLoopDoSources0 + 235
16 CoreFoundation 0x017961ae __CFRunLoopRun + 910
17 CoreFoundation 0x017959d3 CFRunLoopRunSpecific + 467
18 CoreFoundation 0x017957eb CFRunLoopRunInMode + 123
19 GraphicsServices 0x037e45ee GSEventRunModal + 192
20 GraphicsServices 0x037e442b GSEventRun + 104
21 UIKit 0x0022ff9b UIApplicationMain + 1225
22 Betterware - Database and Customer Information 0x0000411d main + 141
23 libdyld.dylib 0x01e37701 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
An NSMutableArray was created with 64 capacity. A NSString object was added. However, string value of the object is nil.
static NSString* cake = #"cake";
...
NSMutableArray* food = [NSMutableArray arrayWithCapacity:64];
[food addObject:[NSString stringWithString:cake]];
NSString* dessert = [[food objectAtIndex:0]stringValue];
// dessert is nil
if [NSString stringWithString: cake] is replaced with just cake, it throws an exception
Here is an entire program which is less than 10 lines of code and does not work
#import <Foundation/Foundation.h>
static NSString* cake = #"cake";
int main(int argc, const char * argv[]){
#autoreleasepool {
NSMutableArray* food = [NSMutableArray arrayWithCapacity:64];
[food addObject:cake];
NSString* dessert = [[food objectAtIndex:0]stringValue];
}
}
It throws an exception.
The problem is likely that your array is nil. This code works.
NSMutableArray *foodArray = [NSMutableArray array];
[foodArray addObject:#"cake"];
NSString *dessert = foodArray[0]; //dessert is "cake"
Update
The unrecognized selector exception you are getting is the result of calling stringValue on an NSString. As #Chuck noted, NSString does not have that method.
Say I have a class with two NSMutableDictionary.
#interface GameDataManager : CCNode {
NSMutableDictionary *worldInfoDictionary;
NSMutableDictionary *levelInfoDictionary;
}
#property (nonatomic, retain) NSMutableDictionary *worldInfoDictionary;
#property (nonatomic, retain) NSMutableDictionary *levelInfoDictionary;
And I load the data from the plist while the app start like this:
-(BOOL) readApplicationData:(NSString *)fileName
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *appFile = [documentsDirectory stringByAppendingPathComponent:fileName];
NSData *myData = [[[NSData alloc] initWithContentsOfFile:appFile] autorelease];
if (myData == nil) {
return NO;
}
NSKeyedUnarchiver *un = [[NSKeyedUnarchiver alloc] initForReadingWithData:myData];
NSMutableDictionary *dic = [un decodeObjectForKey:#"GameData"];
self.worldInfoDictionary = [dic objectForKey:#"WorldInfoDictionary"];
self.levelInfoDictionary = [dic objectForKey:#"LevelInfoDictionary"];
for (int i = 1; i <= 10; i++) {
WorldInfoData * w = [worldInfoDictionary objectForKey:
[[[NSString alloc] initWithFormat:#"World%d", i] autorelease]];
NSLog(#"%d", w.worldNum);
[w release];
}
[un finishDecoding];
[un release];
return YES;
}
After the next two lines:
self.worldInfoDictionary = [dic objectForKey:#"WorldInfoDictionary"];
self.levelInfoDictionary = [dic objectForKey:#"LevelInfoDictionary"];
I can see the number of values/keys in two Dictionaries are right.
Then I tried to print out all the "worldNum" value for each object but the app
crahed:
2011-03-07 15:18:21.819 [1267:207] 1
2011-03-07 15:18:21.820 [1267:207] 2
2011-03-07 15:18:21.821 [1267:207] 3
2011-03-07 15:18:21.823 [1267:207] 4
2011-03-07 15:18:21.831 [1267:207] 5
2011-03-07 15:18:21.832 [1267:207] 6
2011-03-07 15:18:21.832 [1267:207] 7
2011-03-07 15:18:21.833 [1267:207] 8
2011-03-07 15:18:21.834 [1267:207] 9
2011-03-07 15:18:21.834 [1267:207] 10
Stack dump:
0. Running pass 'Sparse Conditional Constant Propagation' on function '#gleLLVMVecProjectionTransform2'
If I uncomment this line:
[un release];
The app works fine, no crash.
Can anybody explain this to me, thanks a lot^_^
Thanks for all the answers.
But if I delete the code lines I used to output some info:
for (int i = 1; i <= 10; i++) {
WorldInfoData * w = [worldInfoDictionary objectForKey:
[[[NSString alloc] initWithFormat:#"World%d", i] autorelease]];
NSLog(#"%d", w.worldNum);
[w release];
}
And uncomment the line "[un release];", the readApplicationData works fine,
but when I tried to read the data later like this:
NSMutableDictionary *dic = [GameDataManager sharedGameDataManager].worldInfoDictionary;
for (int i = 1; i <= 10; i++) {
NSString *key = [[NSString alloc] initWithFormat:#"World%d", i];
WorldInfoData *worldInfoData = [dic objectForKey:key];
if (worldInfoData.worldNum == 1) {
//......
}
[key release];
}
After this line : "WorldInfoData *worldInfoData = [dic objectForKey:key];", the type of worldInfoData
is not WorldInfoData * but CCArray, and since CCArray don't have property
worldNum, it crashed......
First, I would suggest running your application with Zombie detection enabled.
What you will find is a notification that you are overreleasing 'w'.
WorldInfoData * w = [worldInfoDictionary objectForKey:
[[[NSString alloc] initWithFormat:#"World%d", i] autorelease]];
NSLog(#"%d", w.worldNum);
[w release];
You add 'w' to the autorelease pool, but then call release on it explicitly. I would guess that getting rid of the [w release]; line will fix your problem or don't add 'w' to the autorelease pool.