I ran this code here, and it worked perfectly.
However, I’m facing a problem when trying to add it to my project.
After the class YouTubeHelper call showAuthenticationViewController:
– (void)showAuthenticationViewController:(UIViewController *)authView {
[self.navigationController presentViewController:authView animated:NO completion:nil];
}
Inside GTMOAuth2ViewControllerTouch.m I’m getting an exc_bad_access, inside loadView, on [super loadView], as below:
– (void)loadView {
NSString *nibPath = nil;
NSBundle *nibBundle = [self nibBundle];
if (nibBundle == nil) {
nibBundle = [NSBundle mainBundle];
}
NSString *nibName = self.nibName;
if (nibName != nil) {
nibPath = [nibBundle pathForResource:nibName ofType:#”nib”];
}
if (nibPath != nil && [[NSFileManager defaultManager] fileExistsAtPath:nibPath]) {
[super loadView]; <<<< exc_bad_access here!
} else {
// One of the requirements of loadView is that a valid view object is set to
// self.view upon completion. Otherwise, subclasses that attempt to
// access self.view after calling [super loadView] will enter an infinite
// loop due to the fact that UIViewController's -view accessor calls
// loadView when self.view is nil.
self.view = [[[UIView alloc] init] autorelease];
#if DEBUG
NSLog(#"missing %#.nib", nibName);
#endif
}
}
Any idea why this is happening and how to fix it?
Thanks!
You should never call [super loadView]; in your subclass. Remove that line from your implementation.
You can override this method in order to create your views manually. If you choose to do so, assign the root view of your view
hierarchy to the view property. The views you create should be unique
instances and should not be shared with any other view controller
object. Your custom implementation of this method should not call
super.
Reference: UIViewController Class Reference
Thanks Midhun and EridB.
As the libraries are a little bit old, I did my own implementation to upload videos to YouTube.
Here some links that helped on it:
https://developers.google.com/youtube/v3/guides/implementation/videos
https://developers.google.com/youtube/v3/guides/using_resumable_upload_protocol
Specially this one was very useful to try and check request/response:
https://developers.google.com/oauthplayground/?code=4/1c_ILMzPMhgPWpCI6L7M-LeBe5jL-BY1Xa1sS0oWQJ0
I hope it helps others with YouTube API implementation.
Related
Please see attached image for reference. All of the viewControllers have been already removed from the app but Memory Debugger shows its instances as well as all its properties. When i click the Show Only Leaked blocks filter of Memory Debugger, the viewControllers and other instances do not appear in it. Does it mean there are no leaks?
How do I solve the problem. What does it mean?
I do have the PKYStepper block in the CartViewController's cellForRowAtIndexPath (Stepper is a UIControl in my TableViewCell) method as follows :
PKYStepper *qtyStepper = [cell viewWithTag:993];
qtyStepper.tappedCallback = ^(PKYStepper *stepper) {
NSLog(#"Tapped!");
rowSelected = indexPath;
if (((Dish*)((MenuSubSection*)_section.subSections[0]).dishesArray[indexPath.row]).disheOptions.count)
{
UIWindow *window = [UIApplication sharedApplication].keyWindow;
NSBundle* bun = [NSBundle bundleWithIdentifier:#"com.test.test"];
DishItemOption *dishOptions = [[bun loadNibNamed:#"DishItemOption" owner:self options:nil] objectAtIndex:0];
dishOptions.frame = CGRectMake(0, 0, window.frame.size.width, window.frame.size.height);
dishOptions.dish = [[Dish alloc] initWithDishObject:((Dish*)((MenuSubSection*)_section.subSections[0]).dishesArray[indexPath.row])];
dishOptions.delegate = self;
[window addSubview:dishOptions];
}
};
How to make it reference the Weak Self?
It looks like you've likely captured the view controller in a callback block of some sort.
Specifically, PKYStepper seems to have a callback block that is strongly referencing the view controller. Either make sure said reference is weak or make sure the block is properly destroyed when the view controller is torn down.
Found the solution. Updated my callbacks to the following :
__weak typeof(self) weakSelf = self;
qtyStepper.incrementCallback = ^(PKYStepper *stepper, float newValue) {
CartViewController *sSelf = weakSelf;
[sSelf updateTotalCharges]; //Had to use WEAKSELF in the callback!
};
I have an Objective-C app with a programmatically created view for which I'm seeing strange (to me) behavior. Specifically, there's a long pause (up to 30 seconds) between the end of the init method and the beginning of the loadView method. I'm unable to see anything out of the ordinary when setting breakpoints at both those places, so I'm wondering what the system is doing between the init and the loadView, and whether there's anything I can do to optimize the work being done at that point.
Thanks.
Edit: adding some code below (abbreviated for clarity)
The app plays and records video. This view controller reviews a video that's just been recorded but not yet saved / posted.
// called from the view controller that pushes this onto the navigation controller stack
- (id)initWithURL:(NSURL *)fileURL
{
self = [super init];
if (self) {
self.localFileURL = fileURL;
sessionManager = [[sessionManager alloc] initWithURL:fileURL];
}
NSLog(#"return self");
return self;
}
- (void)loadView
{
NSLog(#"begin loadView");
self.playView = [[PlayView alloc] initWithFrame:screenRect];
self.view = self.playView;
}
The pause occurs between the two logging statements.
I've read a bunch of answers on SO already, but I'm a little confused.
I have a tab bar controller subclass I created, and in its viewDidLoad, I'm creating each of the view controllers. However, I have a dependency that I'm passing into the parent, and in turn into the view controller for each tab. I'm passing that dependency in with a custom init method (NS_DESIGNATED_INITIALIZER declared for it in the header). However, it looks like [super init] triggers viewDidLoad directly, so the dependency isn't set properly when the other view controllers are created.
Here's my custom init method:
- (instancetype)initWithSession:(T2Session *)session
{
self = [super init];
if (self) {
_session = session;
}
return self;
}
I'd like session to be set by the time I create the view controllers, but I'm sort of confused about what the best way to do this is. Any advice is much appreciated. Thanks in advance!
I've come across this situation before.
You probably sat there (like me) wishing viewDidLoad didn't get called so soon.
Anyway, this is what I settled on:
- (instancetype)initWithSession:(T2Session *)session {
if (self = [super init]) {
self.session = session;
}
return self;
}
- (void)setSession:(T2Session *)session {
_session = session;
... call the setup methods here, instead of viewDidLoad
}
At first I thought this breaks the golden rule of not calling self.xxxx from within an initializer.
However, I think that rule is only really relevant when calling methods on IBOutlets that may not have been wired up yet.
In this case, T2Session *session isn't a nib outlet.
Alternatively, if you prefer not to break that rule you could always remove the custom initializer .. and revert to using regular property-injection rather than constructor-injection. e.g.
T2Session *session = .....
MYTabBarController *tabBarController = [[MYTabBarController alloc] init];
[tabBarController setSession:session];
These are just my thoughts, hope it helps.
I am trying to use the iOS zxing Widget for QR Code Scanning. I have a ViewController which is pushed as an Item in my UINavigationController or presented Modally from another ViewController. This ViewController has a SegmentedControl for 3 different views. Two of those Views are UIWebViews which load simple Websites, nothing special about them.
The selection looks something like this:
- (IBAction)segmentedControlValueChanged:(id)sender {
NSString *urlString;
ZXingWidgetController *widController;
QRCodeReader* qrcodeReader;
NSSet *readers;
switch (segmentedControl.selectedSegmentIndex) {
case 0:
[self.view bringSubviewToFront:self.productSearchWebView];
urlString = [[SACommunicationService sharedCommunicationService] getURLforKey:kURLTypeProductSearch];
[self.productSearchWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]]];
break;
case 1:
[self.view bringSubviewToFront:self.marketSearchWebView];
urlString = [[SACommunicationService sharedCommunicationService] getURLforKey:kURLTypeMarketSearch];
[self.marketSearchWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]]];
break;
case 2:
widController = [[ZXingWidgetController alloc] initWithDelegate:self showCancel:YES OneDMode:NO];
qrcodeReader = [[QRCodeReader alloc] init];
readers = [[NSSet alloc] initWithObjects:qrcodeReader,nil];
widController.readers = readers;
[self.QRCodeScannerView addSubview:widController.view];
[self.view bringSubviewToFront:self.QRCodeScannerView];
break;
default:
break;
}
}
I tried to debug and go step by step and find out where the problem comes from:
Decoder (which is part of the underlying ZXing logic) tries to call "failedToDecodeImage:" from its delegate (which should be the ZXingWidgetController class) and crashes (EXC_BAD_ACCESS)
While stepping through I found out that the "cancelled" Method of the ZXingWidgetController gets called. Now I don't really know why this method gets called. The Widget shouldn't stop right after initializing and starting the decoder.
So the answer is a very simple one.
I was using iOS 5.0 and ARC. The ZXing ViewController is instantiated locally inside the method. Since the ViewController itself does not get viewed ARC sets a release at the end of the method and the ViewController gets freed. Since the ViewController is released, the view which was retained by the ViewController will be released as well. Cancelled is called because the Main ViewController does not exist anymore and calling some method on a nil pointer results in a BAD_ACCESS.
The Solution here was to set the ZXingViewController as a global strong property. This kept the object from being released right at the end of that method and thus the view which was added as a subview to another ViewControllers view was held in memory as long as the ViewController was alive.
You're not supposed to add controller views as subviews of another view. You're suposed to present controllers using the various UIViewController mechanisms.
By doing what you're doing, you're violating UIViewController contracts. The widget isn't getting things like viewWillAppear, viewDidAppear, etc.
If you want to use ZXing at the UIView/CALayer level instead of the UIViewController level, look at the classes in the ZXing objc directory.
Try this... also in the .h file make this ZXingWidgetController *widController;
And also to the viewScanner set clipToBounds to true.
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self performSelector:#selector(openScanner) withObject:nil afterDelay:0.5];
}
-(void)openScanner
{
self.widController = [[ZXingWidgetController alloc] initMiniWithDelegate:self showCancel:NO OneDMode:YES];
NSMutableSet *readers = [[NSMutableSet alloc ] init];
MultiFormatReader* reader = [[MultiFormatReader alloc] init];
[readers addObject:reader];
self.widController.readers = readers;
[viewScanner addSubview:self.widController.view];
}
Very interesting problem when using loadView in UIViewController.
Usually we used like this way
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
NSLog(#"loadview");
[super loadView];
}
If remove
[super loadView];
We will get dead loop with this
- (void)loadView {
NSLog(#"loadview");
}
Why ?
Only one way to make infinite loop in this case - is getting view property until its not set. If you write next (for example):
- (void)loadView {
self.view = [[UIView alloc] initWithFrame:self.view.bounds];
}
You'll got infinite loop, but
- (void)loadView {
self.view = [[UIView alloc] initWithFrame:CGRectZero];
}
works OK.
So you can't to access view property until you didn't set it.
Since you are just INHERITING what's being implemented in super class(UIViewController), if you don't call super methods, then implementation that needs to be done is NOT done.
Almost all super methods do something critical and the local class inheriting super class implementations must either override them all together (unless you know everything about what super does by referring to the documentation, it's never a good idea), or just ADD local class implementation to the inherited super class implementations.
In conclusion, whenever you inherit a class, which is in most cases of software development, you should let the super class do its implementations unless it's safe to override them.
If I am correct, it seems like super loadView implements something very critical to avoid the loop.
ADDITIONAL NOTE:
However, based on the documentation, you should not call super method: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html
Probably, the reason for infinite loop is caused by not implementing view property appropriately.
If you override loadView, you are expected to provide a root view for the controller's view hierarchy. If you don't provide it loadView would get called every time the view is referenced, possibly leading to an infinite loop. From the docs:
If you specify the views manually, you must implement the loadView method and use it to assign a root view object to the view property.
Implementations that would cause an infinite loop:
- (void)loadView {
NSLog(#"loadview");
}
...self.view is nil after loadView
- (void)loadView {
self.view; // Or anything that references self.view
}
...referencing self.view causes loadView to be invoked, hence an infinite loop.
Correct:
- (void)loadView {
self.view = [[UIView alloc] init];
if (self.view == nil) {
[super loadView]; // Try to load from NIB and fail properly, also avoiding inf. loop.
}
}