UITableView가 데이터 요청을 완료하면 알림을 받습니까?


108

UITableView데이터 소스에서 데이터 요청을 완료 한시기를 확인할 수있는 방법이 있습니까?

관련된 뷰 컨트롤러 ( ) 의 viewDidLoad/ viewWillAppear/ viewDidAppear메소드는 UITableViewController모두 너무 일찍 실행되므로 여기서는 사용되지 않습니다. 이들 중 어느 것도 (완전히 이해할 수있는) 데이터 소스에 대한 쿼리가 당분간 (예 :보기가 스크롤 될 때까지) 완료되었음을 보장하지 않습니다.

내가 찾은 한 가지 해결 방법은를 호출 reloadData하는 것 입니다.을 호출 viewDidAppear하면 reloadData반환 될 때 테이블보기 당분간 필요한만큼 데이터 소스 쿼리를 완료 할 수 있기 때문입니다.

그러나 데이터 소스 reloadData가 처음로드 될 때 데이터 소스에 동일한 정보를 두 번 (자동으로 한 번, 호출로 인해 한 번) 요청하는 것으로 가정하므로 다소 불쾌 해 보입니다 .

이 작업을 수행하려는 이유는 UITableView- 의 스크롤 위치를 유지하고 싶지만 가장 가까운 행뿐만 아니라 픽셀 수준까지 바로 아래로 유지하고 싶기 때문 입니다.

스크롤 위치를 복원 할 때 (를 사용하여 scrollRectToVisible:animated:) 이미 충분한 데이터가있는 테이블 뷰가 필요합니다. 그렇지 않으면 scrollRectToVisible:animated:메서드 호출이 아무 작업도 수행하지 않습니다 ( viewDidLoad, viewWillAppear또는 에서 자체적으로 호출하면 발생합니다 viewDidAppear).


stackoverflow.com/a/11672379/2082172 와 비슷한 것을 찾고있는 것 같습니다 .
Timur Kuchkarov 2013

내 경험상 UITableView는 행을 삽입 / 삭제하는 호출 및 기타 항목을 캐시하는 것처럼 reloadData에 대한 호출을 캐시 할 수 있습니다. UITableView는 CPU 사용량 및 기타 사항에 따라 준비되면 데이터 소스 대리자를 호출합니다.
Walt Sellers

답변:


61

이 답변은 답변이 작성된 이후 UITableView 구현에 대한 일부 변경 사항으로 인해 더 이상 작동하지 않는 것 같습니다. 이 주석을 참조하십시오 : UITableView가 데이터 요청을 마쳤을 때 알림을 받습니까?

나는 며칠이 문제와 함께 연주하고 그 하위 클래스 생각했습니다 UITableView의는 reloadData가장 좋은 방법입니다 :

- (void)reloadData {

    NSLog(@"BEGIN reloadData");

    [super reloadData];

    NSLog(@"END reloadData");

}

reloadData테이블이 데이터를 다시로드하기 전에 끝나지 않습니다. 따라서 두 번째 NSLog가 실행되면 테이블 뷰가 실제로 데이터 요청을 완료합니다.

UITableView전과 후에 대리자에게 메서드를 보내도록 서브 클래 싱 했습니다 reloadData. 매력처럼 작동합니다.


2
이것이 최선의 해결책 인 것 같습니다. 그냥 구현했고 당신이 말했듯이 매력처럼 작동합니다. 감사!
이론

2
@EricMORAND "reloadData는 테이블이 데이터를 다시로드하기 전에 끝나지 않습니다."라고 말합니다. 그 의미를 명확히 할 수 있습니까? 그 발견 reloadData즉시 반환하고 나는 "END reloadData"를 참조 하기 전에 세포가 실제로합니다 (즉, 전에 다시로드 UITableViewDataSource메소드가 호출). 내 실험은 당신이 말하는 것과 정확히 반대되는 것을 보여줍니다. 나는 당신이 말하려는 것을 오해해야합니다.
Rob

3
Eric의 대답은 reloaddata를 구현하지 않고 (재정의하지 않고 읽기) reloaddata를 호출하고 (기본적으로 [super reloaddata]가 될 것입니다) 호출 한 후 완료 될 때 원하는 작업을 수행하는
것과 같지

