I am trying to counteract Apple's lack of innovation with SKStoreProductViewController. Im pretty certain this isn't possible, but lets see.
I am presenting the view controller outside of this block:
[storeController loadProductWithParameters:productParameters completionBlock:^(BOOL result, NSError *error) {}];
[self presentViewController:storeController animated:YES completion:^{}];
That way the view controller shows immediately, rather than waiting 30 seconds to load the product. However, now it obviously shows a blank controller while it loads the product. I would love to put a UIActivityIndicatorViewon the window until the product loads. I have tried this:
[self presentViewController:storeController animated:YES completion:^{
UIActivityIndicatorView *activity = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[activity startAnimating];
activity.frame = CGRectMake(0, 0, 44, 44);
activity.center = self.view.window.center;
[self.view.window addSubview:activity];
}];
No luck there. Is it possible to add an activity indicator on top of this view?
Have you tried to bring up the view controller once the SKStoreProductViewController loading is completed? like this
[storeController loadProductWithParameters:productParameters completionBlock:^(BOOL result, NSError *error)
{
[self presentViewController:storeController animated:YES completion:^{}];
}];
Related
I have an app in which I present a menu modally. Then, when the user selects a menu option, the menu dismisses itself and upon completion, presents another view modally according to what button the user selected.
This method worked flawlessly before, but since iOS 13 it behaves weirdly. Basically, it would not present the second view until the user touches the screen, and I cannot for the life of me find out why it behaves this way.
Here is my code (I added logs where the flow stops):
- (void) dismissPopUpMenu:(UIButton *)sender {
[self dismissViewControllerAnimated:NO completion:^{
if ( (sender.tag == 13 ) {
[self openPopUpWindow:sender];
}
}];
}
- (void) openPopUpWindow:(UIButton *)sender {
interactionDisabledLayer.alpha = 1.0f;
PopUpViewController *popUpController = [[PopUpViewController alloc] initWithPopUp:sender.tag];
popUpController.delegate = self;
NSLog(#"We get to here without problems.");
[self presentViewController:popUpController animated:NO completion:^{
NSLog(#"It only enters here if we touch the screen.");
self->interactionDisabledLayer.alpha = 0.0f;
}];
}
Update: Delaying the code with a timer help, but I consider it a dirty hack and would like to find a better solution.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self presentViewController:popUpController animated:NO completion:^{
self->interactionDisabledLayer.alpha = 0.0f;
}];
});
Delaying the code that presents the second UIViewController with a timer seem to help, but it is a rather dirty hack, and I would like to find a better workaround. If anyone has a proper solution, please post it as an answer and I will accept it as best.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self presentViewController:popUpController animated:NO completion:^{
self->interactionDisabledLayer.alpha = 0.0f;
}];
});
I have a navigation controller that starts my app (rootViewController is the navigationController). Then inside one of the views of the navigation I call:
TabBarController *tab = [[TabBarController alloc] init];
// Presentation
[self presentViewController:tab animated:NO completion:nil];
Then one of the tabs calls the UIImagePickerController and then saves the image on another thread. Then I return to the main queue and run:
dispatch_async(dispatch_get_main_queue(), ^{
[picker dismissViewControllerAnimated:YES completion:nil];
PostViewController *post = [[PostViewController alloc] init];
// Presentation
[self presentViewController:post animated:NO completion:nil];
});
But the post view never gets called and the viewDidLoad never gets hit in the PostViewController.m. Instead the imagePicker disappears and returns to the tabBarController. How do I fix this?
Assuming that you PostViewController object is not nil , Present the view controller after the dismiss process of picker ViewController is completed . Try this Code
dispatch_async(dispatch_get_main_queue(), ^{
[picker dismissViewControllerAnimated:YES completion:^{
PostViewController *post = [[PostViewController alloc] init];
// Presentation
[self presentViewController:post animated:NO completion:nil];
}];
});
I have been getting this error when trying to present the contact book view controller after a long process is complete.
Here is how I am running the process and showing the HUD.
HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
HUD.labelText = #"Scanning...";
UIFont *font = [UIFont fontWithName:#"HelveticaNeue-Light" size:20];
[HUD setLabelFont:font];
[HUD showWhileExecuting:#selector(scanWithImage:) onTarget:self withObject:_image animated:YES];
Here is how I am hiding the HUD and showing the contact book vc, which is called in scanImage.
dispatch_async(dispatch_get_main_queue(), ^(void){
[HUD hide:YES];
});
[self presentViewController:navigation animated:YES completion:nil];
Can anyone tell me how to resolve this issue?
Full error message:
Assertion failed: ([NSThread isMainThread]), function -[AFContextManager addContextProvider:], file /SourceCache/MobileAssistantFramework/MobileAssistantFramework-651.49/AFContextManager.m, line 113.
I guess you are trying to present the new controller from the background thread. Anything with respect to User interface including presenting a new controller cannot be performed from the background thread. So present the new controller from the main thread. Try this
dispatch_async(dispatch_get_main_queue(), ^(void){
[HUD hide:YES];
[self presentViewController:navigation animated:YES completion:nil];
});
I have a button that shows my app in a modal view, so that people can download and rate the app. I got it to show up modally with this code.
NSDictionary *appParameters = [NSDictionary dictionaryWithObject:#"607257427"
forKey:SKStoreProductParameterITunesItemIdentifier];
SKStoreProductViewController *productViewController = [[SKStoreProductViewController alloc] init];
[productViewController setDelegate:self];
[productViewController loadProductWithParameters:appParameters
completionBlock:^(BOOL result, NSError *error)
{
}];
[self presentViewController:productViewController
animated:YES
completion:^{
}];
`
This is what it turns into.
Problem is that the cancel button isn't working, it may be something with the Simulator or also something really simple, but I can't figure out why the cancel button isn't working
You need to implement the delegate method to dismiss the view controller:
- (void)productViewControllerDidFinish:(SKStoreProductViewController *)viewController
{
[viewController dismissViewControllerAnimated:YES completion:nil];
}
I am learning how to handle view controller hierarchies using the storyboard. I have 2 ViewControllers: the root of type cwViewController (what I understand is 'self' below) and a second of type WorkspaceViewController. I am getting "Attempt to present while a presentation is in progress!" as a result of this code.
- (IBAction)nextView {
WorkspaceViewController *workspace = [[WorkspaceViewController alloc] initWithNibName:nil bundle:nil];
[self presentViewController:workspace animated:YES completion:NULL]; }
The answer to How to present view controller properly? is the closest answer that could apply but doesn't quite fit this scenario because I'm not switching back and forth between VCs, I'm just presenting one, then dismissing it to display the original.
Then, I tried dismissing the current one before presenting the second, as some answers suggested, like this:
[self dismissViewControllerAnimated:NO completion:nil];
[self presentViewController:workspace animated:YES completion:NULL];
But that just gets me an additional Warning: Attempt to dismiss from view controller while a presentation or dismiss is in progress!
Doing some other research I saw similar problems were solved by adding a block to
[self dismissViewControllerAnimated:YES...]
But that doesn't help here because my warning occurs before I even get to a point where I call that dismiss method. Any further knowledge on how the order and hierarchy of views are meant to be handled would be a big help. Thanks very much.
Did you create a segue from the button to your WorkSpaceViewController? If so, you are likely attempting to present the WorkSpaceView twice - once when the button is selected and once from cwViewController. To eliminate the error, delete the segue from the button to WorkSpaceViewController and then recreate the segue - this time between cwViewController and the WorkSpaceViewController. That should take care of it.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
// TODO: make this all threaded?
// crop the image to the bounds provided
img = [info objectForKey:UIImagePickerControllerOriginalImage];
NSLog(#"orig image size: %#", [[NSValue valueWithCGSize:img.size] description]);
// save the image, only if it's a newly taken image:
if ([picker sourceType] == UIImagePickerControllerSourceTypeCamera) {
UIImageWriteToSavedPhotosAlbum(img, nil, nil, nil);
}
// self.image_View.image = img;
// self.image_View.contentMode = UIViewContentModeScaleAspectFit;
NSLog(#"Picker has returned");
[self dismissViewControllerAnimated:YES
completion:^{
ModalViewController *sampleView = [[ModalViewController alloc] init];
[self presentModalViewController:sampleView animated:YES];
}];
}
try
[self presentModalViewController:workspace animated:YES];
if (![[self modalViewController] isBeingPresented]) {
[self dismissModalViewControllerAnimated:YES];
}