I have an app in AppStore (iPhone-only, iOS3.1+ compatible, 2011 Xcode 3 compile) that has been working amazingly fine for three years untouched. Recently however it started "freezing" on iOS8 under certain conditions. That happens in couple of places, both when UIActionSheet is to be shown. Nothing pops on screen, the app does not crash but instead stays irresponsive to any taps; nothing in system console. The only way "out" after that happens is to kill the app manually from the task switcher and start it again.
I believe the reason is the way i show the UIActionSheet, which was as simple as these 3 lines, from a UIViewController method:
UIActionSheet* actSheet = [[UIActionSheet alloc] initWithTitle:#"Could not connect to [...]" delegate:nil cancelButtonTitle:#"OK" destructiveButtonTitle:nil otherButtonTitles:nil];
[actSheet showInView:self.view.window];
[actSheet autorelease];
I think the reason is the use of self.view.window, which is UIWindow (which inherits UIView, naturally) - and that just using self.view should solve the issue (i read here https://stackoverflow.com/a/26171717/226086 that showInView: now only works with UIView with UIViewController attached). Why did i use self.view.window in the first place - probably i read about this issue with cancel button alignment.
However, i am unable to reproduce the problem when compiling my app in Xcode 6 - and Xcode 3 cannot debug iOS8. And my conundrum is how do i exorcise a bug i cannot reproduce to verify.
Do you have insight on the changed behavior of UIActionSheet, what is causing the hanging in iOS8?
PS. Please don't tell me "UIActionSheet is deprecated in iOS8, use UIAlertController instead". That is an incorrect answer: "deprecated" does not mean UIActionSheet does not work in iOS8 no more - it is just discouraged for new code and may be dropped in next versions. But i want to keep compatibility with iOS5+ (my reasoning akin to this) so i rather fix the use of it - which i mention above seems fishy with showInView:self.view.window.
This is a long shot, but there is an issue in iOS8 related to rotation not working when the following line is left in your app delegate didFinishLaunchingWithOptions: method. The line is a hangover from pre iOS8 xcode generation and relates to the window for the application. Only affects iOS8. Previous versions all work fine.
The line is:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
This is nolonger needed and should be commented out. Given you are using self.view.window perhaps there is some side effect with UIActionSheet as well.
As I say, a long shot but seems a coincidence that your having an issue in iOS8 only related to using a window view.
I dont think you should have an issue using UIAlertController, as far as support for previouis versions of iOS are concerned you can try creating instance of UIAlertController using [[UIAlertController alloc] init] if it returns nil(which it will for older versions of iOS) you can use UIAlertSheet you are using currently.
Related
I'm using the VFR PDF viewer library in my app, where I present it thus:
ReaderDocument *document = [ReaderDocument withDocumentFilePath:pdfFile password:nil];
ReaderViewController *vc = [[ReaderViewController alloc] initWithReaderDocument:document];
[self.navigationController pushViewController:vc animated:YES];
If I run on iOS7, everything works fine.
If I run my app on iOS8, the willRotateToInterfaceOrientation method in ReaderViewController never gets called, so when the device is rotated the document doesn't get reformatted correctly.
However, if I run the demo app that comes with the library on iOS8, the willRotateToInterfaceOrientation in ReaderViewController does get called, which leads me to believe the library is ok, and I'm doing something wrong (or neglecting to do something) in my app.
I'm rather puzzled at this behaviour. Why doesn't willRotateToInterfaceOrientation get called in my app on iOS8, but it does under the other variations? How can I try to track this down?
I finally managed to resolve my problem; here is what the issue was in case anyone else has the same problem.
My ReaderViewController was being presented from a class that had implemented viewWillTransitionToSize:withTransitionCoordinator:, so the deprecated methods on child view controllers weren't being called.
Also in that implementation it wasn't calling
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]
and so the viewWillTransitionToSize:withTransitionCoordinator: method of all child view controllers wasn't being called either.
The fix was to add a call to
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]
into the parent VC's viewWillTransitionToSize:withTransitionCoordinator: method, subclass ReaderViewController, then add a viewWillTransitionToSize:withTransitionCoordinator: to my subclass to call the appropriate methods in ReaderViewController.
Simply because willRotateToInterfaceOrientation is no more called in iOS8, it is deprecated.
If the new rotation methods are not implemented, and a project is
compiled with the iOS 8 SDK, the view controllers -will not receive
calls- to the deprecated rotation methods.
A similar question to yours can be found here
Citation of #mluisbrown :
The rotation methods are deprecated in the iOS 8 SDK. This will have
no effect at all on apps built with the iOS 7 SDK, even running in iOS
8 and probably several future versions of iOS.
I struggled a bit with some kind of a similar problem to yours. I tried following Apple recommendation to use viewWillTransitionToSize, which in my case did not solve my problem because this only gets triggered on changes from regular to compact for example an not on rotation.
viewWillTransitionToSize:withTransitionCoordinator: to make
interface-based adjustments.
Which is detailed in apple documentation
Also a video of WWDC 2014 explains this but I can't remember which video it was. Perhaps the one on What's new in Cocoa touch or the one on View Controller Advancements in iOS 8.
EDIT
Note that in my case viewWillTransitionToSize, as explained, was not called because I wasn't changing from regular to compact so there was no size transition, strictly speaking for Apple.
The only solution I fount was to handle this manually in the viewDidLayoutSubviews of the corresponding view controller.
In my case I wanted to keep track of the top cell displayed in a tableview with autolayout. As it wasn't tracked automatically by the system, I had to check that manually and scroll manually to the adequate cell on rotation. That's why I did it that way. It's quite "heavy" but works in my case.
I would also be interested if anyone has an easier solution.
I'm coding a video processing app and was just about to submit it to the app store when ios 8.1 came out. I updated my iPhone as well as XCode and all hell broke loose. In my simple single viewcontroller interface nothing is rotating anymore except for the statusbar, which also doesn't get automatically hidden anymore in landscape mode...
I figured it was because I was using the deprecated willAnimateRotationToInterfaceOrientation: for what little custom rotation actions I had, so I implemented traitCollectionDidChange: and viewWillTransitionToSize: to specs instead. However viewWillTransitionToSize never gets called in my app and traitCollectionDidChange: is only called once, at startup. The device simply isn't telling the app that the device has rotated.
After googling I've also tried using name:UIDeviceOrientationDidChangeNotification. At least my selector does get called for that one but I don't know how to manually handle all rotation.
My didFinishLaunching... and viewDidLoad are very simple. alloc UIWindow, storyboard, set my viewcontroller from there, make it rootviewcontroller, makekeyandvisible. All based on one of Apple's AVFoundation demo apps.
Then in didload I add some subviews and a toolbar etc, nothing out of the ordinary and obviously it did work on 8.0 and 8.0.2 on all kinds of devices as well as the 7.1 simulator etc. Still runs flawlessly on my iPad with 8.0.2... Reason I haven't posted any code is I'm 100% sure everything is correct on that end.
Main weird thing is I can't seem to find anyone with this problem.
No errors in console or elsewhere either.
Does anyone have any idea of what might be causing this? I didn't think a point release would make such massive differences and again, no one else seems to be having this. Could it be an issue/bug in the actual storyboard file?
And, mainly, since I can get rotation notifications through UIDeviceOrientationDidChangeNotification, how do I manually handle all rotation/resizing stuff? I have been looking all over for answers but to no avail and am out of time to spend on this project currently :(
Cheers!
alloc'ing UIWindow will be the problem.
First, Make sure your navigation controller (or whatever you're using) is set as "Initial View Controller" in your storyboard.
Secondly, in your AppDelegate.m file, remove any references to UIWindow and rootViewController that appear in application didFinishLaunchingWithOptions. In my case, removing the following two lines fixed my issues.
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[self.window makeKeyAndVisible];
You also don't need to set the window's rootViewController if using storyboards.
They're simply not needed when using storyboards, but until 8.1 there was never any harm using them. It took my 2 days to figure this out, so hopefully it will help you and others too.
Do we have to work with the UIAlertController in the iOS8 or could we still work with the UIActionSheet?
I don't want massive changes in our code for iOS 8 compatibility, but I'm encountering several issues when working with the UIActionSheet on iPad.
For example I'm getting this exception when using the UIActionSheet:
UIPopoverPresentationController (<_UIAlertControllerActionSheetRegularPresentationController: 0x7c57bf90>) should have a non-nil sourceView or barButtonItem set before the presentation occurs.
I understand that it is preferred to work with the new UIAlertController, but is there any workaround for this in order to continue to work with the UIActionSheet?
Also in places that the UIActionSheet actually shows (with no exception) it contains an arrow + it is not centred like before (iOS7) - I'm using the showInView (also tried to work with showFromRect but got the same results).
From the documentation its clear that UIActionSheet is deprecated. Means that you can still use it but in future in can fail or will be removed completely.
I highly recommend you to update to UIAlertController.
The exception you got on iPad is clear. As the UIAlertController with style actionSheet needs sourceView (the view from the actual controller will be presented) as its no more full screen (as its on iPhone).
I've just downloaded SVProgressHUD and incorporated it into my project as explained in the github documentation page, but even if I wrote out [SVProgressHUD showWithMaskType:SVProgressHUDMaskTypeGradient];, it's not different from the default mask type, and when I tapped the screen while the cursor was revolving I got my app crashed - meaning I wasn't able to disable the user interaction feature since my app crashes before showing all of the table view cells there.
And note that clear or black mask type didn't work, either.
So how can I successfully disable the user interaction? And which file of the AppDelegate.m's applicationDidFinishWithLaunchingOptions: and FirstViewController.'s viewDidLoad: should I write the above code?
I use the latest version of the SVProgressHUD and use Xcode 5.1 and iOS 7.1. I also use ARC. Am I missing something?
[Update]
This was a bug issue and it has been resolved in the current version. Check it out on the Github page for the further info.
This is very late to answer but just in case it can help someone because I was stuck with this issue for a while today. If you are using latest classes from github you won't face any issue but if you are using old classes then Replace below method from SVProgressHUD.m as below
+ (void)showWithStatus:(NSString *)status
{
[self setDefaultMaskType:SVProgressHUDMaskTypeGradient];
[self showProgress:SVProgressHUDUndefinedProgress status:status];
}
I am using SVProgressHUD with swift and iOS 10.2 . Just setting mask type
In AppDelegate
SVProgressHUD.setDefaultMaskType(.black) works.
and every time you write
SVProgressHUD.show()
it will show the mask and userInteraction is managed by it.
You're not missing anything. iOS 7 doesn't seem to respect the mask type, so user interaction is never disabled. I think it's a bug with SVProgressHUD rather than anything else. Bit frustrating really.
It can be done easily by doing some changes in SVProgressHUD class:
just put
[self.window setUserInteractionEnabled:NO]; in the last of showprogress with status and put [self.window setUserInteractionEnabled:YES]; in dismiss method.
Objective C (AppDelegate.m)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//add this line
[SVProgressHUD setDefaultMaskType: SVProgressHUDMaskTypeBlack];
}
I am having a problem when calling the UIImagePickerController to use the camera. Sometimes, but more often than none, the preview screen shows to be black (as the camera itself is covered). After doing some research, it seems that people where not delegating it correctly..however, I believe my set up is correct. A restart of the app is what fixes it.
In my .h file I have included UIImagePickerControllerDelegate and UINavigationControllerDelegate.
Here is the code for the .m file
- (IBAction)camera:(id)sender {
UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
#if TARGET_IPHONE_SIMULATOR
imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
#else
imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
#endif
imagePickerController.editing = YES;
imagePickerController.delegate = self;
[self presentViewController:imagePickerController animated:YES completion:nil];
}
Any ideas as to why this is happening?
Thank you
I just fought this issue for a day and a half, sure enough I was doing something UI related outside the main thread. In my case I was updating a label in the response handling code for an asynchronous web service call.
In an app with several view controllers that have 2000+ lines of code each in them, this kind of thing can be very difficult to track down. This is what finally brought me to my answer, and VERY quickly at that.
https://gist.github.com/steipete/5664345
This guy posted a class you can download and add to your project. Simply add it to your project, you don't need to use it anywhere or try to instantiate anywhere, just add it to your project. He also states that you should run this without ARC. To do that, go to your Build Phases tab, expand Compile Sources, double click on the file and then type -fno-objc-arc
Now, run your project and navigate to where you are experiencing the black image preview screen. If all goes to plan, at some point prior to that your app should crash and dump to console some information about performing a UIKit action outside the main thread. Based on what your app was doing and what was dumped to console, you should be able to very quickly find the line of code causing you troubles. In my case I was able to call my response handler with a
[self performSelectorOnMainThread:#selector(handleResponse:) withObject:data waitUntilDone:true];
and my problem was gone immediately
Also, this issue only began once I updated to iOS 7, I never saw this in iOS 5 or iOS 6.
The guy who posted the file advises that you do not ship your app with this file included in your project and I strongly agree with that.
Happy debugging!
Try this. it solved my problem, make sure that there is a value
(Application name as string) in your info.plist > "Bundle display name".
In my case it was empty and because of that it didn't work.
If "Bundle display name" is not there in the info.plist,then add a row named "Bundle display name" and paste your appname .
Test this in your device. I think you are testing it in simulator and allowsImageEditing property Deprecated in iOS 3.1 so dont use it .
This can happen when there is animation not started on the main thread going on in parallel to kicking off the imagePickerController
If this is what you are running into you will likely see
<Warning>: CoreAnimation: warning, deleted thread with uncommitted CATransaction; set CA_DEBUG_TRANSACTIONS=1 in environment to log backtraces.
On your console log
I ran into it first by kicking off an activity indicator from a different thread (bug in its own right I know). But more insidiously this hit me due to loading a nib file in a background thread (which calls [CATransaction setDisableActions:] ... who knew)
Turning on CA_DEBUG_TRANSACTIONS in your scheme and then running in your simulator while tailing the system log (tail -f /var/log/system.log) is really the best way to find out the specific culprit.
Try this...
dispatch_async(dispatch_get_current_queue(), ^(void){
imagePicker.sourceType =
UIImagePickerControllerSourceTypeCamera;
imagePicker.delegate = self;
[self presentModalViewController:imagePicker animated:YES];
} ) ;
While it could be an issue that depends on many factor, as shown from the successful solutions provided by other members, I think it's worth mentioning the fact that the user might have denied permissions for camera usage (Under Privacy->Camera->Your application) and thus the camera shows, but displays a black preview screen. It just happened to me, and it depended from a bug in the early development stage in which that question was never seen by the user because of overlapping alerts.
When you're creating the UIImagePickerController change the cameraOverlayView to nil. It worked like a charm for me.
self.imagePickerController.cameraOverlayView = nil;
And that should be it.
Please check [UIApplication sharedApplication].keyWindow.frame