App is fails when I try set customInfoViewController to nil - objective-c

CustomInfoViewController property of AVPlayerViewController is nil by default.
https://developer.apple.com/documentation/avkit/avplayerviewcontroller/2868498-custominfoviewcontroller?language=objc
When I set new ViewController as custom all is fine:
UIViewController* vc = [[UIViewController alloc] init];
vc.preferredContentSize = CGSizeMake(1000, 100);
vc.title = #"TEST";
self.playerViewController.customInfoViewController = vc; // playerViewController is AVPlayerViewController
But when I try to set customInfoViewController back to nil (to hide it) - it always fails:
self.playerViewController.customInfoViewController = nil;
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0]'
*** First throw call stack:
(
0 CoreFoundation 0x000000010746ea56 __exceptionPreprocess + 294
1 libobjc.A.dylib 0x0000000106537031 objc_exception_throw + 48
2 CoreFoundation 0x00000001074ae54c _CFThrowFormattedException + 194
3 CoreFoundation 0x000000010737bccd -[__NSPlaceholderArray initWithObjects:count:] + 237
4 CoreFoundation 0x0000000107382694 +[NSArray arrayWithObjects:count:] + 52
5 AVKit 0x000000010723997c -[AVPlayerViewController(AVPlayerViewControllerControls) setCustomInfoViewController:] + 88
Any suggestions how I can hide customInfoViewController?

Settings a property to nil will not hide it!
Depends on how you presented CustomInfoViewController.
If you presented it using present function, you should call dismiss and set it to nil inside the completion block.
if you presented it by simply adding its view to AVPlayerViewController's view, you need to remove it from its superview (using removeFromSuperview()) and only then, set it to nil.

Related

Finding line corresponding to error in XCode debugger

When XCode outputs an error like 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]:etc., how can I find the line of code with that objectAtIndex code?
Create a new Exception breakpoint. It will usually show you where the exception is first thrown. Go to the Breakpoints tab on the left:
Look in the lines below it,
you should have a back-trace of the methods that run by you and by the system.
There, you should find the name of the method in which it occurred in.
I've just took an existing project, and add a similar crash and purpose to illustrate this.
My method-
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.contacts = [NSMutableArray arrayWithArray: [ARContact loadContacts]];
NSLog(#"%#", self.contacts[100]); // Index 100 is outside of the array scope
....
}
The console log of the crash (on the bottom of Xcode)
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 100 beyond bounds for empty array'
*** First throw call stack:
(
0 CoreFoundation 0x0000000101a87495 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x00000001007ec99e objc_exception_throw + 43
2 CoreFoundation 0x0000000101a2d745 -[__NSArrayM objectAtIndex:] + 213
3 PhoneBookApp 0x0000000100001f95 -[ViewController viewWillAppear:] + 261
4 UIKit 0x0000000100b1adb5 -[UIViewController _setViewAppearState:isAnimating:] + 422
5 UIKit 0x0000000100b38c4d -[UINavigationController _startTransition:fromViewController:toViewController:] + 707
Here you could see a reverse order of things as they occurred (meaning 0 is the latest thing that run, 1 is just before it, etc').
If you would look at numbers 3 and 4, You'll see that before the crash, there is a call to NSArray's objectAtIndex: method (line 3),
And this method called from viewWillAppear: (line 4).

Objective-c : addTarget to UIButton not calling

I tried to use addTarget to add an event to a UIButton like this
EGOImageButton* image = [[EGOImageButton alloc] initWithPlaceholderImage:[UIImage imageNamed:#"screen.png"]];
[image setImageURL:[NSURL URLWithString:thumbnail]];
[image setFrame:CGRectMake(x, y, self.cellsize, self.cellsize)];
[image setTag: [self.photoIDs count]-1];
[image addTarget:self action:#selector(buttonTouched:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:image];
[image release];
The function definition is this:
-(void)buttonTouched:(id)sender {
NSLog(#"Thumbnail Clicked");
}
This is the code for EGOImageButton init function
- (id)initWithPlaceholderImage:(UIImage*)anImage {
return [self initWithPlaceholderImage:anImage delegate:nil]; }
- (id)initWithPlaceholderImage:(UIImage*)anImage delegate:(id<EGOImageButtonDelegate>)aDelegate {
if((self = [super initWithFrame:CGRectZero])) {
self.placeholderImage = anImage;
self.delegate = aDelegate;
[self setImage:self.placeholderImage forState:UIControlStateNormal];
}
return self;
}
Error is looking like this:
-[NSCFType buttonTouched:]: unrecognized selector sent to instance 0x6c804a0
2012-06-06 01:36:59.061 Photo Collage for Facebook[2416:16103] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFType buttonTouched:]: unrecognized selector sent to instance 0x6c804a0'
* Call stack at first throw:
(
0 CoreFoundation 0x0046a5a9 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x01402313 objc_exception_throw + 44
2 CoreFoundation 0x0046c0bb -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
3 CoreFoundation 0x003db966 __forwarding + 966
4 CoreFoundation 0x003db522 _CF_forwarding_prep_0 + 50
It's a bit strange it doesn't get called, since it seens to be set up correctly (https://stackoverflow.com/questions/8968446/cant-able-to-add-click-event-in-uibutton as a reference ). My first guess, without actually have access to your code, is that something is above your image and hence the click event is not passed to the UIButton sub-class (EGOImageButton).
Check to make sure the method your selector is refered to contains a sender of type UIButton
so like this -(void)buttonTouched:(UIButton *)sender
action:
#selector(buttonTouched:)
I think you don't need colon : here, remove it and try action: like this:
#selector(buttonTouched)
I think your buttonTouched method needs to have a return type of IBAction instead of void.

NSTimer crashing my application

So I have an application which uses an NSTimer. The problem is that when the NSTimer runs, my application will crash with EXC_BAD_ACCESS. I only just started with objective-c so I don't know how to properly debug it. If I thought call the -(void)logIn{} with [self logIn]; the application will work.
My code:
.h
#interface DJ_WAppDelegate : NSObject {
NSTimer *loginTimer;
}
-(void)logIn;
#end
.m
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[self logIn]; // this works
loginTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:#selector(logIn) userInfo:nil repeats:YES]; // this fails
}
- (void)logIn {
NSLog(#"Logging in...");
// if I comment out these 2 lines it works with the NSTimer!?... (I've would have more code below)
NSURL *loginConn = [NSURL URLWithString:[NSString stringWithFormat:#"some-website.com"]];
NSInteger loginReturn = [[NSString stringWithContentsOfURL:loginConn encoding:NSASCIIStringEncoding error:nil] intValue];
// when "loginReturn" return "OK" the timer (loginTimer) will be stopped with: [loginTimer invalidate];
// more code would be below... (which works!)
}
So the problem is with the NSURL it think.
Thanks for helping.
EDIT 1:
Here's the crash stack:
EException Type: EXC_BAD_ACCESS (SIGBUS)
Exception Codes: KERN_PROTECTION_FAILURE at 0x0000000000000020
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Application Specific Information:
objc_msgSend() selector name: respondsToSelector:
Thread 0 Crashed: Dispatch queue: com.apple.main-thread
0 libobjc.A.dylib 0x9603bed7 objc_msgSend + 23
1 com.apple.CoreFoundation 0x922ed5f2 _CFStringAppendFormatAndArgumentsAux + 3138
2 com.apple.CoreFoundation 0x922ec979 _CFStringCreateWithFormatAndArgumentsAux + 105
3 com.apple.Foundation 0x9656ebfb -[NSPlaceholderString initWithFormat:locale:arguments:] + 163
4 com.apple.Foundation 0x9656eaae +[NSString stringWithFormat:] + 88
5 com.who.DJ-W 0x00001d56 -[DJ_WAppDelegate logIn] + 116 (DJ_WAppDelegate.m:108)
6 com.apple.Foundation 0x965b08d4 __NSFireTimer + 141
7 com.apple.CoreFoundation 0x922ffadb __CFRunLoopRun + 8059
8 com.apple.CoreFoundation 0x922fd464 CFRunLoopRunSpecific + 452
9 com.apple.CoreFoundation 0x922fd291 CFRunLoopRunInMode + 97
10 com.apple.HIToolbox 0x91646e04 RunCurrentEventLoopInMode + 392
11 com.apple.HIToolbox 0x91646bb9 ReceiveNextEventCommon + 354
12 com.apple.HIToolbox 0x91646a3e BlockUntilNextEventMatchingListInMode + 81
13 com.apple.AppKit 0x9265378d _DPSNextEvent + 847
14 com.apple.AppKit 0x92652fce -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 156
15 com.apple.AppKit 0x92615247 -[NSApplication run] + 821
16 com.apple.AppKit 0x9260d2d9 NSApplicationMain + 574
17 com.who.DJ-W 0x00001c92 start + 54
hope this helps... to find the error
EDIT 2:
With the Zombie Mode on I get this: *** -[CFString respondsToSelector:]: message sent to deallocated instance 0x46d550 I hope this helps.
EDIT 3:
To Ball: Here is the original URL (took away the domain here) /DJW/work.php?user=iBlackbirdi&udid=00000000-0000-1000-80005&key=660e5744e&cmd=slocau&type=get
There are several problems here:
djwLog is a class method so you should call it on the class not the instance
like this: [[self class] djwLog:#"foo bar"]
The URLFromString: method needs the string to contain a valid URL as specified by RFC 1808. Something along the lines of [NSURL URLFromString:#"http://example.com/foo"]
stringWithContentsOfURL:url… is a syncornous method. Unless you have this code running in a separate thread you should not use this. Look at NSURLConnection for a class to asynchronously load data from a URL. Using synchronized calls for this is a bad idea. Always.
intValue returns a signed integer. To get a NSInteger use integerValue. Also if you use stringWithContentsOfURL make sure to check if it's result is nil before calling
integerValue otherwise you might get a result of 0 if the URL call failed or did not return data. A real parser for the API you are calling would be a good idea in any case.
You're calling a class method as if it was an instance method:
[self djwLog:#"Logging in..."];
Since there is no instance-method named djwLog the application crashes. You should either call NSLog directly, make it an instance-method - or preferably make a macro for logging:
#ifdef DEBUG
# define DLog(...) NSLog(#"%s %#", __PRETTY_FUNCTION__, [NSString stringWithFormat:__VA_ARGS__])
#else
# define DLog(...) do { } while (0)
#endif
If you instead of NSLog write DLog - it will only be logging when DEBUG-flag has been defined. In addition to this, it will log the origin of the log message - so you can see which class/method the log entry came from.

crash after pushing a child view controller onto a UINavigationController

I'm trying to use the following code to push a new view controller on the stack:
RootViewController *childViewController = [[RootViewController alloc] init];
// initialize childViewController fields
[self.navigationController pushViewController:childViewController animated:YES];
When I do this I get the following crash. Can someone please help me figure out why?
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSMutableArray insertObject:atIndex:]: attempt to insert nil object at 1'
*** Call stack at first throw:
(
0 CoreFoundation 0x00db0be9 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x00f055c2 objc_exception_throw + 47
2 CoreFoundation 0x00daa7f1 -[__NSArrayM insertObject:atIndex:] + 225
3 CoreFoundation 0x00da5c44 -[__NSArrayM addObject:] + 68
4 UIKit 0x003123fd -[UINavigationBar pushNavigationItem:] + 210
5 UIKit 0x00312947 -[UINavigationBar _pushNavigationItem:transition:] + 124
6 UIKit 0x003778f0 -[UINavigationController pushViewController:transition:forceImmediate:] + 1110
7 UIKit 0x003704a0 -[UINavigationController pushViewController:animated:] + 62
...
The problem is that the UINavigationItem is nil for that controller. I had the same exact crash and it was because I was returning a custom navigation item that had not yet been set. I solved it by returning super's navigationItem instead if it was nil:
- (UINavigationItem *) navigationItem
{
if (navItem) {
return navItem;
}
return [super navigationItem];
}

Array Initialization

The following code for initialization of array works ::
NSArray *array = [[NSArray alloc] initWithObjects:#"Toy Story 3",#"Inception",nil];
self.list = [array sortedArrayUsingSelector:#selector(compare:)];
[array release];
[super viewDidLoad];
But the following code doesnt. The iPhone Simulator Terminates as soon as I try to scroll the Table View which i used to view the array. (Only after i scroll onto empty tableViewCells)
NSBundle *bundle = [NSBundle mainBundle];
NSString *plistPath = [bundle pathForResource:#"MovieList" ofType:#"plist"];
NSMutableArray *array = [[NSMutableArray alloc] initWithContentsOfFile:plistPath];
NSLog([array objectAtIndex:1]);
self.list = [array sortedArrayUsingSelector:#selector(compare:)];
[array release];
[super viewDidLoad];
This was an example app from the Book "Beginning iPhone Development" by Dave Mark. In the example , they have initialized the array within the code, while i have tried to initialize it from a external file.
The console Log ::
2010-12-22 20:57:43.772 Nav[2474:40b] WARNING: Using legacy cell layout due to delegate implementation of tableView:accessoryTypeForRowWithIndexPath: in <RootViewController: 0x9908870>. Please remove your implementation of this method and set the cell properties accessoryType and/or editingAccessoryType to move to the new cell layout behavior. This method will no longer be called in a future release.
2010-12-22 20:58:12.480 Nav[2474:40b] WARNING: Using legacy cell layout due to delegate implementation of tableView:accessoryTypeForRowWithIndexPath: in <DisclosureButtonController: 0x9b32ab0>. Please remove your implementation of this method and set the cell properties accessoryType and/or editingAccessoryType to move to the new cell layout behavior. This method will no longer be called in a future release.
2010-12-22 20:59:13.299 Nav[2474:40b] -[UIDeviceRGBColor length]: unrecognized selector sent to instance 0x9b3d900
2010-12-22 20:59:13.301 Nav[2474:40b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIDeviceRGBColor length]: unrecognized selector sent to instance 0x9b3d900'
*** Call stack at first throw:
(
0 CoreFoundation 0x00db2be9 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x00f075c2 objc_exception_throw + 47
2 CoreFoundation 0x00db46fb -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
3 CoreFoundation 0x00d24366 ___forwarding___ + 966
4 CoreFoundation 0x00d23f22 _CF_forwarding_prep_0 + 50
5 UIKit 0x0051a9ca -[UITableViewCellLayoutManager layoutSubviewsOfCell:] + 3424
6 UIKit 0x00482e02 -[UITableViewCell layoutSubviews] + 95
7 QuartzCore 0x01c70451 -[CALayer layoutSublayers] + 181
8 QuartzCore 0x01c7017c CALayerLayoutIfNeeded + 220
9 QuartzCore 0x01c6937c _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 310
10 QuartzCore 0x01c690d0 _ZN2CA11Transaction6commitEv + 292
11 QuartzCore 0x01c997d5 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 99
12 CoreFoundation 0x00d93fbb __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 27
13 CoreFoundation 0x00d290e7 __CFRunLoopDoObservers + 295
14 CoreFoundation 0x00cf1bd7 __CFRunLoopRun + 1575
15 CoreFoundation 0x00cf1240 CFRunLoopRunSpecific + 208
16 CoreFoundation 0x00cf1161 CFRunLoopRunInMode + 97
17 GraphicsServices 0x016e7268 GSEventRunModal + 217
18 GraphicsServices 0x016e732d GSEventRun + 115
19 UIKit 0x002ca42e UIApplicationMain + 1160
20 Nav 0x00002598 main + 102
21 Nav 0x00002529 start + 53
)
terminate called after throwing an instance of 'NSException'
enter code here
It sounds like this is a perfect job for the debugger, doesn't it? Why not set a breakpoint on the first line and make sure nothing is unexpectedly nil or out of bounds as you step through and inspect your variables? Perhaps paying attention to the error that's undoubtedly logged to the console might be helpful, too?
Given you've mentioned neither the line on which it terminates nor any log messages, this is about as specific as anyone can get.
The first argument to NSLog needs to be an NSString. The object you're passing to it appears to be part of the UIColor cluster. I suggest you change to:
NSLog(#"%#", [array objectAtIndex:1]);
So the first argument is definitely a string and it says just to print a description of whichever object is the next argument.