I have simple singleton class that takes care of creating and presenting UIImagePickerController. It worked just fine until few hours ago. All I did was moving the code from ViewController to separate singleton class (relevant code at the end of post). When I tried to undo all changes to get back to previous state, the problem persisted.
Whenever I present camera, I get warning (not sure if it is related or not)
"Snapshotting a view that has not been rendered results in an empty snapshot. Ensure your view has been rendered at least once before snapshotting or snapshot after screen updates."
Then, when I hit shutter button, nothing happens, no sound, no focus, no photo taken, no callback back to my app.
When I hit cancel, I get the callback and dismiss the controller without problems.
Now when I open camera again, the screen practically freezes, I get the controls and everything, but the screen doesn't update (actually it does, but only once or twice a minute)
#interface AddPhotoManager()
#property (nonatomic, weak) UIViewController *controller;
#property (nonatomic, strong) UIImagePickerController *imagePickerController;
#end
#implementation AddPhotoManager
+ (instancetype)sharedInstance
{
static dispatch_once_t once;
static id sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (void)addNewPhotoFromController:(UIViewController*)controller
{
self.controller = controller;
UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:#"Camera", #"Photo library", nil];
[sheet showInView:self.controller.view];
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(buttonIndex == 0 || buttonIndex == 1) {
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
// Will get here on both iOS 7 & 8 even though camera permissions weren't required
// until iOS 8. So for iOS 7 permission will always be granted.
if (granted) {
// Permission has been granted. Use dispatch_async for any UI updating
// code because this block may be executed in a thread.
dispatch_async(dispatch_get_main_queue(), ^{
[self presentPickerController:buttonIndex == 0];
});
} else {
// Permission has been denied.
}
}];
}
}
- (void)presentPickerController:(bool)camera
{
self.imagePickerController = [[UIImagePickerController alloc] init];
self.imagePickerController.sourceType = camera ? UIImagePickerControllerSourceTypeCamera : UIImagePickerControllerSourceTypeSavedPhotosAlbum;
self.imagePickerController.delegate = self;
[self.controller presentViewController:self.imagePickerController animated:false completion:nil];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
[picker dismissViewControllerAnimated:true completion:nil];
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
UIImageWriteToSavedPhotosAlbum(image, self, nil, nil);
// TODO: upload the image
self.imagePickerController = nil;
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[picker dismissViewControllerAnimated:true completion:nil];
self.imagePickerController = nil;
}
The singleton is used simply by calling
[[AddPhotoManager sharedInstance] addNewPhotoFromController:self];
from any view controller
EDIT:
storing imagePickerController in strong property doesn't seem to be necessary, but I wasn't sure so I tried it. However, results are same in both cases.
EDIT 2:
I tried exact same code in new test app and everything worked without problems, so it must be some interference with some other parts of the app? Any ideas what it could be? I tried deleting the app to reset permissions, even changed bundle Id, but nothing helped
Related
I'm meeting another strange problem....
I allow users to take photo. To do that, I'm using UIImagePickerController.
With iPhone, it's working, but with iPad (iOS 8, I don't know for others versions), I have a black screen preview.
This is my code :
- (BOOL) startCameraControllerFromViewController: (UIViewController*) controller usingDelegate: (id <UIImagePickerControllerDelegate, UINavigationControllerDelegate>) delegate {
if (([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera] == NO) || (delegate == nil) || (controller == nil))
return NO;
UIImagePickerController *cameraUI = [[UIImagePickerController alloc] init];
cameraUI.sourceType = UIImagePickerControllerSourceTypeCamera;
cameraUI.allowsEditing = NO;
cameraUI.delegate = delegate;
[self presentViewController:cameraUI animated:YES completion:NULL];
return YES;
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSLog(#"photo taken");
}
So when the user click on the button, I've the view to take the photo which appears. But the screen is black, and when I click on the button to take the photo, there is nothing.... and didFinishPickingMediaWithInfo isn't called.
(I see more topics, but I don't found any solution for this problem.)
Thanks,
Make sure you run UIKit operations on main thread. Check also if you app has permissions to use camera [in device settings].
This can also be an issue.(If it helps someone.)
Try this its 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 .
I've got two labels in a custom UITableViewCell. Their purpose is to indicate the status of a timing operation on the object represented by the cell.
One label displays a countup timer. The other simply blinks "Timer Sleeping." Their visibility is mutually exclusive (if one is visible, the other is not, and vice versa) according to a switch statement to determine which label is currently visible. Each is driven by a dedicated NSTimer.
Everything works fine--until I do a modal segue to another View Controller (for the purpose of adding another entity or other task) and then return to the original VC via Cancel or Savethrough delegation. Then, regardless of which label had been visible (and updating via its timer) prior to the segue, no label is to be seen. The cell appears blank.
The weird thing is that when I segue to yet another VC via a push segue, then return via the "Home" button, the labels appear, blinking or counting up, just as though nothing had happened. The only obvious difference I can see between the two return methods is that the modal is handled via delegation whereas the push is unwound through a nav controller.
Any ideas? I can supply any relevant code, but didn't know where to start and didn't want to paste all of it.
Thanks!
EDIT for clarification in response to question below:
I'm returning via delegation. Here's the code in the modal:
- (IBAction)saveButton:(UIBarButtonItem *)sender
{
if (self.activityField.text.length > 0)
{
if (self.categoryLabel.text.length < 1)
{
// self.thisActivity.category = #"Uncategorized";
// self.thisActivity.name =self.activityField.text;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"No category selected"
message:#"Please select a category or Cancel"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
else
{
self.thisCategory.name = self.categoryLabel.text;
self.thisActivity.name = self.activityField.text;
self.thisActivity.category = self.thisCategory.name;
NSLog(#"Category name is %#", self.thisCategory.name);
NSLog(#"Activity name is %#", self.thisActivity.name);
[self.delegate addActivityViewControllerDidSave];
}
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"No activity entered"
message:#"Please enter a new activity or Cancel"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
}
- (IBAction)cancelButton:(UIBarButtonItem *)sender
{
[self.delegate addActivityViewControllerDidCancel:self.thisActivity];
NSLog(#"delegate is %#",self.delegate);
}
And here's the delegate method implementation code from the original VC:
#pragma mark - AddViewControllerDelegate stuff
-(void) addActivityViewControllerDidSave
{
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];
[localContext MR_saveToPersistentStoreAndWait];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
[self refreshData];
}
-(void) addActivityViewControllerDidCancel:(WMDGActivity *) activityToDelete
{
[activityToDelete MR_deleteEntity];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
[self refreshData];
}
2nd edit:
Here's the refreshData code:
-(void) refreshData
{
actFRC = [WMDGActivity MR_fetchAllSortedBy:#"category,name"
ascending:YES withPredicate:nil
groupBy:#"category"
delegate:nil];
[self.myTableView reloadData];
}
I've tried calling this method in viewDidLoad, and NOT calling it there. Same results.
UPDATE, 3/26/2014:
OK, I've discovered that if I remove the call to refreshData from my addActivityViewControllerDidCancel method, the labels work fine. They likewise work fine if I remove the same line from addActivityViewControllerDidSave. Unfortunately, this prevents newly added items from appearing in the HomeViewController table view until the app is relaunched.
Here is my current code for the cancel and save methods:
-(void) addActivityViewControllerDidSave
{
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];
[localContext MR_saveToPersistentStoreAndWait];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
[self refreshData];
}
-(void) addActivityViewControllerDidCancel:(WMDGActivity *) activityToDelete
{
[activityToDelete MR_deleteEntity];
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];
[localContext MR_saveToPersistentStoreAndWait];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
// [self refreshData];
}
I view this as a temporary, or interim, fix. Sure would be grateful for a real cure.
Thanks!
When i try to load camera from my code, camera preview is black. If I wait for 10-20 seconds it will show real camera preview. I found several questions and some of them suggest that running some other code in background should be the reason for this. However I don't have any code running in background.
How should I fix this?
This is my code where I run camera
UIImagePickerController *photoPicker = [[UIImagePickerController alloc] init];
photoPicker.delegate = self;
photoPicker.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentViewController:photoPicker animated:YES completion:NULL];
About 5 months ago my team discovered a memory leak with UIImageViewController in iOS7. Each instantiation slowed down the app exponentially (i.e. first alloc-init had a 1 second delay, second had a 2 second delay, third had a 5 second delay). Eventually, we were having 30-60 delays (similar to what you're experiencing).
We resolved the issue by subclassing UIImagePickerController and making it a Singleton. That way it was only ever initialized once. Now our delay is minimal and we avoid the leak. If subclassing isn't an option, try a class property in your viewController and just lazy load it like so.
-(UIImagePickerController *)imagePicker{
if(!_imagePicker){
_imagePicker = [[UIImagePickerController alloc]init];
_imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
}
return _imagePicker;
}
Then you can just call it later like:
[self presentViewController:self.imagePicker animated:YES completion:nil];
Had this myself - it happens if something is running on the main dispatch thread - are you resizing images by any chance?
It puts the preview onto the main thread and if something is using it, you get a black screen. It's a bug and the workaround is to either take over the main thread or to disable the photo picker until the queue is free
This Should work for you:
- (void)cameraViewPickerController:(UIImagePickerController *)picker
{
[self startCameraControllerFromViewController: picker
usingDelegate: self];
}
- (BOOL) startCameraControllerFromViewController: (UIViewController*) controller
usingDelegate: (id <UIImagePickerControllerDelegate,
UINavigationControllerDelegate>) delegate {
if (([UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypeCamera] == NO)
|| (delegate == nil)
|| (controller == nil))
return NO;
UIImagePickerController *cameraUI = [[UIImagePickerController alloc] init];
cameraUI.sourceType = UIImagePickerControllerSourceTypeCamera;
// Displays a control that allows the user to choose movie capture
cameraUI.mediaTypes = [[NSArray alloc] initWithObjects: (NSString *) kUTTypeImage, (NSString *) kUTTypeMovie,nil];
// Hides the controls for moving & scaling pictures, or for
// trimming movies. To instead show the controls, use YES.
cameraUI.allowsEditing = NO;
cameraUI.delegate = delegate;
[controller presentViewController:cameraUI animated:YES completion:nil];
return YES;
}
I´m trying to integrate ShareKit in my ios game.
Everything is working fine and the actionsheet is shown and I can interact with it but I´m not able to return the focus to my app when the sharekit action has finished (by closing the actionsheet or finishing any action).
I have tried in several ways but any has worked for me. What´s happening?
I´m not an expert programmer so I expect I´m missing something.
I´m
This is my .h
#import <UIKit/UIKit.h>
#import "SHK.h"
#import "SHKConfiguration.h"
#interface SocialWrapper: UIViewController{
}
- (id) init;
- (void) open;
- (void) dealloc;
#end
and .m
#import "SocializeWrapper.h"
#implementation SocialWrapper
- (id) init {
self=[super init];
DefaultSHKConfigurator *configurator = [[DefaultSHKConfigurator alloc] init];
[SHKConfiguration sharedInstanceWithConfigurator:configurator];
[SHK flushOfflineQueue];
return self;
}
- (void) open
{
NSString *someText = #"Hello Earth!";
SHKItem *item = [SHKItem text:someText];
// Get the ShareKit action sheet
SHKActionSheet *actionSheet = [SHKActionSheet actionSheetForItem:item];
UIWindow *window = [UIApplication sharedApplication].keyWindow;
[window addSubview:self.view];
[SHK setRootViewController:self];
[actionSheet showInView:self.view];
}
- (void) dealloc {
NSLog(#"SHK dealloc");
[self release];
[super dealloc];
}
#end
I´m calling it by using this wrapper
#import "SocializeWrapper.h"
SocialWrapper *socialize;
void SHKinit(void) {
NSLog(#"SHK Init");
socialize = [[SocialWrapper alloc] init];
}
void SHKopenWeb(void){
NSLog(#"SHK Open actionsheet");
[socialize open];
}
I´m working with ios 5, xcode 4.3.2 and the last sharekit version from the git.
I think I have to dissmiss my SocialWrapper once the actionsheet is closed but I don´t know how to capture that event, or even if this is correct. I´m stucked.
any help will be greatly appreciated.
UPDATE
As comment adviced, now the controller is on a category, using the actionsheet delegate, the focus can be regained when clicking the cancel´s actionsheet button. The problem still persists when an action is finished or cancelled. Don´t know how to capture that event.
This is my category code:
#import "SocialWrapper.h"
#implementation UIViewController (SocialController)
-(void) loadconfig
{
DefaultSHKConfigurator *configurator = [[DefaultSHKConfigurator alloc] init];
[SHKConfiguration sharedInstanceWithConfigurator:configurator];
[SHK flushOfflineQueue];
}
- (void) open
{
NSLog(#"Opening social button");
NSString *someText = #"Monkey Armada rules!";
SHKItem *item = [SHKItem text:someText];
// Get the ShareKit action sheet
SHKActionSheet *actionSheet = [SHKActionSheet actionSheetForItem:item];
UIWindow *window = [UIApplication sharedApplication].keyWindow;
[window addSubview:self.view];
[actionSheet setDelegate:self];
[SHK setRootViewController:self];
[actionSheet showInView:self.view];
}
- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex
{
NSLog(#"SHK actionsheet dissmiss with button %d", buttonIndex);
if(buttonIndex == 4)
{
NSLog(#"SHK close actionsheet");
[self dismissViewControllerAnimated:YES completion:nil];
[self.view removeFromSuperview];
}
}
#end
Well since SHKActionSheet is a subclass of UIActionSheet you can set the delegate of that class to self to know when the dismissal happens.
Also, [self release]; in dealloc is complete misunderstanding of what release does, if you're in dealloc then releasing self won't do anything !
Learn the memory management rules.
I should also warn you that [window addSubview:self.view] is deprecated, you should not do that at all. In fact, I don't see a reason to wrap share kit stuff each view controller should be able to write that code easily. At worse you could put that code in a category on UIViewController if you don't want to rewrite the code every time.
iam trying import an image from photos library but when i press the import button program crashes and received SGIBART !! but my code works fine on iPhone why ?
here is my code :
.h :
#interface CameraViewController : UIViewController <UIImagePickerControllerDelegate ,UINavigationControllerDelegate> {
UIImagePickerController *ipc;
UIImageView * image1;
#property (.......................;
}
.m :
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
image1.image = [[info objectForKey:UIImagePickerControllerOriginalImage]retain];
[[picker parentViewController]dismissModalViewControllerAnimated:YES];
[picker release];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
[[picker parentViewController]dismissModalViewControllerAnimated:YES];
[picker release];
}
-(IBAction) importImage1 {
ipc = [[UIImagePickerController alloc]init];
ipc.delegate = self;
ipc.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentModalViewController:ipc animated:YES];
}
You're crashing because you're releasing picker, but you didn't retain it. You should remove the calls to [picker release].
You should switch to using accessors for all of your ivars. Accessors and dealloc are generally the only places you should retain or release your ivars. picker is not your ivar and you didn't create it, so you shouldn't be releasing it at all.
You should spend some time with the Memory Management Programming Guide. You can get the short version at Three Magic Words.
On the iPad iOS 3.2 a UIImagePickerController must be presented in a popover, not as a modal view.
check this out :
http://www.cocos2d-iphone.org/forum/topic/6108