5
옛날 옛적에 reloadData는로드 프로세스가 끝나기 전에 완료했습니다. 그러나 애플은 어느 시점에서 그것을 변경했습니다. 이제 UITableView 클래스는 모든 행 삽입 및 삭제 호출과 함께 reloadData 호출을 캐시 할 수 있습니다. UITableView에 대한 @interface 선언을 보면 _insertItems 및 _deleteItems 바로 아래에 NSMutableArray 멤버 _reloadItems가 있습니다. (나는이 변경으로 인해 상속 재 작업 코드를 I로 했어.)
월트 판매는

3
호출 후 메인 대기열의 블록에 완료 코드를 게시하는 [super reloadData]것은 나를 위해 작동합니다 dispatch_async(dispatch_get_main_queue(), ^{NSLog(@"reload complete");});. 기본적으로에서 테이블 뷰에 의해 게시 된 블록을 뛰어 넘습니다 reloadData.
Timothy Moose

53

나는 내 앱에서 동일한 시나리오를 가지고 있었고 여기에 언급 된 다른 답변이 iOS7 이상에서 작동하지 않기 때문에 여러분에게 내 답변을 게시 할 것이라고 생각했습니다.

마지막으로 이것이 나를 위해 일한 유일한 것입니다.

[yourTableview reloadData];

dispatch_async(dispatch_get_main_queue(),^{
        NSIndexPath *path = [NSIndexPath indexPathForRow:yourRow inSection:yourSection];
        //Basically maintain your logic to get the indexpath
        [yourTableview scrollToRowAtIndexPath:path atScrollPosition:UITableViewScrollPositionTop animated:YES];
 });

신속한 업데이트 :

yourTableview.reloadData()
dispatch_async(dispatch_get_main_queue(), { () -> Void in
    let path : NSIndexPath = NSIndexPath(forRow: myRowValue, inSection: mySectionValue)
    //Basically maintain your logic to get the indexpath
    yourTableview.scrollToRowAtIndexPath(path, atScrollPosition: UITableViewScrollPosition.Top, animated: true)

})

그래서 이것이 어떻게 작동하는지.

기본적으로 재로드를 수행하면 주 스레드가 바쁘기 때문에 디스패치 비동기 스레드를 수행 할 때 블록은 주 스레드가 완료 될 때까지 대기합니다. 따라서 tableview가 완전히로드되면 메인 스레드가 완료되고 메서드 블록을 전달합니다.

iOS7 및 iOS8에서 테스트되었으며 훌륭하게 작동합니다.)

iOS9 업데이트 : iOS9에서도 잘 작동합니다. POC로 github에 샘플 프로젝트를 만들었습니다. https://github.com/ipraba/TableReloadingNotifier

여기에 테스트 스크린 샷을 첨부하고 있습니다.

테스트 환경 : Xcode7의 iOS9 iPhone6 ​​시뮬레이터

여기에 이미지 설명 입력


8
내가 찾은 최고의 answear!
Nikolay Shubenkov 2014 년

@Gon iOS9에서 테스트를했는데 제대로 작동합니다. 당신은 참조하시기 바랍니다 수 github.com/ipraba/TableReloadingNotifier
iPrabu

내 에뮬레이터에서는 잘 작동하지만 실제 장치에서는 작동하지 않는 것 같습니다. 이 문제가있는 다른 사람이 있습니까?
sosale151

1
이 솔루션은 마침내 저에게 효과적입니다! iOS 9에서 잘 작동합니다
Strong

1
Real Device, iPhone 6s에서 테스트했습니다. 그것도 잘 작동합니다.
Strong

25

편집 :이 답변은 실제로 해결책이 아닙니다. 재로드가 매우 빠르게 발생할 수 있기 때문에 처음에는 작동하는 것처럼 보이지만 실제로는 데이터가 완전히 다시로드 된 후에 완료 블록이 반드시 호출되는 것은 아닙니다. reloadData가 차단되지 않기 때문입니다. 더 나은 솔루션을 찾아야 할 것입니다.

@Eric MORAND의 답변을 확장하려면 완료 블록을 넣으십시오. 누가 블록을 좋아하지 않습니까?

@interface DUTableView : UITableView

   - (void) reloadDataWithCompletion:( void (^) (void) )completionBlock;

@end

과...

#import "DUTableView.h"

@implementation DUTableView

