UITableView에서 데이터 요청이 완료되면 알림을 받으시겠습니까?
언제인지 알 수 있는 방법이 있습니까?UITableView
데이터 소스의 데이터 요청을 마쳤습니까?
아무 것도 없습니다.viewDidLoad
/viewWillAppear
/viewDidAppear
뷰 view controller)의(methods of the associated view controller()UITableViewController
는 모두 여기서 는 모두 너무 일찍 발사되기 때문에 여기에 유용합니다.이들 중 어느 것도(완전히 이해할 수 있는) 당분간 데이터 소스에 대한 쿼리가 완료되었음을 보장하지 않습니다(예: 보기가 스크롤될 때까지).
한 가지 해결 방법은 전화를 거는 것입니다.reloadData
viewDidAppear
이후로, 언제부터.reloadData
를 반환합니다. 테이블 보기는 당분간 필요한 만큼 데이터 소스 쿼리를 완료할 수 있습니다.
한 정보를 으로 한 번, 한 번) 에 다소으로 보입니다.reloadData
call할 때 합니다.call).
이 작업을 수행하려는 이유는 파일의 스크롤 위치를 유지하고 싶기 때문입니다.UITableView
가장 가까운 행뿐만 아니라 픽셀 레벨로 바로 내려갑니다.
위치를 할 때 ()scrollRectToVisible:animated:
가 있어야 . 뷰에 충분한 데이터가 있어야 . 그렇지 않으면scrollRectToVisible:animated:
은 아무 것도 하지 의 위치에 합니다).viewDidLoad
,viewWillAppear
또는viewDidAppear
).
답변이 작성된 이후 UITableView 구현에 일부 변경 사항이 적용되었기 때문에 이 답변은 더 이상 작동하지 않는 것 같습니다.이 의견 참조: UITableView에서 데이터 요청이 완료되면 알림을 받으시겠습니까?
며칠 동안 이 문제를 가지고 놀았는데 하위 분류가UITableView
의reloadData
좋은 접근법입니다.
- (void)reloadData {
NSLog(@"BEGIN reloadData");
[super reloadData];
NSLog(@"END reloadData");
}
reloadData
테이블이 데이터 다시 로드를 완료하기 전에 종료되지 않습니다.두 래서가 때 두번째.NSLog
가 실행되면 테이블 보기에서 데이터 요청이 완료됩니다.
하위분습다니했류를 하위 했습니다.UITableView
전후에 대리인에게 방법을 보냅니다.reloadData
그것은 매력적으로 작동합니다.
저는 제 앱에 같은 시나리오가 있었고 여기에 언급된 다른 답변이 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)
})
이게 어떻게 작동하는지.
기본적으로 당신이 다시 로드할 때 메인 스레드가 사용 중이 되어 우리가 디스패치 비동기 스레드를 할 때 블록은 메인 스레드가 완료될 때까지 대기합니다.따라서 테이블 뷰가 완전히 로드되면 메인 스레드가 완료되고 메소드 블록이 발송됩니다.
iOS7과 iOS8에서 테스트를 거쳤으며, 매우 잘 작동합니다;)
iOS9용 업데이트: iOS9도 잘 작동합니다.저는 github을 POC로 샘플 프로젝트를 만들었습니다.https://github.com/ipraba/TableReloadingNotifier
제 시험 스크린샷을 여기에 첨부합니다.
테스트 환경: Xcode7의 iOS9 iPhone6 시뮬레이터
편집: 이 답변은 실제로 해결책이 아닙니다.처음에는 재로드가 매우 빠르게 발생할 수 있기 때문에 작동하는 것처럼 보이지만, 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
}];
데이터를 다시 로드합니다. 보이는 셀에 대한 데이터만 요청합니다.될 때 를 후크하십시오.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
}
그게 제 해결책입니다.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
한 가지 예외를 제외하고는 조쉬 브라운의 솔루션과 유사합니다.performSelector 메서드는 지연이 필요하지 않습니다.시간이 얼마나 걸리든 간에 상관없이. tableViewDidLoadData:
질문이 cellForRowAtIndexPath
끝나면 항상 실행됩니다.
하위 클래스를 원하지 않더라도UITableView
간단히 전화할 수 있습니다.[performSelector:@selector(finishReload) withObject:nil afterDelay:0.0f]
테이블을 다시 로드한 후 바로 선택기가 호출됩니다. 한 .reloadData
:
[self.tableView reloadData];
[self performSelector:@selector(finishReload) withObject:nil afterDelay:0.0f];
맛있게 드세요 :)
다음은 약간 다른 질문에 대한 대답입니다.인지 .UITableView
또한 전화하는 것을 마쳤습니다.cellForRowAtIndexPath()
하위 분류했습니다.layoutSubviews()
MORAND) 콜백을 ( @Eric MORAND) 그리인콜추가습니다했을백대리고고워요마▁(다▁a니(eric▁added습▁delegate▁call▁@back.
SD 테이블 보기.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
용도:
내 테이블 보기 컨트롤러입니다.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
클래스. 인터페이스 작성기 ID 검사기에서 수행됩니다.다음을 선택합니다.UITableView
의내에의 UITableViewController
"사용자 지정 클래스"를 다음으로 설정합니다.SDTableView
.
변경 알림을 받기 위해 비슷한 것을 찾았습니다.contentSize
TableView
contentSize도 때문에 합니다. contentSize 데 로 딩 따 라 바 뀌 때 여 문 생 다 니 기 도 야 합 해 각 작 동 한 고 다 서 에 기 도 에 이 터 ▁i ▁as content 니 다 합 ▁here ▁should size ▁content size ▁work 생 ▁with각
사용해 보십시오.
viewDidLoad
쓰고, 글을 쓰고,
[self.tableView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld | NSKeyValueObservingOptionPrior context:NULL];
다음 방법을 뷰 컨트롤러에 추가합니다.
- (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
}
}
}
}
변경 사항을 확인하기 위해 약간의 수정이 필요할 수 있습니다.하지만 이것은 저에게 효과가 있었습니다.
건배! :)
해킹이지만 가능한 해결책은 다음과 같습니다.
[self.tableView reloadData];
[self performSelector:@selector(scrollTableView) withObject:nil afterDelay:0.3];
당신의 의너어에가 ?-scrollTableView
▁view▁with▁the▁table로 표 보기를 .-scrollRectToVisible:animated:
그리고 물론, 위의 코드에서 0.3에서 당신에게 효과가 있는 것처럼 보이는 것으로 지연을 구성할 수 있습니다.도 안되게 촌스럽긴 , 제5와 4S에서 합니다... ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ 5와 4S에서 작동합니다.
제가 믿는 비슷한 것이 있었습니다.하였습니다.-viewWillAppear:
복원되지 않은 경우에는 해당 방법으로 복원하고 오프셋을 복구했음을 나타내도록 BOOL을 설정합니다.
이것은 일종의 해킹이고 아마도 더 잘 할 수 있을 것입니다. 하지만 현재로서는 이것이 저에게 효과가 있습니다.
셀 내용을 업데이트하려는 것처럼 들리지만 셀 삽입 및 삭제와 함께 발생할 수 있는 갑작스러운 점프는 없습니다.
그것을 하는 것에 대한 몇 가지 기사들이 있습니다.이거 하나.
스크롤 보기의 픽셀 단위 설정을 위해 스크롤 대신 setContentOffset:animated:를 사용하는 것이 좋습니다.
다음과 같은 논리를 시도할 수 있습니다.
-(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를 0으로 설정합니다.예:
prevIndexPath = nil;
[mainTableView reloadData];
NSLogs로 테스트를 해봤는데, 이 논리는 괜찮은 것 같습니다.필요에 따라 사용자 지정/개선할 수 있습니다.
마침내 나는 이것으로 내 코드를 작동시켰습니다.
[tableView scrollToRowAtIndexPath:scrollToIndex atScrollPosition:UITableViewScrollPositionTop animated:YES];
처리해야 할 것이 몇 가지 있었습니다.
- "안에 그것을 부름.
- (UITableViewCell *)MyTableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
" - "ScrollToRowAt"를 확인하십시오.IndexPath" 메시지가 관련된 UITableView 인스턴스(이 경우 MyTableView)로 전송됩니다.
- 내 경우 UIView는 UITableView의 인스턴스를 포함하는 뷰입니다.
- 또한 모든 셀 로드에 대해 호출됩니다.따라서 "cellForRowAt" 내부에 논리를 작성합니다."scrollToRowAt" 호출을 피하기 위한 IndexPath"인덱스 경로"가 두 번 이상 있습니다.
모든 데이터가 로드될 때 다음 방법으로 테이블 보기의 크기를 조정하거나 내용 크기를 설정할 수 있습니다.
- (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);
}
반복 예약 타이머를 실행하고 테이블의 contentSize가 테이블일 때 더 클 때만 비활성화합니다.머리글 보기 높이(표에 행 내용이 있음을 의미).코드는 C#(모노터치)이지만, 아이디어가 명확하기를 바랍니다.
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;
}
}));
}
}
아닌가요?UITableView
layoutSubviews
테이블 보기에 내용이 표시되기 직전에 호출하시겠습니까?테이블 뷰가 데이터 로드를 완료하면 호출된다는 것을 알게 되었습니다. 해당 방향으로 조사해야 할 것 같습니다.
6 6은UITableview
대리자 메서드 호출:
-(void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
테이블이 다시 로드되면 실행됩니다.이 방법에서 필요에 따라 사용자 지정을 수행할 수 있습니다.
스위프트에서 찾은 최고의 솔루션
extension UITableView {
func reloadData(completion: ()->()) {
self.reloadData()
dispatch_async(dispatch_get_main_queue()) {
completion()
}
}
}
왜 그냥 연장하지 않습니까?
@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];
}
}];
많은 데이터로 테스트되지 않음
언급URL : https://stackoverflow.com/questions/1483581/get-notified-when-uitableview-has-finished-asking-for-data
'programing' 카테고리의 다른 글
javascript에서 Firebase fire store에 저장하기 위한 날짜를 타임스탬프로 변환 (0) | 2023.06.06 |
---|---|
python numpy ValueError: 피연산자를 셰이프와 함께 브로드캐스트할 수 없습니다. (0) | 2023.06.06 |
조건에 따라 목록을 분할(분할, 분할)하려면 어떻게 해야 합니까? (0) | 2023.06.06 |
Python에서 소스 파일 이름과 줄 번호를 기록하는 방법 (0) | 2023.06.06 |
Firestore 문서에서 필드를 삭제하는 방법은 무엇입니까? (0) | 2023.06.06 |