The Problem - Preparing and showing an MFMessageComposeViewController is trivial as per the Apple docs. What I need to know is when this has been fully presented.
Explanation - Showing the MFMessageViewComposeController with a completion block is easy, but doesn't solve my problem:
[self presentViewController:messageController animated:YES completion:^(void){
//Controller has been shown. But not really....
}];
The problem is more obvious for messages to larger groups of recipients (say 50 people). The completion block gets called, but the phone's screen remains black. Several seconds later, the messaging window appears. Several seconds later, the recipient list becomes active with a flashing cursor. Basically, there's a lot of loading and processing that goes on after the controller has supposedly been presented.
What I'd like - To figure out when the interface has been fully loaded. I don't expect a simple answer, and I've already spent quite a bit of time on it - definitely bounty worthy. If you can post a working answer with code I'll award maximum bounty for it.
Just check MFMailComposeViewController view's frame. Once it achieves top of the screen handle the appearance.
[self presentViewController:messageController animated:YES completion:^
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^
{
while(messageController.view.frame.origin.y > 0)
{
}
dispatch_async(dispatch_get_main_queue(), ^
{
// Handle appearance of MFMailComposeViewController
});
});
}];
The other way is to wait 0.3 seconds using dispatch_after() method. But this time interval could be changed next versions of iOS.
Related
I'm trying to extend what apple watch can do by rendering UIImage 'frames' and then setting them on my WKInterfaceImage every 500 milliseconds (2 frames per second).
My plan is to try render 8bit style games that don't need high detail or frame rates and then get arrow buttons on the watch app to direct how the game state changes.
So I have a Game class that has a 'tick' method which returns a UIImage. Each call to 'tick' will proceed the game by a single point. Think Tetris where each 'tick' of the game moves the falling blocks by one block space downwards. The game proceeds by 'ticks' until there is interaction from the user. Upon call to rotate the block, I am telling the Game class to rotate left or right when the next 'tick' happens. Here are the relevant parts of my WKInterfaceController class below.
- (void)willActivate
{
// This method is called when watch view controller is about to be visible to user
NSLog(#"%# will activate", self);
// wait 2 seconds until game 'starts'
[self performSelector:#selector(timerFired) withObject:nil afterDelay:2.];
}
- (void)timerFired
{
dispatch_async(dispatch_get_main_queue(), ^{
[self.theImage setImage:[self.game tick]];
[self performSelector:#selector(timerFired) withObject:nil afterDelay:.5];
});
}
- (IBAction)leftButtonPressed
{
self.game.futureMove = FutureMoveAntiClockWise;
}
- (IBAction)rightButtonPressed
{
self.game.futureMove = FutureMoveClockWise;
}
Now, amazingly all that code works great - for a few seconds. Then it all gets slower and slower and more and more behind (in terms of frames). After 10 seconds or so pressing the rotate left or right buttons only shows up on the rendered UIImage a few seconds later.
The watch app starts off rendering maybe 30 frames a second (if I wanted it to), and then crawls slower and slower and ultimately stops. Is there a better way to reliably setImage on a WKInterfaceImage repeatedly without it slowing down?
I'm so close!!
Thanks for you comments. After updating to Xcode 6.3 it works fine and doesn't lag but I will heed #MikeSwanson and expect Apple to reject my app :(.
I'm developing a game that uses cocos2d-x, I'm having a problem on old devices such as ipad 1 where large scene takes a lot of time to load.
so the scene transition can take a few seconds, therefore I tried to implement a "busy" animation between scene transitions while the new scene is being loaded.
I implemented this using MBProgressHUD on IOS and ProgressDialog on android.
I decided that I don't want to start showing this animation immediately, instead I could schedule the animation to start 1-2 seconds after the scene transition starts, so that on newer devices the animation will not be shown at all.
Initially what I did was this:
- (void) showProgressDialog: (int) runWithoutDelay
{
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(showProgressDialogAfterDelay) object:nil];
shouldShow = YES;
if (runWithoutDelay){
[self showProgressDialogAfterDelay];
}
else{
[self performSelector:#selector(showProgressDialogAfterDelay) withObject:nil afterDelay:delay];
}
}
- (void) showProgressDialogAfterDelay
{
if (shouldShow){
isShown = YES;
[progressHUD show:YES];
}
}
and if I pass the scene transition part I would just set shouldShow flag to false and won't start the animation.
The problem is that because cocos2d-x scene transition is done in main\ui thread sometimes instead of calling the show method after 2 seconds it takes up to 6-8 seconds for it to be called and sometimes it even gets called after I set my flag to false.
As I understand it happens because performSelector (and so is NSTimer which I also tried) both run on the same thread by placing the call in the thread run loop queue.
I needed something like performSelectorInBackground that takes delay, so I tried using dispatch_after (even though I still haven't figure out how this could be canceled, as I need to cancel a previous schedule when I create a new one) this looked more accurate according Xcode's logs but even though the logs said that the method was called exactly 2 seconds after being scheduled the time would take 5-8 seconds to show and sometimes would not show at all.
As I understand it, and correct me if I'm wrong, this happens because MBProgressHUD changes to UI must happen on main\UI thread so even though I call [ProgressHUD show:YES] on a background thread the actual update of the UI is scheduled to be executed somehow on the main thread and because of it being stuck on cocos2d-x stuff it only starts to show after that, when the scene transition is completed and its too late.
is there any way around this problem? can I somehow schedule it to start with a delay but have it display right when I want it?
What I don't understand is why if I start it with no delay the animation works smoothly without being stuck even though the main thread is busy with cocos2d-x processing.
I‘ve managed a way around this somehow!
Create a normal method where you will call the progressHUD and call the second
Create the second method where you do the time consuming stuff (loading views)
Perform that method on the main thread
Sample:
-(void)callHUD {
[progressHUD show];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self performSelectorOnMainThread:#selector(loadView) withObject:nil waitUntilDone:YES];
dispatch_async(dispatch_get_main_queue(), ^{
[progressHUD dismiss];
});
});
}
-(void)loadView {
//Perform your segue or transition which needs to load
}
Hope that could help you a little.
so I'm making a post to Facebook and want the user to select an image before doing that.
Once the image is picked and I show Facebook. Problem is, when I show Facebook straight away, without the image picking part, it looks fine. When I show it after picking the image, Facebook sharing appears animated, but laggy. As if the action has a very low framerate or something.
Here's my code:
self.portraitPicker = [[UIImagePickerController alloc] init];
#if !(TARGET_IPHONE_SIMULATOR)
self.portraitPicker.sourceType = UIImagePickerControllerSourceTypeCamera;
#endif
[self.portraitPicker setDelegate:self];
self.portraitPicker.allowsEditing = YES;
[self presentViewController:self.portraitPicker animated:YES completion:nil];
Now when this is complete, I show the Facebook posting modally:
[picker dismissViewControllerAnimated:YES completion:^{
if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook])
{
self.facebookController = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
[self.facebookController setInitialText:#"Some text"];
[facebookController addImage:pickedImage];
[self presentViewController:self.facebookController animated:NO completion:nil];
}
}];
I can do this in the didFinishPickingMediaWithInfo or the imagePickerControllerDidCancel, doesn't matter, the problem still comes up.
Being desperate, I tried:
Showing it on the main thread delayed
Showing it async
Showing it outside the dismiss-block
Showing it from the AppDelegate's rootviewcontroller instead
This is not Facebook-related as it happens with SLServiceTypeTwitter as well as with MFMessageComposeViewController.
Can't seem to do away with the laggy animation that ONLY happens showing the image picker. Does anyone know what's causing this?
Given the lack of response and similar issues, I figured the cause was my own architecture.
It turns out that one of my viewcontrollers' ViewDidAppear was called after the camera picker was displayed (as it became the active viewcontroller and consequently the inactive one, giving control back to the original viewcontroller).
Blocking the background calls and animation that happened in this viewDidAppear resolved the issue. I still don't know why calling it delayed (i.e. 10 seconds, or even 100 seconds into the future, when nothing was going on) still had the laggy appearence show up, but there it is.
I noticed that after dismiss a UIAlertView, there is a short amount of time that apps do not recognize any touches.
So, I made a very simple project, which only contains 2 UIButtons (one to change a label to a random number and one to show a UIAlertView).
Tested it both on device (an iPhone4) and simulator (iOS 6 and iOS 7).
The result is this lag only happens on iOS 7. On iOS 6.x, it works just fine.
The delay duration depends on how large the app is. In the test project, which I described above, the delay is about 0.3s. However, in an another project of mine, it maybe up to 1 second.
I also used GCD, follow this:
- (void) startSomeLongOperation {
//display alertView
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_NORMAL, 0), ^{
// …do something that takes long…
dispatch_async(dispatch_get_main_queue(), ^{
//dismiss alertView
});
});
}
another one I have tried:
dispatch_async(dispatch_get_main_queue(), ^{
//show and dismiss alertView
});
neither of them work.
So, I jumped in to conclusion that this delay was caused by iOS 7.
Have anyone experienced this before ?
I have a question about presenting the TWTweetComposerViewController as a modal view in iOS 5.
I use the apple sample code as below to implement a tweet method in my app.
-(void)tweet
{
//Using tweeting example code.
//Setup the build-in twitter composer view controller
TWTweetComposeViewController *tweetViewController = [[TWTweetComposeViewController alloc]init];
//Add url
[tweetViewController addURL:[self URL]];
[tweetViewController setInitialText:#""];
//Present Composer
[self presentModalViewController:tweetViewController animated:YES];
//Creat the completion handler
[tweetViewController setCompletionHandler:^(TWTweetComposeViewControllerResult result)
{
//Do something here.
[self dismissModalViewControllerAnimated:YES];
}];
[tweetViewController release];
}
This works fine, when I call the tweet method, the tweet controller does appear as a modal view.
However, the problem is: the composer shows up very slowly. It usually takes 3-5 seconds to show the composer. Of course, this is when the app calls this method for the first time. After the first time, it shows up a little bit quicker, but still take about 1~2 seconds.
I wonder if is there something I didn't do right to make the composer view appear slowly? Is there any way to speed up the process?
Btw. the testing device is the iPhone 4.
Thanks!
Yes, there is. You can preload the class by initializing it in the background sometime before you'll ever need it. Move tweetViewController into an instance or static variable, initialize and set all of its properties. Then just show it in the tweet method.