- (void) reloadDataWithCompletion:( void (^) (void) )completionBlock {
    [super reloadData];
    if(completionBlock) {
        completionBlock();
    }
}

@end

용법:

[self.tableView reloadDataWithCompletion:^{
                                            //do your stuff here
                                        }];

2
블록을 충분히 얻을 수 없습니다. 멋진 블록이있을 때 델리게이트가 필요한 사람!
bandejapaisa

나는 이것을 좋아하지만, 시스템이 reloadData ()를 호출 할 때, 예를 들어 테이블이 처음 표시 될 때 어떨까요?
Symmetric

12
이것은 해결책이 아닙니다. 완성 블록은 cellForRowAtIndexPath 전에 실행을 시작합니다
zvjerka24

1
이것은 작동하지 않습니다. reloadData는 차단 방법이 아닙니다. 이 코드는 셀이 아직 다시로드되지 않은 경우에도 reloadData를 호출 한 직후 에 호출됩니다. 게다가,이 코드를 보면 reloadData 뒤에 코드를 넣는 것이 낫다는 것을 알 수 있습니다 .
colinta

1
이것은 약간의 변경으로 나를 위해 작동합니다. 완료 블록을 직접 호출하는 대신 메인 대기열에 게시 된 블록에서 호출합니다 dispatch_async(dispatch_get_main_queue(), ^{completionBlock();});. 이것은 기본적으로에서 테이블보기에 의해 게시 된 블록을 뛰어 넘습니다 reloadData.
Timothy Moose

11

reloadData는 보이는 셀에 대한 데이터 만 요청합니다. 테이블의 특정 부분이로드 될 때 알림을 받으려면 tableView: willDisplayCell:메소드 를 후크하십시오 .

