How to add 'cancel' button to camera acquisition code? - objective-c

I have this code which captures a barcode; it works fine, except on an iPad, if you can't/don't hold the iPad steady, it "tries until the cows come home" if you get my drift. I want to add a "cancel" button or figure out some way to cancel the method so I don't have to kill the app and start it again. Here is my code:
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
CGRect highlightViewRect = CGRectZero;
AVMetadataMachineReadableCodeObject *barCodeObject;
NSString *detectionString = nil;
NSArray *barCodeTypes = #[AVMetadataObjectTypeEAN13Code];
for (AVMetadataObject *metadata in metadataObjects) {
for (NSString *type in barCodeTypes) {
if ([metadata.type isEqualToString:type])
{
barCodeObject = (AVMetadataMachineReadableCodeObject *)[_prevLayer transformedMetadataObjectForMetadataObject:(AVMetadataMachineReadableCodeObject *)metadata];
highlightViewRect = barCodeObject.bounds;
detectionString = [(AVMetadataMachineReadableCodeObject *)metadata stringValue];
break;
}
}
if (detectionString != nil) {
_label.text = detectionString;
oISBNField.text = detectionString; // move detectionString to ISBN textbox
[_session stopRunning];
[_prevLayer removeFromSuperlayer];
[_label removeFromSuperview];
break;
}
else
_label.text = #"(none)";
}
}
Can someone please give me some help on this? I would really, really appreciate it! :D

Just create a cancel button and add it to the UIViewController's view.
When the button is pressed, stop the capture session and dismiss the presented view controller.
- (void)cancelButtonPressed:(id)sender {
[self.captureSession stopRunning]; //stop the capture session
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil]; // dismiss the current view controller
}

Related

Objective C Objects Only Being Changed In Method Scope

