xcode - alert that shows crash reason - objective-c

Is there a way to build an alert box that shows what the crash reason is? Specifically, what line of code is causing the crash?
My boss is asking for this, and I haven't found a way to make this possible. I'm going through the analytics tab on the device and finding the crash, but he wants something that populates on the device (it's an internal app) giving the reason for the crash.
Is this possible?

If you want to show an alert when app crashes you can't do that but you can read the crash log when you open the app again after a crash.
You could create a method with following logic, it basically reads back trace for last crash when you open the app again after a crash.
aslmsg q, m;
int i;
const char *key, *val;
float how_old = fTime ;
q = asl_new(ASL_TYPE_QUERY);
asl_set_query(q, ASL_KEY_LEVEL, strLoggerLevel ,ASL_QUERY_OP_LESS_EQUAL);
asl_set_query(q, ASL_KEY_FACILITY, [#"YourBundleIdOfAPP" UTF8String] ,ASL_QUERY_OP_EQUAL);
asl_set_query(q, ASL_KEY_TIME, [[NSString stringWithFormat:#"%.f", [[NSDate date] timeIntervalSince1970] - how_old] UTF8String], ASL_QUERY_OP_GREATER_EQUAL);
int goInside=0;
aslresponse r = asl_search(NULL, q);
while (NULL != (m = aslresponse_next(r)))
{
NSString *cValueToWrite;
NSMutableDictionary *tmpDict = [NSMutableDictionary dictionary];
for (i = 0; (NULL != (key = asl_key(m, i))); i++)
{
//get the only required fields
if(i==12 || i==10 || i==11 || i==8 || i==9 ||i==3)
{
NSString *keyString = [NSString stringWithUTF8String:(char *)key];
val = asl_get(m, key);
NSString *string = [NSString stringWithUTF8String:val];
[tmpDict setObject:string forKey:keyString];
}
}
cValueToWrite=[[NSString alloc]initWithFormat:#"\n--------------[Debug]----------------\nDateTime: %#\nApplication: %#\nInfo: %#",[tmpDict valueForKey:#"CFLog Local Time"],[tmpDict valueForKey:#"Sender"],[tmpDict valueForKey:#"Message"]];
}
strLoggerLevel is the NSString which hold the logger type which you want which ranges upto 7

Related

CGDisplayIOServicePort is deprecated in OS X >= 10.9, how to replace?

I did small app to allow quickly change screen resolutions on multiple monitors. I want to show product name as title of the monitor, and it's very simple to find using this code:
NSDictionary *deviceInfo = (__bridge NSDictionary *)IODisplayCreateInfoDictionary(CGDisplayIOServicePort(dispID), kIODisplayOnlyPreferredName);
NSDictionary *localizedNames = [deviceInfo objectForKey:[NSString stringWithUTF8String:kDisplayProductName]];
if([localizedNames count] > 0) {
_title = [localizedNames objectForKey:[[localizedNames allKeys] objectAtIndex:0]];
} else {
_title = #"Unknown display";
}
But CGDisplayIOServicePort is deprecated in OS X >= 10.9 and Apple's documentation says there is no replacement. How to find service port or product name without using this method?
I tried to iterate through IO-registry and tried to use IOServiceGetMatchingServices method to find display services but I'm not very familiar with IO-registry so I couldn't find solution.
Thanks for help!
It looks like #Eun's post missed a piece of information to close this discussion. With a little search, I found that IOServicePortFromCGDisplayID is not an API which Apple provides. Rather, it's a piece of open source code found here:
https://github.com/glfw/glfw/blob/e0a6772e5e4c672179fc69a90bcda3369792ed1f/src/cocoa_monitor.m
I copied IOServicePortFromCGDisplayID and also 'getDisplayName' from it.
I needed two tweaks to make it work on OS X 10.10.
Remove the code to handle serial number in IOServicePortFromCGDisplayID. (CFDictionaryGetValue for
kDisplaySerialNumber returns NULL for me.)
Remove project specific
error handling code in getDisplayName.
If you need more information
Issue tracker of the problem: github.com/glfw/glfw/issues/165
Commit
for the solution:
github.com/glfw/glfw/commit/e0a6772e5e4c672179fc69a90bcda3369792ed1f
I would thank Matthew Henry who submitted the code there.
Here is my take on the issue. I also started with the code from GLFW 3.1, file cocoa_monitor.m.
But I had to modify it in different ways than Hiroshi said, so here goes:
// Get the name of the specified display
- (NSString*) screenNameForDisplay: (NSNumber*) screen_id
{
CGDirectDisplayID displayID = [screen_id unsignedIntValue];
io_service_t serv = [self IOServicePortFromCGDisplayID: displayID];
if (serv == 0)
return #"unknown";
CFDictionaryRef info = IODisplayCreateInfoDictionary(serv, kIODisplayOnlyPreferredName);
IOObjectRelease(serv);
CFStringRef display_name;
CFDictionaryRef names = CFDictionaryGetValue(info, CFSTR(kDisplayProductName));
if ( !names ||
!CFDictionaryGetValueIfPresent(names, CFSTR("en_US"), (const void**) & display_name) )
{
// This may happen if a desktop Mac is running headless
CFRelease( info );
return #"unknown";
}
NSString * displayname = [NSString stringWithString: (__bridge NSString *) display_name];
CFRelease(info);
return displayname;
}
// Returns the io_service_t (an int) corresponding to a CG display ID, or 0 on failure.
// The io_service_t should be released with IOObjectRelease when not needed.
- (io_service_t) IOServicePortFromCGDisplayID: (CGDirectDisplayID) displayID
{
io_iterator_t iter;
io_service_t serv, servicePort = 0;
CFMutableDictionaryRef matching = IOServiceMatching("IODisplayConnect");
// releases matching for us
kern_return_t err = IOServiceGetMatchingServices( kIOMasterPortDefault, matching, & iter );
if ( err )
return 0;
while ( (serv = IOIteratorNext(iter)) != 0 )
{
CFDictionaryRef displayInfo;
CFNumberRef vendorIDRef;
CFNumberRef productIDRef;
CFNumberRef serialNumberRef;
displayInfo = IODisplayCreateInfoDictionary( serv, kIODisplayOnlyPreferredName );
Boolean success;
success = CFDictionaryGetValueIfPresent( displayInfo, CFSTR(kDisplayVendorID), (const void**) & vendorIDRef );
success &= CFDictionaryGetValueIfPresent( displayInfo, CFSTR(kDisplayProductID), (const void**) & productIDRef );
if ( !success )
{
CFRelease(displayInfo);
continue;
}
SInt32 vendorID;
CFNumberGetValue( vendorIDRef, kCFNumberSInt32Type, &vendorID );
SInt32 productID;
CFNumberGetValue( productIDRef, kCFNumberSInt32Type, &productID );
// If a serial number is found, use it.
// Otherwise serial number will be nil (= 0) which will match with the output of 'CGDisplaySerialNumber'
SInt32 serialNumber = 0;
if ( CFDictionaryGetValueIfPresent(displayInfo, CFSTR(kDisplaySerialNumber), (const void**) & serialNumberRef) )
{
CFNumberGetValue( serialNumberRef, kCFNumberSInt32Type, &serialNumber );
}
// If the vendor and product id along with the serial don't match
// then we are not looking at the correct monitor.
// NOTE: The serial number is important in cases where two monitors
// are the exact same.
if( CGDisplayVendorNumber(displayID) != vendorID ||
CGDisplayModelNumber(displayID) != productID ||
CGDisplaySerialNumber(displayID) != serialNumber )
{
CFRelease(displayInfo);
continue;
}
servicePort = serv;
CFRelease(displayInfo);
break;
}
IOObjectRelease(iter);
return servicePort;
}
This works fine for me in a screensaver I wrote under macOS 10.11 (El Capitan).
I tested it with the built-in display of my MacBookPro and an Apple Display connected via Thunderbolt.
As of macOS 10.15 -[NSScreen localizedName] is available:
NSLog(#"Name of main display is %#", NSScreen.mainScreen.localizedName);
NSString* screenNameForDisplay(CGDirectDisplayID displayID)
{
NSString *screenName = nil;
io_service_t service = IOServicePortFromCGDisplayID(displayID);
if (service)
{
NSDictionary *deviceInfo = (NSDictionary *)IODisplayCreateInfoDictionary(service, kIODisplayOnlyPreferredName);
NSDictionary *localizedNames = [deviceInfo objectForKey:[NSString stringWithUTF8String:kDisplayProductName]];
if ([localizedNames count] > 0) {
screenName = [[localizedNames objectForKey:[[localizedNames allKeys] objectAtIndex:0]] retain];
}
[deviceInfo release];
}
return [screenName autorelease];
}

EXC_BAD_INSTRUCTION when using NSRunAlertPanel

To show errors on some condition, I am using NSRunAlertPanel on Mac OS X (on the code which is ported from Windows, where I was using MessageBox).
Before actual creation of Windows, some code is being run and calling this code to show some conditional error.
In a thread com.apple.libdispatch-manager, under following call stack
0 _dispatch_mgr_invoke
1 _dispatch_mgr_thread
it is giving EXC_BAD_INSTRUCTION
Is it because Windows is not created before NSRunAlertPanel?
What is the reason of this runtime error? What is exact alternative of MessageBox on Mac OS X?
Long ShowDebugMessageBox (const wchar_t * Message, const wchar_t * Title)
{
NSString * message; ///< Message.
NSString * title; ///< Title.
NSInteger response; ///< response.
message = WideToNSString (Message);
title = WideToNSString (Title);
//response = NSRunAlertPanel(title, message, #"Yes", #"No", #"Cancel");
response = NSRunCriticalAlertPanel (title, message, #"Okay", #"Cancel", nil);
switch(response) {
case NSAlertDefaultReturn:
return IDYES;
case NSAlertAlternateReturn:
return IDNO;
default:
return IDCANCEL;
}
}
NSString * WideToNSString (const wchar_t * Str)
{
if(!Str) {
return nil;
}
NSString * str; ///< String in NSString.
#if CP_SIZEOFWCHAR == 4
str = [[NSString alloc] initWithBytes: (CVPtr) Str
length: sizeof(wchar_t)* wcslen(Str)
encoding: NSUTF32LittleEndianStringEncoding];
//encoding: NSUTF32StringEncoding];
#else
str = [[NSString alloc] initWithBytes: (CVPtr) Str
length: sizeof(wchar_t)* wcslen(Str);
encoding: NSUTF16LittleEndianStringEncoding];
//encoding: NSUTF16StringEncoding];
#endif
return str;
}
class File {
public:
int Open(char * fname, int mode)
{
fd = open(fname, mode);
}
int Close()
{
close(fd);
//fd = 0; //CAUSE of the PROBLEM
}
~File ()
{
//ALERT Display message box about the error.
ALERT(fd != 0);
}
private:
int fd;
};
This is the code to show the message box.
Code to get NSString from wchar_t * string (Wide string) is perfectly fine and was tested. It is used in many places and running fine.
Same code on the other application (which creates Window first) is running fine.
Problem occurs when the destructor of File is called. Since fd is not 0, it shows message box and cause the problem.
When fd is set to 0, no alert box is displayed for constructor. However, other alert are shown but no problem occurred.
Is it due fd?
You haven't provided enough information to say what is causing the exception (please show the code).
I use NSRunCriticalAlertPanel() to display fatal errors in my app, which I am able to call pretty much any time I like:
void criticalAlertPanel(NSString *title, NSString *fmt, ...)
{
va_list va;
va_start(va, fmt);
NSString *message = [[NSString alloc] initWithFormat:fmt arguments:va];
va_end(va);
NSRunCriticalAlertPanel(title, message, #"OK", nil, nil);
}
(this code is ARC enabled).

Substring with range out of bounds?

Okay, so this is a bit confusing (well to me). I have a string that has a single number I want out of it. I have surrounded this number with '/' so that I will be able to get that number out of it later.
Here is how I am getting the number out of it:
if ([MYSTRING hasSuffix:#"mp"]) {
int start = 0;
int end = 0;
char looking = '/';
for(int i=0; i < MYSTRING.length; i++){
if (looking == [MYSTRING characterAtIndex:i]) {
if (start == 0) {
start = i;
}
else{
end = i + 1;
}
}
}
NSLog(#"%#", MYSTRING); //When i NSLOG here i get '2012-06-21 03:58:00 +0000/1/mp', 1 is the number i want out of the string, but this number could also change to 55 or whatever the user has
NSLog(#"start: %i, end: %i", start, end); //When i NSLOG here i get 'start: 25, end: 28'
NSString *number = [MYSTRING substringWithRange:NSMakeRange(start, end)];
number = [number stringByReplacingOccurrencesOfString:#"/" withString:#""];
if ([number intValue] > numberInt) {
numberInt = [number intValue];
}
It keeps crashing and the console says:
* Terminating app due to uncaught exception 'NSRangeException', reason: '-[__NSCFString substringWithRange:]: Range or index out of bounds'
* First throw call stack:
(0x1875d72 0x106ce51 0x1875b4b 0x184ea64 0x3a6c 0x1080713 0x1bf59 0x1bef1 0xd532e 0xd588c 0xd49f5 0x49a2f 0x49c42 0x290fe 0x1b3fd 0x17d2f39 0x17d2c10 0x17ebda5 0x17ebb12 0x181cb46 0x181bed4 0x181bdab 0x17d1923 0x17d17a8 0x18e71 0x200d 0x1f35)
libc++abi.dylib: terminate called throwing an exception
From my counting the range is within the bounds, I dont get why I am getting this error?
Any help would be appreciated.
Thanks
Your NSMakeRange(start, end) should be NSMakeRange(start, end- start);
I think you have confusion in syntax of NSMakeRange. It is something like this
NSMakeRange(<#NSUInteger loc#>, <#NSUInteger len#>)
<#NSUInteger loc#>: It is the location from where you want to start picking or substring.
<#NSUInteger len#>: This is the length of your output or substring.
Example:
Mytest12test
Now I want to pick'12'
so:
NSString *t=#"Mytest12test";
NSString *x=[t substringWithRange:NSMakeRange(6, 2)] ;
In your code instead of length you are passing index of end character that is your mistake.
I don't know why your are using this approach, but iOS provides a string function which separates a string with respect to another string and returns an array of the components. See the following example:
NSString * str = #"dadsada/2/dsadsa";
NSArray *listItems = [str componentsSeparatedByString:#"/"];
NSString *component = [listItems objectAtIndex:1];
Now your component string should have 2 store in it.
When the compiler runs into this code...
else{
end = i + 1;
}
... in the last iteration of the loop, it sets the end variable to one more then the range of MYSTRING. This is why you are getting that error. To fix it, just do this:
else{
end = i;
}
Hope this helps!
P.S. Saleh's approach is a simpler way of accomplishing what you want
------UPDATE------
You should do it like this actually:
NSMutableArray *occurencesOfSlashes = [[NSMutableArray alloc] init];
char looking = '/';
for(int i=0; i < MYSTRING.length; i++){
if ([MYSTRING characterAtIndex:i] == looking) {
[occurencesOfSlashes addObject:[NSNumber numberWithInt:i]];
}
NSString *finalString = [MYSTRING substringWithRange:NSMakeRange([occurencesOfSlashes objectAtIndex:0],[occurencesOfSlashes objectAtIndex:1])];

CS193p-Adding backspace to a calculator

I recently started following the online course on iPhone development from Stanford University on iTunes U.
I'm trying to do the homework assignments now for the first couple of lectures. I followed through the walkthrough where I built a basic calculator, but now I'm trying the first assignment and I can't seem to work it out. It's a follows:
Implement a “backspace” button for the user to press if they hit the wrong digit button. This is not intended to be “undo,” so if they hit
the wrong operation button, they are out of luck! It’s up to you to
decided how to handle the case where they backspace away the entire
number they are in the middle of entering, but having the display go
completely blank is probably not very user-friendly.
I followed this: Creating backspace on iOS calculator
So the code is
-(IBAction)backspacePressed:(UIButton *)sender {
NSMutableString *string = (NSMutableString*)[display text];
int length = [string length];
NSString *temp = [string substringToIndex:length-1];
[display setText:[NSString stringWithFormat:#"%#",temp]];
}
My question is shouldn't I check whether my last is a digit or operand? If operand, no execution and if digit, remove it...
First of all, there are several unnecessary steps in that code... And to answer your question, yes, you should check for an operand. Here is how I would write that method with a check:
NSString *text = [display text];
int length = [text length];
unichar c = [text characterAtIndex:length];
NSCharacterSet *digits = [NSCharacterSet decimalCharacterSet];
if ([digits characterIsMember:c] || c == '.') {
NSString *temp = [[display text] substringToIndex:length-1];
[display setText:temp];
}
I'm also going through the fall 2011 class on iTunes U.
The walk through gives us an instance variable userIsInTheMiddleOfEnteringANumber so I just checked to see if that is YES.
- (IBAction)backspacePressed {
if (self.userIsInTheMiddleOfEnteringANumber) {
if ([self.display.text length] > 1) {
self.display.text = [self.display.text substringToIndex:[self.display.text length] - 1];
} else {
self.display.text = #"0";
self.userIsInTheMiddleOfEnteringANumber = NO;
}
}
}
I used the approach taken by Joe_Schmoe, which is straightforward. (just remove characters in the dispaly until you reach the end).
If the user continues pressing 'Clear Error', I removed an item from the stack as well.
I have just started on the course myself, this post is quite old now but my solution might help others, food for thought if nothing else:
- (IBAction)deletePressed:(id)sender
{
NSString *displayText = [display text];
int length = [displayText length];
if (length != 1) {
NSString *newDisplayText = [displayText substringToIndex:length-1];
[display setText:[NSString stringWithFormat:#"%#",newDisplayText]];
} else {
userIsInTheMiddleOfEnteringANumber = NO;
NSString *newDisplayText = #"0";
[display setText:[NSString stringWithFormat:#"%#",newDisplayText]];
}
}

List / Scan for available WiFis iPhone

I'm searching for a way to present available WiFis in an iPhone App.
So far my research resulted in the following:
Apps that implement(ed) such a functionality were removed from the AppStore (means you can't deploy the App via AppStore which is fine for me)
Apple hides the functionality that is necessary for a scan in a private framework and you can't find any explanations/comments/examples on "how to use"
http://code.google.com/p/iphone-wireless seems to be most promising. anyway, i can't figure out how to include the delivered sources in my code so that it runs on a device
Even the adaptions that are mentioned htt ://code.google.com/p/iphone-wireless/issues/detail?id=26 didn't get me the desired results. The most progress was ending up with a
dlopen error: dlopen(/System/Library/SystemConfiguration/Aeropuerto.bundle/Aeropuerto, 1): image not found
failed: __Apple80211Associate
message after launching the app on a device (iPhone 3GS; iOS 3.1.3).
Used source code that procudes the error is here:
NSMutableDictionary *networks;
bool scanning;
void *libHandle;
void *airportHandle;
int (*open)(void *);
int (*bind)(void *, NSString *);
int (*close)(void *);
int (*scan)(void *, NSArray **, void *);
networks = [[NSMutableDictionary alloc] init];
// libHandle = dlopen("/System/Library/Frameworks/Preferences.framework/Preferences", RTLD_LAZY);
// libHandle = dlopen("/System/Library/PrivateFrameworks/Apple80211.framework/Preferences", RTLD_LAZY);
libHandle = dlopen("/System/Library/SystemConfiguration/WiFiManager.bundle/WiFiManager", RTLD_LAZY);
open = dlsym(libHandle, "Apple80211Open");
bind = dlsym(libHandle, "Apple80211BindToInterface");
close = dlsym(libHandle, "Apple80211Close");
scan = dlsym(libHandle, "Apple80211Scan");
open(&airportHandle);
bind(airportHandle, #"en0");
NSLog(#"Scanning...");
scanning = true;
NSArray *scan_networks;
NSDictionary *parameters = [[NSDictionary alloc] init];
scan(airportHandle, &scan_networks, parameters);
bool changed;
for (int i = 0; i < [scan_networks count]; i++) {
if([networks objectForKey:[[scan_networks objectAtIndex: i] objectForKey:#"BSSID"]] != nil
&& ![[networks objectForKey:[[scan_networks objectAtIndex: i] objectForKey:#"BSSID"]] isEqualToDictionary:[scan_networks objectAtIndex: i]])
changed = true;
[networks setObject:[scan_networks objectAtIndex: i] forKey:[[scan_networks objectAtIndex: i] objectForKey:#"BSSID"]];
}
if(changed) {
NSLog(#"NetworksUpdated");
}
scanning = false;
NSLog(#"Scan Finished...");
NSLog(#"Found %i networks: %#", [networks count], networks);
Even if trying one of the other commented lines, it doesn't work:
program received EXC_BAD_ACCESS and several
warning: check_safe_call: could not restore current frame
warning: Unable to restore previously selected frame.
What i'm searching are hints how to include iphone-wireless in my project and how to modify the given code?
An alternative would be a tip on how to scan for WiFis in your environment.
Would be nice if someone could help.
path has changed in 3.X and beyond, from :
/System/Library/SystemConfiguration/Aeropuerto.bundle/Aeropuerto
to:
/System/Library/SystemConfiguration/IPConfiguration.bundle/IPConfifuration