- (void) reloadDisplayData
{
    isLoading =  YES;
    NSLog(@"Reload display with last index %d", lastIndex);
    [_tableView reloadData];
    if(lastIndex <= 0){
    isLoading = YES;
    //Notify completed
}

- (void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if(indexPath.row >= lastIndex){
    isLoading = NO;
    //Notify completed
}

1
이것이 작동하는지 확실하지 않습니다. 마지막 인덱스는 테이블 데이터의 끝 (예 : 100 개의 레코드)이지만 테이블은 화면에 보이는 것만 표시합니다 (예 : 8 개의 레코드).
Travis M.

10

그것이 제 해결책입니다. 100 % 작동하며 많은 프로젝트에서 사용됩니다. 간단한 UITableView 하위 클래스입니다.

@protocol MyTableViewDelegate<NSObject, UITableViewDelegate>
@optional
- (void)tableViewWillReloadData:(UITableView *)tableView;
- (void)tableViewDidReloadData:(UITableView *)tableView;
@end

@interface MyTableView : UITableView {
    struct {
        unsigned int delegateWillReloadData:1;
        unsigned int delegateDidReloadData:1;
        unsigned int reloading:1;
    } _flags;
}
@end

@implementation MyTableView
- (id<MyTableViewDelegate>)delegate {
    return (id<MyTableViewDelegate>)[super delegate];
}

- (void)setDelegate:(id<MyTableViewDelegate>)delegate {
    [super setDelegate:delegate];
    _flags.delegateWillReloadData = [delegate respondsToSelector:@selector(tableViewWillReloadData:)];
    _flags.delegateDidReloadData = [delegate    respondsToSelector:@selector(tableViewDidReloadData:)];
}

- (void)reloadData {
    [super reloadData];
    if (_flags.reloading == NO) {
        _flags.reloading = YES;
        if (_flags.delegateWillReloadData) {
            [(id<MyTableViewDelegate>)self.delegate tableViewWillReloadData:self];
        }
        [self performSelector:@selector(finishReload) withObject:nil afterDelay:0.0f];
    }
}

- (void)finishReload {
    _flags.reloading = NO;
    if (_flags.delegateDidReloadData) {
        [(id<MyTableViewDelegate>)self.delegate tableViewDidReloadData:self];
    }
}

@end

한 가지 예외를 제외 하면 Josh Brown의 솔루션 과 유사합니다 . performSelector 메소드에는 지연이 필요하지 않습니다. 아무리 오래 reloadData걸리 더라도 . 요청이 끝나면 tableViewDidLoadData:항상 실행됩니다 .tableViewdataSource cellForRowAtIndexPath

서브 클래스 UITableView를 원하지 않더라도 간단히 호출 할 수 있으며 [performSelector:@selector(finishReload) withObject:nil afterDelay:0.0f]테이블이 다시로드 된 직후 선택기가 호출됩니다. 그러나 selector는 다음을 호출 할 때마다 한 번만 호출되도록해야합니다 reloadData.

[self.tableView reloadData];
[self performSelector:@selector(finishReload) withObject:nil afterDelay:0.0f];

즐겨. :)


1
performSelector 호출을 사용하는 것은 훌륭합니다. 간단하고 작업, 고맙습니다
줄리아

이것은 절대적으로 굉장합니다. 나는 이것으로 며칠 동안 논쟁을 해왔다. 감사합니다!
David Carrico

@MarkKryzhanouski, iOS 9에서 테스트 했습니까?
Victor

@MarkKryzhanouski, 신속한 피드백에 감사드립니다! iOS 7 및 8에서 잘 작동합니다.
Victor

솔루션 performSelector또는 메인 스레드에서 실행하는 것은 iOS 9에서dispatch_asynch 작동하지 않습니다 .
Manuel

8

이것은 약간 다른 질문에 대한 답입니다. 언제 UITableView에게 전화 를 걸 었는지 알아야했습니다 cellForRowAtIndexPath(). 나는 layoutSubviews()(@Eric MORAND에게 감사드립니다) 서브 클래 싱 하고 델리게이트 콜백을 추가했습니다.

SDTableView.h :

@protocol SDTableViewDelegate <NSObject, UITableViewDelegate>
@required
- (void)willReloadData;
- (void)didReloadData;
- (void)willLayoutSubviews;
- (void)didLayoutSubviews;
@end

@interface SDTableView : UITableView

@property(nonatomic,assign) id <SDTableViewDelegate> delegate;

@end;

SDTableView.m :

#import "SDTableView.h"

@implementation SDTableView

@dynamic delegate;

- (void) reloadData {
    [self.delegate willReloadData];

    [super reloadData];

    [self.delegate didReloadData];
}

- (void) layoutSubviews {
    [self.delegate willLayoutSubviews];

    [super layoutSubviews];

    [self.delegate didLayoutSubviews];
}

@end

용법:

MyTableViewController.h :

#import "SDTableView.h"
@interface MyTableViewController : UITableViewController <SDTableViewDelegate>
@property (nonatomic) BOOL reloadInProgress;

MyTableViewController.m :

#import "MyTableViewController.h"
@implementation MyTableViewController
@synthesize reloadInProgress;

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

    if ( ! reloadInProgress) {
        NSLog(@"---- numberOfSectionsInTableView(): reloadInProgress=TRUE");
        reloadInProgress = TRUE;
    }

    return 1;
}

- (void)willReloadData {}
- (void)didReloadData {}
- (void)willLayoutSubviews {}

- (void)didLayoutSubviews {
    if (reloadInProgress) {
        NSLog(@"---- layoutSubviewsEnd(): reloadInProgress=FALSE");
        reloadInProgress = FALSE;
    }
}

참고 :UITableView 이것은 이미 위임 속성을 가리키는 하위 클래스이므로 MyTableViewController다른 속성 을 추가 할 필요가 없습니다. "@dynamic delegate"는 컴파일러에게이 속성을 사용하도록 지시합니다. (다음은 이것을 설명하는 링크입니다 : http://farhadnoorzay.com/2012/01/20/objective-c-how-to-add-delegate-methods-in-a-subclass/ )

새 클래스 를 사용하려면 의 UITableView속성을 MyTableViewController변경해야합니다 SDTableView. 이것은 Interface Builder Identity Inspector에서 수행됩니다. UITableView내부를 선택 UITableViewController하고 "Custom Class"를로 설정합니다 SDTableView.


MyTableViewController를 SDTableView의 대리자로 설정하는 위치는 어디입니까? 수퍼 클래스에 이미 해당 이름 (UITableView.delegate)의 속성이있는 경우 SDTableView에 "delegate"라는 이름의 속성을 설정할 수있는 이유는 무엇입니까? 속성이 "UITablewView"유형이고 객체 (SDTableView의 인스턴스)가 "SDTableView"유형 인 경우 사용자 지정 SDTableView를 MyTableViewController.tableView 속성에 어떻게 연결합니까? 나는 같은 문제와 싸우고있다. 그래서 나는 이러한 문제들에 대한 해결책이 있기를 희망한다. :)
Earl Grey