I am making a chat application, and when the person logs onto the chat successfully, the server replies with the people that are online at that moment. That string (the server sends a string) gets converted to a NSMutableArray, which is then stored into a NSMutableArray called tableData, which is the data source for a NSTableView. When the online people are stored into tableData, the NSLog output shows that tableData is filled. However, when that method is done, and the login view is closed, in the debugger tableData says 0 Objects, and the NSTableView doesn't fill, which it normally does. Here is are my methods (one calls another):
- (void)getPeople:(NSString *)outputMessage
{
NSArray *newTableData = [outputMessage componentsSeparatedByString:#";"];
self.tableData = [NSMutableArray arrayWithArray:newTableData];
//[self.tableData removeObjectAtIndex:0];;
NSLog(#"Data: %#", self.tableData);
[self.people reloadData];
}
- (void)accessGrantedWithOnlineUsers:(NSString *)users
{
NSLog(#"Access Granted");
self.isLoggedIn = YES;
[self.loginButton setTitle:#"Logout"];
[self getPeople:users];
}
Here is my method that opens and closes the login view:
- (IBAction)loginToChat:(id)sender {
NSLog(#"Called");
if (self.loginPopover == nil) {
NSLog(#"Login Popover is nil");
self.loginPopover = [[NSPopover alloc] init];
self.loginPopover.contentViewController = [[LoginViewController alloc] initWithNibName:#"LoginViewController" bundle:nil];
}
if (!self.loginPopover.isShown) {
NSLog(#"Login Popover is opening");
[self.loginButton setTitle:#"Cancel"];
[self.settingsButton setEnabled:NO];
[self.send setEnabled:NO];
[self.message setEnabled:NO];
[self.loginPopover showRelativeToRect:self.loginButton.frame ofView:self.view preferredEdge:NSMinYEdge];
}
else {
NSLog(#"Login Popover is closing");
if (self.isLoggedIn) {
[self.loginButton setTitle:#"Logout"];
}
else {
[self.loginButton setTitle:#"Login"];
}
[self.settingsButton setEnabled:YES];
[self.send setEnabled:YES];
[self.message setEnabled:YES];
[self.loginPopover close];
}
}
Any help would be greatly appreciated because I have a deadline for this project.
Instead of
self.tableData = [NSMutableArray arrayWithArray:newTableData];
can you try
self.tableData = [newTableData copy];
The only thing i can think of is - is the tableData a strong property?
After this
self.tableData = [NSMutableArray arrayWithArray:newTableData];
write this snippet:
[self setTableData:tableData]

UIImagePickerController issue?

This is my code to present the UIImagePickerController:
// Show the media browser with our settings, then the browser will call our delegate if needed
- (BOOL) startMediaBrowserFromViewController: (UIViewController*) controller
usingDelegate: (id <UIImagePickerControllerDelegate,
UINavigationControllerDelegate>) delegate {
if (([UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypeSavedPhotosAlbum] == NO)
|| (delegate == nil)
|| (controller == nil))
return NO;
UIImagePickerController *mediaUI = [[[UIImagePickerController alloc] init] autorelease];
mediaUI.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
// Check for images type
NSArray * availableTypes = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeSavedPhotosAlbum];
BOOL imgsOnlyAvailable = NO;
// Check if we have only images
for (int i = 0; i < [availableTypes count]; i++) {
// Convert the type
CFStringRef type = (CFStringRef) [availableTypes objectAtIndex:i];
if (CFStringCompare ((CFStringRef) type, kUTTypeImage, 0) == kCFCompareEqualTo) {
// We have images
imgsOnlyAvailable = YES;
break;
}
}
// Check if they are available
if (imgsOnlyAvailable == NO)
return NO;
// Displays only saved pictures from the Camera Roll album.
mediaUI.mediaTypes = [NSArray arrayWithObject:(id) kUTTypeImage];
// Hides the controls for moving & scaling pictures, or for
// trimming movies. To instead show the controls, use YES.
mediaUI.allowsEditing = NO;
mediaUI.delegate = delegate;
[controller presentModalViewController: mediaUI animated: YES];
return YES;
}
// Picker delegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSString *mediaType = [info objectForKey: UIImagePickerControllerMediaType];
UIImage *originalImage;
// Handle a still image picked from a photo album
if (CFStringCompare ((CFStringRef) mediaType, kUTTypeImage, 0)
== kCFCompareEqualTo) {
originalImage = (UIImage *) [info objectForKey:
UIImagePickerControllerOriginalImage];
// Set image
self.imgPic.image = originalImage;
// Now set the button to enabled
self.btnToText.enabled = YES;
}
// Hide picker selector
[[picker parentViewController] dismissModalViewControllerAnimated: YES];
[picker release];
}
The problem is whenever I try to click an image in the UIImagePickerController nothing happens (usually it chooses the image then will dismiss the Controller)
Is there any reason why things are going wrong like this?
Thanks!
// Select the image
- (IBAction)btnSelectFileTouchUp:(id)sender {
// Start the media browser
if ([self startMediaBrowserFromViewController:self usingDelegate:self] == NO) {
// Can't open the media browser
UIAlertView * alrt = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Can't open the photo media browser in this device" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alrt show];
[alrt release];
}
}
Check out the documentation for parentViewController in the UIViewController Class Reference. Specifically this little tidbit.
Prior to iOS 5.0, if a view did not have a parent view controller and
was being presented modally, the view controller that was presenting
it would be returned. This is no longer the case. You can get the
presenting view controller using the presentingViewController
property.
In this instance, I expect that parentViewController is nil on iOS 5 and that is why the controller will not dismiss. Try replacing parentViewController with presentingViewController.
Update: You'll have to check for the existence of presentingViewController on UIViewController to provide behavior for iOS versions < 5.0.
UIViewController *dismissingController = nil;
if ([self respondsToSelector:#selector(presentingViewController)])
dismissingController = self.presentingViewController;
else
dismissingController = self.parentViewController;
[dismissingController dismissModalViewControllerAnimated:YES];

ShareKit modal view controller won't go away

I'm using ShareKit 0.2.1 on Xcode 4.2 (iOS SDK 5) to share text on Twitter. It shares fine, but the modal view controller wont go away after successfully sharing on after clicking on the cancel button (see below):
And this is my code:
-(IBAction)shareOnTwitter:(id)sender{
// Item to share
NSString *text = #"Go away, modal view controller!";
[SHKTwitter shareText:text];
}
What am I doing wrong?
It is an iOS 5 issue. It's because ShareKit is using a method on UIViewController called parentViewController and according to the Apple docs you can no longer use this in iOS 5. Instead, you must use presentingViewController.
So to fix it in the ShareKit code, go into SHK.m, find the method with signature (void)hideCurrentViewControllerAnimated:(BOOL)animated, and replace it with:
- (void)hideCurrentViewControllerAnimated:(BOOL)animated
{
if (isDismissingView)
return;
if (currentView != nil)
{
// Dismiss the modal view
if ([currentView parentViewController] != nil)
{
self.isDismissingView = YES;
[[currentView parentViewController] dismissModalViewControllerAnimated:animated];
} else if ([currentView presentingViewController] != nil) {
self.isDismissingView = YES;
[[currentView presentingViewController] dismissModalViewControllerAnimated:animated];
} else
self.currentView = nil;
}
}
This works for me on iOS 5.
if (isDismissingView)
return;
if (currentView != nil)
{
// Dismiss the modal view
if ([currentView parentViewController] != nil)
{
self.isDismissingView = YES;
[[currentView parentViewController] dismissModalViewControllerAnimated:animated];
}
else {
//## ADD BELOW ##
self.isDismissingView = YES;
[currentView dismissModalViewControllerAnimated:animated];
self.currentView = nil;
}
}
else {
[[self getTopViewController].navigationController popViewControllerAnimated:YES];
}
This is the code I use in one of my apps.
It dismisses fine.
NSURL *url = [NSURL URLWithString:#"http://itunes.apple.com/us/app/packager/id459511278?l=nl&ls=1&mt=8"];
NSString *twittertext = [[NSString alloc] initWithFormat: #"Tweet Text"];
SHKItem *item = [SHKItem URL:url twittertext];
// Share the item
[SHKTwitter shareItem:item];
[twittertext release];
I have used the following code in my app (ARC disabled)
NSString *text = #"Go away, modal view controller!";
[SHKTwitter shareText:text];
I can confirm it dismisses fine.
You probably changed some code in SHKTwitterForm.m when attempting to make Sharekit ARC compatible. Which resulted in your bug

UIAlertView showing up only after it's dismissed

I've been trying to figure this out for 2 days now, and before anyone posts another stackoverflow question, I've read them all and none of them cover my problem exactly:
I have a CoreData app that updates dynamically. Now during the update I want an UIAlertView to pop up saying that an update is being downloaded.
So here's the important code:
AppDelegate:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[myUpdater checkForUpdatesInContext:self.managedObjectContext];
}
_
Updater Class:
- (void)checkForUpdatesInContext:(NSManagedObjectContext *)myManagedObjectContext
{
[self loadUpdateTime];
NSLog(#"Update start");
NSDate *now = [NSDate dateWithTimeIntervalSinceNow:[[NSTimeZone localTimeZone] secondsFromGMT]];
if ([now timeIntervalSinceDate:updateTime] < UPDATE_TIME_INTERVAL)
{
return;
}
[self showAlertViewWithTitle:#"Update"];
... //updating process
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
NSLog (#"Update done");
}
- (void) showAlertViewWithTitle:(NSString *)title
{
self.alertView = [[UIAlertView alloc] initWithTitle:title message:#"Daten werden aktualisiert..." delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
... //design the alertView
[self.alertView show];
NSLog (#"AlertView shows");
}
So here is what happens when I run this:
Launch image shows
NSLog "Update starts" fires
NSLog "AlertView shows" fires
Screen dims but no AlertView is shown
Update is running
NSLog "Update done" fires
Launch image goes away and TabBarController shows up
UIAlertView shows up and is dismissed right away and the dimmed screen returns to normal
What I would like to have happen:
Launch image
TabBarController shows up
Screen dims and UIAlertView shows
Update is running
UIAlertView gets dismissed and dimmed screen returns to normal
I know it's something with the UI Thread and the main Thread and stuff.. But I tried every combination it seems but still not the expected result. Please help :)
EDIT:
HighlightsViewController Class:
- (void)viewDidLoad
{
[super viewDidLoad];
self.updater = [[Updater alloc] init];
[updater checkForUpdatesInContext:self.managedObjectContext];
... // other setup stuff nothing worth mentioning
}
Is this the right place to call [super viewDidLoad]? Because it still doesn't work like this, still the update is being done while the Launch Image is showing on the screen. :-(( I'm about to give this one up..
Here you go, in this prototype things work exactly how you want them to.
Header:
#import <UIKit/UIKit.h>
#interface AlertViewProtoViewController : UIViewController
{
}
- (void) showAlertViewWithTitle:(NSString *)title;
- (void) checkForUpdatesInContext;
- (void) update;
- (void)someMethod;
- (void)someOtherMethod;
#end
#import "AlertViewProtoViewController.h"
Class:
#implementation AlertViewProtoViewController
UIAlertView *alertView;
bool updateDone;
UILabel *test;
bool timershizzle;
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor yellowColor];
UILabel *test = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
test.backgroundColor = [UIColor blueColor];
[self.view addSubview:test];
[self performSelector:#selector(checkForUpdatesInContext) withObject:nil afterDelay:0.0];
}
- (void)update
{
//NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; //commented for auto ref counting
NSLog(#"update start");
//your update stuff
NSLog(#"update end");
updateDone = YES;
//[pool release];
}
- (void)checkForUpdatesInContext//:(NSManagedObjectContext *)myManagedObjectContext
{
//[self loadUpdateTime];
NSLog(#"Update start");
NSDate *now = [NSDate dateWithTimeIntervalSinceNow:[[NSTimeZone localTimeZone] secondsFromGMT]];
// if ([now timeIntervalSinceDate:updateTime] < UPDATE_TIME_INTERVAL)
// {
// return;
// }
[self showAlertViewWithTitle:#"Update"];
//[self setManagedObjectContext:myManagedObjectContext];
[self performSelector:#selector(someMethod) withObject:nil afterDelay:0.0];
[self performSelector:#selector(someOtherMethod) withObject:nil afterDelay:0.0];
}
-(void)someOtherMethod
{
while (!updateDone) {
// NSLog(#"waiting...");
}
[alertView dismissWithClickedButtonIndex:0 animated:YES];
NSLog (#"Update done");
self.view.backgroundColor = [UIColor greenColor];
}
-(void)someMethod
{
[self performSelectorInBackground:#selector(update) withObject:nil];
}
- (void) showAlertViewWithTitle:(NSString *)title
{
alertView = [[UIAlertView alloc] initWithTitle:title message:#"Daten werden aktualisiert..." delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
alertView.frame = CGRectMake(100, 100, 200, 200);
alertView.backgroundColor = [UIColor whiteColor];
[self.view addSubview:alertView];
[self.view setNeedsDisplay];
NSLog (#"AlertView shows");
}
#end
You should adjust were needed for your own purposes but it works.
You are starting a background thread and then dismissing the alert immediately. I would suggest that you might use an NSNotification, posted from the background task, and received in whichever controller starts the alert, triggering a method that dismissed the alert.
I find the UIAlertView interface unsuitable for this type of user notice, and prefer to use a semi-transparent overlay view with a UIActivityIndicatorView, plus an informing message for the user.
You are doing a:
- (void)applicationDidBecomeActive:(UIApplication *)application
Isn't it so that the alertview you want to show needs a view to be loaded which isn't active yet at this point? See: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIAlertView_Class/UIAlertView/UIAlertView.html
Similar question? UIAlertView starts to show, screen dims, but it doesn't pop up until it's too late!

Adding a UIImage from the UIImagePickerController to a UIButton

I have a UIButton which the user clicks on to bring up a UIImagePickerController. Once this has processed, it returns an edited UIImage to a delegate handler, which then is supposed to populate the UIButton with the new image.
In practise, however, what happens is if the user selects an image from their library, it works fine. But if they take a picture using the camera and edit it, the image doesn't make it to the UIButton. However, if I put the same image into a UIImageView for test purposes, it shows up.
Moreover, this works fine in the Simulator, but doesn't work on the device. Is it some kind of memory issue? Here's my code:
- (IBAction)takePictureButtonTapped
{
UIActionSheet *popupQuery = [[UIActionSheet alloc]
initWithTitle:nil
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:#"Take a Photo", #"Upload from Library", nil];
popupQuery.actionSheetStyle = UIActionSheetStyleBlackOpaque;
[popupQuery showInView:self.view];
[popupQuery release];
}
- (void)actionSheet:(UIActionSheet *)actionSheet
clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSLog(#"actionSheet:clickedButtonAtIndex:%d", buttonIndex);
if(buttonIndex == 2)
{
// cancel
[imagePickerController release];
}
else
{
imagePickerController = [[[UIImagePickerController alloc] init] autorelease];
imagePickerController.delegate = self;
imagePickerController.allowsEditing = YES;
if (buttonIndex == 0)
{
// Take a photo
// Set up the image picker controller and add it to the view
imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
}
else if (buttonIndex == 1)
{
// Upload from Library
imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary] == NO)
imagePickerController.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
}
[self presentModalViewController:imagePickerController animated:YES];
}
}
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingImage:(UIImage *)img
editingInfo:(NSDictionary *)editInfo
{
NSLog(#"imagePickerController::didFinishPickingImage:%#", img);
itemImage = img;
[itemImage retain];
[imageButton setBackgroundImage:itemImage forState:UIControlStateNormal];
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
}
I've tried setImage, setBackgroundImage, for ALL states, and none of them work. Yet if I put the same image into a UIImageView, it's fine.
Any ideas?
I discovered that the reason it wasn't working properly was because I was using didFinishPickingImage:editingInfo: which is DEPRECATED. I should've been using imagePickerController:didFinishPickingMediaWithInfo: instead. Now it's working perfectly!
For some reason XCode wasn't warning me of the deprecation.