_datePicker.frame = CGRectMake(70, self.view.frame.size.height -150,250,100);
I'm using this code under viewDidLoad to change the size of a UIDatePicker. It works great but gives me another 3 seconds on load time. I tried using this:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
(unsigned long)NULL), ^(void) {
_datePicker.frame = CGRectMake(70, self.view.frame.size.height -150,250,1);
});
but I lose all the animation between segues if I do, don't know why. I thought about using another thread in viewDidLoad but I don't know how to do it or if it's possible.
Thanks
Related
UIView *test=[[UIView alloc]initWithFrame:CGRectMake(20, 150, 10, 20)];
[test setBackgroundColor:[Util colorWithHexString:#"#FF00007f"]];
[self.view addSubview:test];
int testNum=0;
for(int i=0;i<50;i++){
testNum=0;
//do something spend 100 ms
while(testNum<800){
testNum+=1;
}
[test setFrame:CGRectMake(20, 150, 10+i*200/50, 20)];
}
I want to build a custom progress bar.
Just like above, but the uiview only redraw by last one of loop.
How can I resolve the problem? And, what happen?
Thanks.
I change code to
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
int testNum=0;
for(int i=0;i<50;i++){
testNum=0;
while(testNum<800){
NSLog(#"%d",testNum);
testNum+=1;
}
dispatch_async(dispatch_get_main_queue(), ^{
[test setFrame:CGRectMake(20, 150, 10+i*200/50, 20)];
});
}
});
It work, but while loop just simulate situations for block code in my project.
Actually, spend time code is alloc list item and initial it's view, so it necessary in main thread.
Any suggestions?
Thank you.
Your "do something spend 100 ms" loop takes just a few cycles to execute on the iPhone, your code is working but it's not stalling long enough for any visible progress to be seen.
Also it's very bad practice to try and lock up the UI thread like that.
I have an interface which contains several UIImageView components on a view and i would like to update the animation images in run-time.
The main idea is to change the animation images into a thread with a delay of 2 seconds. The code below works fine. However, when i introduce a sleep time (with the commented NSThread sleepForTime); it no longer works. I am sure there is a logical explanation but i cannot identify it.
It's important to note that the animation is already running with another set of animated images.
Any help or tip is more than welcome :)
dispatch_async(allowToTouchThread, ^{
//[NSThread sleepForTimeInterval:2.0];
int randomnReward = 0;
WizzReward* currentReward = [rewardListForPages objectAtIndex:randomnReward];
WizzAnimalModel* animalModel = [gameLevelManager getAnimalModelByCategoryId: [currentReward getAnimalId]];
NSMutableArray* expressionsForAnimals = [animalModel getArrayForClosedEyesFaceExpression];
float animationDuration = [animalModel getStandardRewardAnimationDuration];
pageContentViewController.imagesArrayFileLevel1 = expressionsForAnimals;
pageContentViewController.animationLevel1Duration = animationDuration;
}
});
What about replacing your dispatch_async to a dispatch_after and set a delay of 2 seconds:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
int randomnReward = 0;
WizzReward* currentReward = [rewardListForPages objectAtIndex:randomnReward];
WizzAnimalModel* animalModel = [gameLevelManager getAnimalModelByCategoryId: [currentReward getAnimalId]];
NSMutableArray* expressionsForAnimals = [animalModel getArrayForClosedEyesFaceExpression];
float animationDuration = [animalModel getStandardRewardAnimationDuration];
pageContentViewController.imagesArrayFileLevel1 = expressionsForAnimals;
pageContentViewController.animationLevel1Duration = animationDuration;
});
Changing the animated images without any timer, could be done directly by modifying the array of images.
However, changing the same animated images with a timer, needed 3 steps:
first the modification of the image arrays
second the actual re-association of the UIView AnimationImages to the modified array of images;
and finally startAnimating the UIView eventhough it hasn't been stopped beforehand
The source code below now works fine with a timer:
WizzReward* currentReward = [rewardListForPages objectAtIndex:0];
WizzAnimalModel* animalModel = [gameLevelManager getAnimalModelByCategoryId: [currentReward getAnimalId]];
NSMutableArray* expressionsForAnimals = [animalModel getArrayForClosedEyesFaceExpression];
pageContentViewController.imagesArrayFileLevel1 = expressionsForAnimals;
pageContentViewController.reward1CurrentPage.animationImages = pageContentViewController.imagesArrayFileLevel1;
[pageContentViewController.reward1CurrentPage startAnimating];
I did find neither "time vs no-timer difference"information in the literature nor actual reason why it should be done like that; but it works every time. Hope it helps anyone who runs into the same problem.
This question already has answers here:
Calling sleep(5); and updating text field not working
(4 answers)
Closed 8 years ago.
In my Application, I have a NSMutableArray with UIImage in it.
I would like to display the first UIImage in the array for three seconds, and then to
display the second image.
All of this should happen when I press a UIButton.
Below is my code:
[testImageView setImage:[arr objectAtIndex:0]] ;
sleep(3) ;
[testImageView setImage:[arr objectAtIndex:1]] ;
testImageView is a UIImageView object on my screen.
When I'm running this code, my button remain pressed for three seconds and only the second image is displayed.
What should I do?
Try using one of the most obscure methods of UIImageView.
UIImageView *myImageView = [[UIImageView alloc] initWithFrame:...];
myImageView.animationImages = images;
myImageView.animationDuration = 3.0 * images.count;
[self.view addSubview:myImageView];
Then, when you wanna start animating
[myImageView startAnimating];
I don't know what you plan on doing with this, but 3 seconds might be too much. If you're doing some sort of presentation-ish, then this method might not be very good, since there's no easy way of going back.
The reason that your button remains pressed is because you slept main thread for 3 seconds, this means that nothing is going to happen to your application (at least the user interface) until thread is back to active.
There are multiple ways to achieve what you wish, but you must put a timer on the background thread. I would suggest you put the code to set the second image in another method first and make array into a property.
- (void)setImage
{
[testImageView setImage:self.yourArray[1]];
}
Then you can use one of the following ways to execute the method:
Use a NSTimer:
[NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:#selector(setImage) userInfo:nil repeats:NO]
Use performSelector method of NSObject:
[self performSelector:#selector(setImage) withObject:nil afterDelay:3.0];
Use Grand Central Dispatch.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3.0), dispatch_get_main_queue(), ^{
[self setImage];
});
Any of the ways described above will work.
Read more information about concurrency on the links below:
http://jeffreysambells.com/2013/03/01/asynchronous-operations-in-ios-with-grand-central-dispatchNS
https://developer.apple.com/library/ios/documentation/general/conceptual/concurrencyprogrammingguide/Introduction/Introduction.html
how to call a method of multiple arguments with delay
How can I delay a method call for 1 second?
I'm trying to make a photo slider similar to iOS's photos app. I've seen PhotoScroller, and I'm using initWithContentsOfFile.
CATiledLayer seems like a good idea, except I have no way of pre-generating tiles. The tiles also take up a lot of space. Images are part of a document bundle synced up with iCloud. Photos are typically JPEG. From hours of reading it seems like generating the tiles on the fly is slower than just loading the whole image.
It seems like a majority of the time is spent in decompressing the image anyway. And moving it to a background queue and displaying a smaller image should work well. So that's what I'm trying to do. And it works to a point, but if I slide without waiting for the image to load there's still somewhat of a stutter, which sometimes causes the scroll view to hang momentarily (when paging).
This is the function that sets the image:
- (void)setImage:(UIImage *)image placeholder:(UIImage *)placeholder
{
_image = image;
self.zoomScale = 1.0;
imageView.image = nil;
imageSize = image.size;
imageView.frame = CGRectMake(0, 0, image.size.width, image.size.height);
MachTimer *timer = [MachTimer new];
[timer start];
imageView.image = placeholder;
NSLog(#"placeholder: %f", [timer elapsedSeconds]);
//imageView.layer.contents = (id)placeholder.CGImage;
self.contentSize = image.size;
[self setMaxMinZoomScalesForCurrentBounds];
self.zoomScale = self.minimumZoomScale;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
MachTimer *timer = [MachTimer new];
[timer start];
UIGraphicsBeginImageContext(CGSizeMake(1, 1));
[image drawAtPoint:CGPointZero];
UIGraphicsEndImageContext();
NSLog(#"decode: %f", [timer elapsedSeconds]);
dispatch_sync(dispatch_get_main_queue(), ^{
if(_image == image) {
MachTimer *timer = [MachTimer new];
[timer start];
imageView.image = image;
NSLog(#"display: %f", [timer elapsedSeconds]);
//imageView.layer.contents = (id)image.CGImage;
}
});
});
}
My "placeholder" times are about 0.00005 - 0.00006 seconds (decompress and display), and they're 480px tall. My "decode" times (for full image) are about 0.8 to 1.2 seconds. "display" is about 0.0001 seconds (which is about 0.1 milliseconds).
So with those times the UI should be smooth as butter, but it isn't.
I've even tried to go as far as setting contents of a regular UIView to the CGImage. I've tried iOS 6.0's drawsAsynchronously, and that seems to make it a little worse.
What am I doing wrong?
EDIT:
I've pushed my sample project to GitHub:
https://github.com/lukescott/PhotoScroller
I would create a background thread for hard work (photo load or decode) and when its done then delegate UI work (draw or whatever) to main thread using one of tools (queues, msgs, etc).
I'm having problems adding subviews to a scrollview sequentially.
I've got a JSON response coming back from the server which I parse into an array of Business objects, and I send off to the function updateCarousel, which looks like this:
-(void) updateCarousel: (NSArray *)response{
if(response && response.count>0){
int i=0;
self.scrollView.hidden=NO;
[self.scrollView setNeedsDisplay];
self.pageControl.hidden=NO;
[self.scrollView setContentOffset:CGPointMake(0, 0) animated:NO];
for (Business *business in response){
if (i >= MAX_INITAL_SEARCH_RESULTS)
break;
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * i;
frame.origin.y = 0;
frame.size = scrollView.frame.size;
CardView *cardView = [[CardView alloc] initWithBusinessData:business andFrame:frame];
//I've tried the following code with and without wrapping it in a GCD queue
dispatch_queue_t addingQueue = dispatch_queue_create("adding subview queue", NULL);
dispatch_async(addingQueue, ^{
[self.scrollView addSubview:cardView];
});
dispatch_release(addingQueue);
cardView.backgroundColor = [UIColor colorWithWhite:1 alpha:0];
i++;
self.scrollView.contentSize = CGSizeMake(i*(self.scrollView.frame.size.width), self.scrollView.frame.size.height);
self.pageControl.numberOfPages=i;
}
}else{
self.scrollView.hidden=YES;
self.pageControl.hidden=YES;
NSLog(#"call to api returned a result set of size 0");
}
The result - despite the many things I've tried - is always the same: the scrollView adds the subviews all at once, not as they are processed through the loop. I don't understand how this is possible. If I add a sleep() at the end of the loop, it somehow waits for the whole loop to be over before it shows the subviews as added. How does it even know how long the results array is? I'm at my wits' end, please help.
I assume you are not using any extra threads to process the data.
What you experience is the application is stuck executing your method. Even though you add your subviews one by one (with a sleep between them), no other piece of code is executed to handle your adding.
1. You can use another thread to load the data and add subviews but this needs to be synchronized to the main thread (more complicated).
2 You can break your method in multiple calls. Between 2 calls of your load method, other pieces of code are allowed to execute and this means the scrollview will be able to process/display your subviews one by one.
You will need to change your loading method to something like this:
- (void)updateCarouselStep:(NSNumber*)loadIndex
{
if (response && response.count > 0)
{
// Here add only a subview corresponding to loadIndex
// Here we schedule another call of this function if there is anything
if (loadIndex < response.count - 1)
{
[self performSelector:#selector(updateCarouselStep:) withObject:[NSNumber numberWithInt:(loadIndex+1) afterDelay:0.5f];
}
}
}
This is just one basic solution to the problem. For example, you need to take into consideration what happens if you update response data before you finish loading the previous one.