Symmetric (SDTableView) 코드에서 didLayoutSubviews 대신 didReloadData에서 reloadInProgress를 FALSE로 설정하면 안됩니까? reloadData는 layoutSubviews 이후에 호출되고로드는 reloadData가 완료되기 전에 수행되지 않아야하기 때문입니다.
tzuchien.chiu

이것은 iOS 8에서 작동하지 않으며 iPrabu의 답변 을 통합해야했습니다 .
Stunner

6

나는 변화에 대한 알림을받을 비슷한 것을 발견했다 contentSize의를 TableView. contentSize도 데이터로드에 따라 변경되기 때문에 여기서도 작동해야한다고 생각합니다.

이 시도:

에서 viewDidLoad쓰기,

[self.tableView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld | NSKeyValueObservingOptionPrior context:NULL];

이 메소드를 viewController에 추가하십시오.

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"contentSize"]) {
        DLog(@"change = %@", change.description)

        NSValue *new = [change valueForKey:@"new"];
        NSValue *old = [change valueForKey:@"old"];

        if (new && old) {
            if (![old isEqualToValue:new]) {
                // do your stuff
            }
        }


    }
}

변경 확인시 약간의 수정이 필요할 수 있습니다. 이것은 나를 위해 일했습니다.

건배! :)


1
매우 영리한. 나를 위해 완벽하게 작동합니다. 공유해 주셔서 감사합니다!
DZenBot 2014-06-02

2
우아한! 내가 추가 할 유일한 것은 자신과 관찰자를 제거해야한다는 것입니다 (아마도 -dealloc 메서드에서). 또는 자신을 관찰자로 추가 -viewWillAppear하고 -viewWillDisapear메소드 에서 자신을 제거하십시오 .
Loozie 2015-08-26

2

해킹이지만 가능한 해결책은 다음과 같습니다.

[self.tableView reloadData];
[self performSelector:@selector(scrollTableView) withObject:nil afterDelay:0.3];

귀하의 -scrollTableView방법이 -scrollRectToVisible:animated:. 물론 위의 코드에서 0.3에서 작동하는 것으로 보이는 지연을 구성 할 수 있습니다. 예, 엄청나게 해키하지만 iPhone 5 및 4S에서 작동합니다 ...


2
"해키"처럼 보일 수 있지만 이것은 실제로 스크롤링에 대한 표준 접근 방식입니다. 다음 실행 주기로 연기합니다. 지연 시간을 0으로 변경합니다. 왜냐하면 그게 잘 작동하고 지연 시간이 적기 때문입니다.
phatmann

지연이 0으로 설정된 상태에서 작동하지 않았습니다. 0.3은 내가 갈 수 있고 여전히 데이터를 얻을 수있는 최저치였습니다.
Josh Brown

@phatmann 이것은 나를 위해 일했습니다. 또한 지연 시간에 0을 사용할 수있었습니다. 두 분 모두 감사합니다.
mcphersonjr 2014 년

1

나는 내가 믿는 비슷한 것을 가지고 있었다. 오프셋이 복원되었는지 여부를 알려주는 인스턴스 변수로 BOOL을 추가하고 -viewWillAppear:. 복원되지 않은 경우 해당 방법으로 복원하고 오프셋을 복구했음을 나타내도록 BOOL을 설정합니다.

그것은 일종의 해킹이며 아마도 더 잘 할 수 있지만 이것은 현재 저에게 효과적입니다.


예, 문제는 viewWillAppear가 (적어도 내 시나리오에서는) 너무 이른 것처럼 보인다는 것입니다. viewWillAppear에서 오프셋을 복원하려고 시도해도 reloadData를 먼저 호출하는 해킹을 추가하지 않는 한 아무 작업도 수행되지 않습니다. 내가 이해하는대로 viewWillAppear / viewDidAppear는 실제로 나타나는 테이블 뷰 자체 만 참조합니다. 뷰의 테이블 셀이 열거되었는지 또는 채워 졌는지 여부에 대한 주장을하지 않습니다.이 작업은 복구하기 전에 발생해야합니다. 오프셋, 그렇지 않으면 빈 뷰에서 오프셋을 복구 할 것입니다 (그리고 이것이 작동하지 않는 이유를 이해합니다!).
kennethmac2000

