dismissViewControllerAnimated doesn't dismiss using ZbarSDK qr code reader - objective-c

I'm using the zbarSDK QR code reader http://zbar.sourceforge.net/iphone/sdkdoc/
The SDK is very great but i encountered a little problem. I need the user to visualize a view before to start scanning (containing information about how to scan), than him press a button which made the scan start (showing the camera) and when the qr code has been scanned to Segue to another View showing something linked to the specific qr code.
I've done this, but it goes all well when i frame the qr code after starting the scan, but not if when i start the scan the qr code is already framed in the videocamera view.
When i start scan i do this
-(IBAction)StartScan:(id) sender
{
ZBarReaderViewController *reader = [ZBarReaderViewController new];
reader.readerDelegate = self;
reader.readerView.torchMode = 0;
ZBarImageScanner *scanner = reader.scanner;
// present and release the controller
[self presentModalViewController: reader
animated: YES];
[reader release];
}
using
[self presentModalViewController: reader
animated: YES];
to show the videocamera and scan the qr code.
and then when the qr code has been scanned i do this:
- (void) imagePickerController: (UIImagePickerController*) reader didFinishPickingMediaWithInfo: (NSDictionary*) info
{
id<NSFastEnumeration> results = [info objectForKey: ZBarReaderControllerResults];
ZBarSymbol *symbol = nil;
for(symbol in results)
hiddenData=[NSString stringWithString:symbol.data];
[reader dismissViewControllerAnimated:YES completion:^{ NSLog(#"Test"); }];
[self performSegueWithIdentifier:#"aDettaglioOpera" sender:self];
}
dismissing the camera view with
[reader dismissViewControllerAnimated:YES completion:^{ NSLog(#"Test"); }];
and presenting the view linked to the following segue.
Now all goes well if a point the camera to a point where there is not the qrcode and then point it to the qrcocde, instead if when i start scan i have already a qr code in the frame of the camera the imagePickerController get executed (i checked) but the dismissViewControllerAnimated:YES doesn't dismiss anything and doesn't execute the block after "completion" (which is instead correctly executed and nslogging "test")
What's the problem? The presentModalViewController has not the time it needs to allow the dismissViewControllerAnimated to function? And if the problem is this how can i avoid it?

I had the same problem and found a work around for this.
Set scanCrop property in reader as below before presentViewController and set it back back to default (0, 0, 1, 1) after 1 second. It works!!!
reader.scanCrop = CGRectMake(0, 0, 0.5, 0.5);
[self performSelector:#selector(changeScanCrop) withObject:nil afterDelay:1.0];
-(void)changeScanCrop {
reader.scanCrop = CGRectMake(0, 0, 1, 1);
}

Related

XCUIElement not found using app.images when running XCUITest

I have a a XCUITest that fails to find a specific image, yet it is perfectly visible on the screen.(emulators and physical devices)
How can I workaround or make the the UIImage accessible to the tests?
All I want to validate is whether the element is visible and touchable on the screen.
The UIImage is added as a subview to a UITableView - it is placed at the bottom of the TableView.
- (void)viewDidLoad {
[super viewDidLoad];
// portions of code left out here
_aView = [[UIImageView alloc] initWithFrame:CGRectZero];
[[self aView] setContentMode:UIViewContentModeScaleAspectFit];
[[self aView] setImage:[UIImage imageNamed:IMG_NAME]] ;
[[self tableView] addSubview:[self aView]];
The UIImageView is later layed out:
- (void) viewWillLayoutSubviews {
// portions of code left out here
[[self aView] setFrame:CGRectMake(0, MAX([self tableView].contentSize.height - 41 ,[self tableView].bounds.size.height - 41) , 180, 30)];
[[self aView] setCenter:CGPointMake([self tableView].center.x, [self aView].center.y)];
Then when running the test:
let app = XCUIApplication()
//this works
let tapString = localizedString("skip")
let skipButton = app.buttons[tapString].firstMatch
if (skipButton.exists) {
skipButton.tap()
}
let theImage = app.images["img.png"]
let doesExist = theImage.exists //<< it never exists
Also doing a debug and printing all the images
does not show the image. I set a breakpoint at the line with doesExists
and in the debug window I run the command:
po app.images
Many images are found but not the particular image under test.
Is there perhaps an alternative to solve this problem?

Draw minimal with drawRect and setNeedsDisplayInRect

He, I just realized that [self setNeedsDisplayInRect:(dRect)] draws everything (and not only the necessary) and then updates the screen in "dRect". So I started to edit the drawRect-method like this:
- (void)drawRect:(NSRect)dirtyRect{
if (gUs==1){
imagePos = NSMakePoint(0, 0);
[_bz_BG dissolveToPoint:imagePos fraction:1.0];
[self drawBPM];
[self writeSeq1steps];
[self writeSeq2steps];
[self drawSeq1Patterns];
[self drawSeq2Patterns];
[self drawSeq1];
[self drawSeq2];
[self drawSampleNameSeq1];
[self drawSampleNameSeq2];
[self drawBattCharge];
[self drawCPUload];}
if (gUs==2){
[self drawCPUload];}
if (gUs==3){
[self drawBattCharge];}
if (gUs==4){
[self drawBPM];}
}
and then let the methods that need display alter "gUs". That works fine and since I have a lot of controls reduces the cpu work extremely.
But then I saw that under heavy load or often display updates sometimes another method alters "gUs" before the needDisplay from the previous call is processed, leading to wrong drawings.
How can I avoid this?

Program crashes when segueing back and dispatch queue has animation method

Ok so i have a uitableview and when an item is selected it segues to a new view controller to show an image (inside of a uiscrollview). The image begins downloading in a dispatch_queue from prepareforsegue. To be clear I am doing all UI updates in the main queue. The problem is that if i hit the back button quick enough then my program crashes with an exc_bad_address. I think the problem has to deal with zoomToRect animated:YES because when i set animated to NO i cant get it to crash. Plus the call stack below deals with animation. What is the best way to go about fixing this and is there a better way to get what i need done?
Also when debugging the problem print 'Block completed' and then crashes shortly after.
stack trace
Here is the method called. It is called in a setter of the destination controller in prepareForSegue.
-(void) updateDisplay {
dispatch_queue_t queue = dispatch_queue_create("Load Flickr Photo", NULL);
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:spinner];
[spinner startAnimating];
dispatch_async(queue, ^{
UIImage *image = [FlickrFetcher imageForPhoto:self.currentPhoto format:FlickrPhotoFormatLarge];
dispatch_async(dispatch_get_main_queue(), ^{
self.navigationItem.rightBarButtonItem = nil;
self.imageView.image = image;
self.title = [FlickrFetcher titleForPhoto:self.currentPhoto];
CGAffineTransform transform = CGAffineTransformMakeScale(1.0, 1.0);
self.imageView.transform = transform;
self.imageView.frame = CGRectMake(0, 0, self.imageView.image.size.width, self.imageView.image.size.height);
self.scrollView.maximumZoomScale = 4.0;
self.scrollView.minimumZoomScale = .2;
self.scrollView.zoomScale = 1;
self.scrollView.contentSize = self.imageView.bounds.size;
//i think problem is here
[self.scrollView zoomToRect:self.imageView.frame animated:YES];
NSLog(#"Block completed");
});
});
}
I think a potential problem could be that while your block retains your self the view controller while its active in queue...
If you send -zoomToRect:animated:NO, the block will still be active and blocking on the call which ensures that all the objects are still valid in memory.
If you send -zoomToRect:animated:YES, the block will exit potentially generating a race condition where your view controller would be released since storyboards will also release your view controller when you go back in a segue leaving it with an effective retain count of zero.

How to update UIWebView during an animation?

I've got a view that contains a UIWebView (With text images, etc) that is attached to a GestureRecognizer. Once the webView is "tapped," it flips over and displays updated text, images, etc. on this web view. I have the action associated with this recognizer as follows:
- (IBAction)flipWebViewGestureRecognizer:(id)sender
{
// isFrontView is boolean to determine if card is front or back
if(self.isFrontOfView)
{
self.isFrontOfView = NO;
[UIView transitionWithView: self.imageView
duration: 1.0
options: UIViewAnimationOptionTransitionFlipFromTop
animations: ^{ [self loadBack]; }
completion: nil];
}
else
{
self.isFrontOfView = YES;
[UIView transitionWithView: self.imageView
duration: 1.0
options: UIViewAnimationOptionTransitionFlipFromTop
animations: ^{ [self loadFront]; }
completion: nil];
}
}
The methods loadFront and loadBack are as follows (html itself is shortened to minimum):
- (void) loadFront
{
NSString *html = #"<p>Front Of Card</p>";
[self.viewWebView loadHTMLString:html baseURL:nil];
}
- (void) loadBack
{
NSString *html = #"<p>Front Of Card</p> <br /> <p>as well as back of card<p>";
[self.viewWebView loadHTMLString:html baseURL:nil];
}
From a functionality perspective this works great. The card can be flipped, and the web view is updated with the new HTML text. However, the update to the actual web view takes place after the card has already finished flipping (after the animation instead of during). What do I need to do to have the viewWebView already loaded with the updated html once the view animation finishes it's flip, rather than immediately afterwards.
I believe your problem is that UIWebView loads items asynchronously. If so, you need to start your load and then when the UIWebView calls the delegate function webViewDidFinishLoad: begin your animation.
However, it's possible that the UIWebView will render to the screen before the delegate method is called causing the content to flash up before the animation begins.
If so, then you may have to do this with two different UIWebViews and animate switching from one to the other.

How to use UIActivityIndicatorView on custom UIButton?

I want to use UIActivityIndicatorView on my custom UIButton.
Here is my code:
if (sender.tag == 1)
{
// Start animating
activityIndicator.hidden = NO;
[activityIndicator startAnimating];
// Check if the network is available
if ([self reachable]) {
// Stop animating
activityIndicator.hidden = YES;
[activityIndicator stopAnimating];
}
}
What I want to do here is:
Once the user touch the button, I want to start the ActivityIndicatior while Reachable checking the network availability. Once it done pass it to the next view.
Update
UIActivityIndicator is on top of my custom UIButton. It build successfully, but ActivityIndicator is not showing when I touch the button.
I'm sure you had your answer since then.
After 4 years, language has changed to Swift, but I had the same problem : UIActivityIndicatorView is not showing when I add it through :
self.myButton.addSubview(self.myIndicatorView)
I had to climb a level up :
self.myButton.superview!.addSubview(self.myIndicatorView)
Assuming everything else is correct in your project, the problem here is that you're showing and hiding an activity indicator in the same event loop, without giving a pause to draw it. Let me explain:
If you have the code:
UIView* view = someView;
view.backgroundColor = [UIColor redColor];
// various synchronous operations
view.backgroundColor = [UIColor yellowColor];
The view will only ever have a background color of yellow.
To answer your question, you probably want to animate the spinner, do some asynchronous operation, then stop the animation. The key being to not stall on the main event loop while your asynchronous task is running. If your comfortable with blocks it would look something like this:
if (sender.tag == 1) {
// Start animating
activityIndicator.hidden = NO;
[activityIndicator startAnimating];
// Check if the network is available
[self checkReachableWithCallback:^{
// Stop animating
activityIndicator.hidden = YES;
[activityIndicator stopAnimating];
}];
}