3

I want to load some data when a button is pressed and show a "loading view" as a subview of my current view while it's loading.

So I want to start loading only after the subview did appear. If not my UI gets stuck without a notice (and the subview only shows after the loading is done).

Is there a way to use something like viewDidAppearfor subviews?

Doing the work right after the addSubview: like this doesn't work:

- (void)doSomeWorkAndShowLoadingView
{
    UIView *loadingView = [[[UIView alloc] initWithFrame:self.view.frame] autorelease];
    loadingView.backgroundColor = [UIColor redColor];
    [self.view addSubview:loadingView];
    [self doSomeWork];
    [loadingView removeFromSuperview];
}
- (void)doSomeWork
{ 
    sleep(5);
}

(I don't want to do the loading on a new thread, because is's CoreData i'm working on, which is't thread safe).

Thank You!

Jochen
  • 606
  • 6
  • 23

2 Answers2

2

I found a solution:

Adding the subview with an animation I could use - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag to call something like subviewDidAppear of the delegate of the subview.

In subclass of UIView:

#define KEY_SHOW_VIEW @"_ShowLoadingView_"
#define KEY_HIDE_VIEW @"_HideLoadingView_"
- (void)addToSuperview:(UIView *)theSuperview
{

    [theSuperview addSubview:self];   

    CATransition *animation = [CATransition animation];
    [animation setDuration:0.2];
    [animation setType:kCATransitionFade];
    [animation setDelegate:self];
    [animation setRemovedOnCompletion:NO];
    [animation setValue:KEY_SHOW_VIEW forKey:@"animation_key"];
    [[theSuperview layer] addAnimation:animation forKey:nil];

}

- (void)removeFromSuperview
{
    CATransition *animation = [CATransition animation];
    [animation setDuration:0.2];
    [animation setType:kCATransitionFade];
    [animation setDelegate:self];
    [animation setRemovedOnCompletion:NO];
    [animation setValue:KEY_HIDE_VIEW forKey:@"animation_key"];
    [[self.superview layer] addAnimation:animation forKey:nil]; 

    [super removeFromSuperview];
}

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{    
    NSString* key = [anim valueForKey:@"animation_key"];
    if ([key isEqualToString:KEY_SHOW_VIEW]) {
        if (self.delegate) {
            if ([self.delegate respondsToSelector:@selector(loadingViewDidAppear:)]) {
                [self.delegate loadingViewDidAppear:self];
            } 
        }
    } else if ([key isEqualToString:KEY_HIDE_VIEW]){
        [self removeFromSuperview];
    }
}

This got me the results I was looking for.

Thanks again for your help!

Jochen
  • 606
  • 6
  • 23
1

You should either be able to simply start your loading directly after calling [parentView addSubview:loadingView] or in your loading view (assuming it is subclassed) override didMoveToSuperview like so:

- (void)didMoveToSuperview {
    // [self superview] has changed, start loading now...
}
Simon Cave
  • 3,971
  • 4
  • 24
  • 28
  • Doesn't work. `didMoveToSuperview` doesn't mean, that the subview did actually appear, but only that it has been added to a superview. If I start loading in `didMoveToSuperview` the subview still get's visible only after the loading of the data. – Jochen Mar 29 '11 at 12:11
  • When you say "loading", what are you doing? Are you waiting on a network operation or performing some sort of calculation? – Simon Cave Mar 29 '11 at 12:22
  • I load data from a CoreData database. – Jochen Mar 29 '11 at 12:27
  • actually it's not "loading". I copy data from an object to another. – Jochen Mar 29 '11 at 12:33
  • This definitely sounds like something that should be done off the main thread. If that's not an option, you might want to try calling your `doSomeWork` method momentarily after you add your loading subview. Like so: `[self performSelector:@selector(doSomeWork) withObject:nil afterDelay:1/10]` – Simon Cave Mar 29 '11 at 14:38