그러나 아마도 viewWillAppear 내에서 reloadData를 호출하여 먼저 테이블 셀을 강제로로드한다는 것을 의미했을 수 있습니까?
kennethmac2000

아니요, 재 장전을 강요하지 않습니다. 문제가 발생했을 때 오프셋을 복원하려고했지만 -viewDidLoad(물론 발생해야하는 위치) 오프셋 애니메이션을 설정할 때만 작동했습니다. 오프셋 설정을 이동하면 -viewWillAppear:효과가 있었지만 한 번만 설정하려면 플래그를 유지해야했습니다. 테이블 뷰가 뷰에 추가되면 데이터를 다시로드한다고 가정합니다 -loadView. 보기로드시 데이터를 사용할 수 있습니까? 아니면 별도의 스레드에서로드되고 있습니까?
Joost

좋아, 아마도 여기에서 내 이해를 도울 수 있습니다. 이것이 UITableView가 구축 될 때 호출 순서를 이해하는 방법입니다. 1) viewDidLoad가 먼저 실행됩니다. 이것은 UITableView가 메모리에로드되었음을 나타냅니다. 2) viewWillAppear가 불 옆에 있습니다. 이는 UITableView가 표시되지만 모든 표시되는 UITableViewCell 개체가 완전히 인스턴스화 / 완료된 렌더링 일 필요는 없음을 나타냅니다.
kennethmac2000

2
그리고 위의 모든 것이 사실입니다. 그러면 질문은 UITableView가 데이터 소스에서 스크롤 요청 (예 : scrollRectToVisible : animated : call) 을 보장 하기 위해 데이터 소스로부터 충분한 정보를 얻었을 때 알아 내기위한 해킹이 아닌 옵션이 무엇인지입니다. ) 실제로 작동합니까 (아무것도하지 않음)?
kennethmac2000

1

셀 내용을 업데이트하려는 것처럼 들리지만 셀 삽입 및 삭제를 수반 할 수있는 갑작스러운 점프가 없습니다.

이에 대한 몇 가지 기사가 있습니다. 이것은 하나입니다.

스크롤 뷰의 픽셀 완벽한 설정을 위해 scrollRectToVisible : animated : 대신 setContentOffset : animated :를 사용하는 것이 좋습니다.


1

다음 논리를 시도 할 수 있습니다.

-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyIdentifier"];

    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"MyIdentifier"];
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
    }

    if ( [self chkIfLastCellIndexToCreate:tableView :indexPath]){
        NSLog(@"Created Last Cell. IndexPath = %@", indexPath);
        //[self.activityIndicator hide];
        //Do the task for TableView Loading Finished
    }
    prevIndexPath = indexPath;

    return cell;
}



-(BOOL) chkIfLastCellIndexToCreate:(UITableView*)tableView : (NSIndexPath *)indexPath{

    BOOL bRetVal = NO;
    NSArray *visibleIndices = [tableView indexPathsForVisibleRows];

    if (!visibleIndices || ![visibleIndices count])
        bRetVal = YES;

    NSIndexPath *firstVisibleIP = [visibleIndices objectAtIndex:0];
    NSIndexPath *lastVisibleIP = [visibleIndices objectAtIndex:[visibleIndices count]-1];

    if ((indexPath.row > prevIndexPath.row) && (indexPath.section >= prevIndexPath.section)){
        //Ascending - scrolling up
        if ([indexPath isEqual:lastVisibleIP]) {
            bRetVal = YES;
            //NSLog(@"Last Loading Cell :: %@", indexPath);
        }
    } else if ((indexPath.row < prevIndexPath.row) && (indexPath.section <= prevIndexPath.section)) {
        //Descending - scrolling down
        if ([indexPath isEqual:firstVisibleIP]) {
            bRetVal = YES;
            //NSLog(@"Last Loading Cell :: %@", indexPath);
        }
    }
    return bRetVal;
}

그리고 reloadData를 호출하기 전에 prevIndexPath를 nil로 설정하십시오. 처럼:

prevIndexPath = nil;
[mainTableView reloadData];

