Why NSData convert to NSString crashed on ios10 - objective-c

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
}

Related

I am getting EXC_BAD_ACCESS in creating NSString using stringWithFormat

Stack trace:
0 libobjc.A.dylib 0x00007fff2021a26e objc_opt_respondsToSelector + 27
1 com.apple.CoreFoundation 0x00007fff20405674 __CFStringAppendFormatCore + 9123
2 com.apple.CoreFoundation 0x00007fff20534412 _CFStringCreateWithFormatAndArgumentsReturningMetadata + 145
3 com.apple.CoreFoundation 0x00007fff204032cb _CFStringCreateWithFormatAndArgumentsAux2 + 20
4 com.apple.Foundation 0x00007fff210d1eef +[NSString stringWithFormat:] + 153
Faulting Code:
NSString* GetPlistPath(){
return [[NSString stringWithFormat:#"%#/%#/%#",UserLibrary,PREFERENCE_PLIST_DIR_NAME,PREFERENCE_PLIST_NAME] stringByExpandingTildeInPath];
}
Where UserLibrary is an NSString* and PREFERENCE_PLIST_DIR_NAME and PREFERENCE_PLIST_NAME are NSString* const.

Display last submitted data from .csv file?

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

How can a string be converted into binary with the spaces intact?

For my app, I want to convert an NSString to a NSMutableString containing the binary equivalent. All spaces must be put in the appropriate spot.
I've found a snippet that converts the string to binary, but all spaces are excluded. It looked like this more or less:
NSMutableString *str2 = [NSMutableString stringWithFormat:#""];
for(NSInteger numberCopy = str; numberCopy > 0; numberCopy >>=1) {
//Prepend "0" or "1", depending on the bit
[str2 insertString:((numberCopy & 1) ? #"1" : #"0") atIndex:0];
}
Str is input, str2 is output.
For the version that includes spaces, I have an array divide the input string by componentsSeparatedByString: #" ", and then the binary converter snippet (above) to each array object. I add the spaces back in.
However, I get the console error
*** -[__NSArrayM objectAtIndex:]: index 2 beyond bounds [0 .. 1]
Followed by this (although I don't think its important):
0 CoreFoundation 0x00007fff84a08b06 __exceptionPreprocess + 198
1 libobjc.A.dylib 0x00007fff8c72f3f0 objc_exception_throw + 43
2 CoreFoundation 0x00007fff849a58ec -[__NSArrayM objectAtIndex:] + 252
3 G-Clock 0x0000000100001ff1 -[GCAppController tick:] + 1937
4 Foundation 0x00007fff8a011d05 __NSFireDelayedPerform + 358
5 CoreFoundation 0x00007fff849c5804 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 20
6 CoreFoundation 0x00007fff849c531d __CFRunLoopDoTimer + 557
7 CoreFoundation 0x00007fff849aaad9 __CFRunLoopRun + 1529
8 CoreFoundation 0x00007fff849aa0e2 CFRunLoopRunSpecific + 290
9 HIToolbox 0x00007fff83bbdeb4 RunCurrentEventLoopInMode + 209
10 HIToolbox 0x00007fff83bbdb94 ReceiveNextEventCommon + 166
11 HIToolbox 0x00007fff83bbdae3 BlockUntilNextEventMatchingListInMode + 62
12 AppKit 0x00007fff88b7a533 _DPSNextEvent + 685
13 AppKit 0x00007fff88b79df2 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 128
14 AppKit 0x00007fff88b711a3 -[NSApplication run] + 517
15 AppKit 0x00007fff88b15bd6 NSApplicationMain + 869
16 G-Clock 0x0000000100000ea2 main + 34
17 libdyld.dylib 0x00007fff864fc7e1 start + 0
18 ??? 0x0000000000000003 0x0 + 3
)
I can't figure out whats wrong, let alone how to change it.
My code, with str being input and str2 being output:
//Convert to binary
NSMutableString *str2 = [NSMutableString stringWithFormat:#""];
int count = -1;
NSArray *array = [str componentsSeparatedByString: #" "];
NSUInteger numObjects = [array count];
//Converts each object of array into binary separately, so spaces remain intact.
while (1) {
++count;
NSString *string = array[count];
NSMutableString *mutStr = [NSMutableString stringWithFormat:#""];
for (NSInteger numberCopy = [string intValue]; numberCopy > 0; numberCopy >>=1) {
//Prepend "0" or "1", depending on the bit
[mutStr insertString:((numberCopy & 1) ? #"1" : #"0") atIndex:0];
}
if (numObjects != count + 1) {
//Add space if this is not last run through
[mutStr appendString: #" "];
} else break;
[str2 appendString: mutStr];
}
You have two places in the loop where count is incremented.
Also mutStr must be appended to str2 in any case.
But I would use a for-loop instead:
for (count = 0; count < numObjects; count++) {
NSString *string = array[count];
NSMutableString *mutStr = [NSMutableString stringWithFormat:#""];
for (NSInteger numberCopy = [string intValue]; numberCopy > 0; numberCopy >>=1) {
//Prepend "0" or "1", depending on the bit
[mutStr insertString:((numberCopy & 1) ? #"1" : #"0") atIndex:0];
}
[str2 appendString: mutStr];
if (numObjects != count + 1) {
//Add space if this is not last run through
[str2 appendString: #" "];
}
}
It was a logic error. After #Martin 's part, on the last run, the else break was after the part where [array count] was called, and since there was no array object at that index of count, the program broke.
while (1) {
++count;
if (count == numbObjects)
break;
...
}

Execute a terminal command from a Cocoa Desktop app

I am trying to execute a command for creating a Cordova Project in my Cocoa Desktop App but It doesn't work.
That's my code:
NSTask *task = [NSTask new];
[task setLaunchPath:#"/Documents/Cordova/bin/ ./create ~/Documents/Cordova/HelloWorld2 org.apache.cordova.HelloWorld2 HelloWorld2"];
[task setArguments:[NSArray arrayWithObjects:#"-l", #"-a", #"-t", nil]];
NSPipe *pipe = [NSPipe pipe];
[task setStandardOutput:pipe];
[task launch];
NSData *data = [[pipe fileHandleForReading] readDataToEndOfFile];
[task waitUntilExit];
// [task release];
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog (#"got\n%#", string);
And that's output:
2013-04-02 23:48:18.968 Phonegap-ProjectCreator[2209:303] launch path not accessible
2013-04-02 23:48:18.970 Phonegap-ProjectCreator[2209:303] (
0 CoreFoundation 0x00007fff8b2b80a6 __exceptionPreprocess + 198
1 libobjc.A.dylib 0x00007fff88d7e3f0 objc_exception_throw + 43
2 CoreFoundation 0x00007fff8b2b7e7c +[NSException raise:format:] + 204
3 Foundation 0x00007fff8bd21cd2 -[NSConcreteTask launchWithDictionary:] + 409
4 Phonegap-ProjectCreator 0x0000000100002a4a -[MainWindow createProject:] + 314
5 AppKit 0x00007fff94506a59 -[NSApplication sendAction:to:from:] + 342
6 AppKit 0x00007fff945068b7 -[NSControl sendAction:to:] + 85
7 AppKit 0x00007fff945067eb -[NSCell _sendActionFrom:] + 138
8 AppKit 0x00007fff94504cd3 -[NSCell trackMouse:inRect:ofView:untilMouseUp:] + 1855
9 AppKit 0x00007fff94504521 -[NSButtonCell trackMouse:inRect:ofView:untilMouseUp:] + 504
10 AppKit 0x00007fff94503c9c -[NSControl mouseDown:] + 820
11 AppKit 0x00007fff944fb60e -[NSWindow sendEvent:] + 6853
12 AppKit 0x00007fff944f7744 -[NSApplication sendEvent:] + 5761
13 AppKit 0x00007fff9440d2fa -[NSApplication run] + 636
14 AppKit 0x00007fff943b1cb6 NSApplicationMain + 869
15 Phonegap-ProjectCreator 0x00000001000011d2 main + 34
16 libdyld.dylib 0x00007fff89ced7e1 start + 0
17 ??? 0x0000000000000003 0x0 + 3
)
I don't understand what is the problem? It can't find path for executing or can't execute?
The launch path is the path to be launched, not the command line to be invoked. It should only contain the path to the executable to be run.
The arguments array is the arguments that should be passed. You are mixing the two.
Your executable looks to be "/Documents/Cordova/bin/create"
Arguments appear to be something like:
NSArray *args = #["-l", "~/Documents/Cordova/HelloWorld2", "-a", "org.apache.cordova.HelloWorld2", "-t", "HelloWorld2"];
I.e. arguments have values and the values are interleaved with the arguments in the arguments array.
I found the solution. I am new to objective c and I realized I made a lot of mistake.
That's the solution:
/** Path to Application **/
NSString *path = #"/Users/username/Documents/Cordova/bin/create";
/** Arguments **/
NSArray *args = [NSArray arrayWithObjects:#"/Users/username/Documents/Cordova/HelloWorld3",#"org.apache.cordova.HelloWorld3",#"HelloWorld3", nil];
[[NSTask launchedTaskWithLaunchPath:path arguments:args] waitUntilExit];

Error when get object from array element property

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];