NSLogs로 테스트했는데이 논리는 괜찮은 것 같습니다. 필요에 따라 사용자 정의 / 개선 할 수 있습니다.


0

마침내 나는 내 코드가 이것으로 작동하도록 만들었다.

[tableView scrollToRowAtIndexPath:scrollToIndex atScrollPosition:UITableViewScrollPositionTop animated:YES];

처리해야 할 것들이 거의 없었습니다.

  1. " - (UITableViewCell *)MyTableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath" 내에서 호출
  2. "scrollToRowAtIndexPath"메시지가 UITableView의 관련 인스턴스로 전송되는지 확인하십시오.이 경우에는 확실히 MyTableview입니다.
  3. 제 경우에는 UIView는 UITableView의 인스턴스를 포함하는 뷰입니다.
  4. 또한 이것은 모든 셀 부하에 대해 호출됩니다. 따라서 "scrollToRowAtIndexPath"를 두 번 이상 호출하지 않도록 "cellForRowAtIndexPath"내에 논리를 배치하십시오.

이 부분이 두 번 이상 호출되지 않도록합니다. 그렇지 않으면 스크롤을 잠급니다.
smile.al.d.way 2010 년

이것은 효과가있을 수 있지만 확실히 우아하지 않으며 내가 찾고있는 해결책이 아닙니다. 불행하게도, -reloadData 실제로 데이터를 가져 오는 완료 여부를 결정하기 위해 더 좋은 방법이있을 것 같지 않습니다 ...
조쉬 브라운

0

모든 데이터가로드 될 때이 메서드에서 tableview의 크기를 조정하거나 콘텐츠 크기를 설정할 수 있습니다.

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    tableView.frame =CGRectMake(tableView.frame.origin.x, tableView.frame.origin.y, tableView.frame.size.width, tableView.contentSize.height);
}

0

나는 단지 반복 예약 타이머를 실행하고 tableHeaderView 높이 (테이블에 행 내용이 있음을 의미) 일 때 테이블의 contentSize가 더 클 때만 무효화합니다. C # (monotouch)의 코드이지만 아이디어가 명확하기를 바랍니다.

    public override void ReloadTableData()
    {
        base.ReloadTableData();

        // don't do anything if there is no data
        if (ItemsSource != null && ItemsSource.Length > 0)
        {
            _timer = NSTimer.CreateRepeatingScheduledTimer(TimeSpan.MinValue, 
                new NSAction(() => 
                {
                    // make sure that table has header view and content size is big enought
                    if (TableView.TableHeaderView != null &&
                        TableView.ContentSize.Height > 
                            TableView.TableHeaderView.Frame.Height)
                    {
                        TableView.SetContentOffset(
                            new PointF(0, TableView.TableHeaderView.Frame.Height), false);
                        _timer.Invalidate();
                        _timer = null;
                    }
                }));
        }
    }

0

UITableView layoutSubviews테이블 뷰에 내용이 표시되기 직전에 호출 되지 않습니까? 테이블 뷰가 데이터로드를 마치면 호출되는 것으로 나타났습니다. 해당 방향으로 조사해야 할 수도 있습니다.


0

iOS 6 이후부터 UITableview위임 메서드는 다음을 호출했습니다.

-(void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section

테이블이 성공적으로 다시로드되면 실행됩니다. 이 방법에서 필요에 따라 사용자 정의를 수행 할 수 있습니다.


0

내가 Swift에서 찾은 최고의 솔루션

extension UITableView {
    func reloadData(completion: ()->()) {
        self.reloadData()
        dispatch_async(dispatch_get_main_queue()) {
            completion()
        }
    }
}

-1

왜 그냥 연장하지 않습니까?

@interface UITableView(reloadComplete)
- (void) reloadDataWithCompletion:( void (^) (void) )completionBlock;
@end

@implementation UITableView(reloadComplete)
- (void) reloadDataWithCompletion:( void (^) (void) )completionBlock {
    [self reloadData];
    if(completionBlock) {
        completionBlock();
    }
}
@end

끝으로 스크롤 :

[self.table reloadDataWithCompletion:^{
    NSInteger numberOfRows = [self.table numberOfRowsInSection:0];
    if (numberOfRows > 0)
    {
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:numberOfRows-1 inSection:0];
        [self.table scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:NO];
    }
}];

많은 데이터로 테스트되지 않음

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.