जब UITableView ने डेटा मांगना समाप्त कर लिया हो तो सूचित करें?


108

क्या यह पता लगाने का कोई तरीका है कि किसी UITableViewने अपने डेटा स्रोत से डेटा मांगना कब समाप्त किया है?

में से कोई भी viewDidLoad/ viewWillAppear/ viewDidAppearसंबद्ध दृश्य नियंत्रक (के तरीकों UITableViewController) वे के रूप में सभी आग बहुत जल्दी यहाँ उपयोग की कर रहे हैं। उनमें से कोई भी (पूरी तरह से समझ में नहीं आता) गारंटी देता है कि डेटा स्रोत के लिए क्वेरीज़ समय समाप्त हो गया है (उदाहरण के लिए, जब तक कि दृश्य स्क्रॉल नहीं किया जाता है)।

एक वैकल्पिक हल मैं पाया है कॉल करने के लिए है reloadDataमें viewDidAppear, के बाद से, जब reloadDataरिटर्न, तालिका दृश्य है जितना डेटा स्रोत क्वेरी करने के रूप में यह समय से किया जा रहा के लिए की जरूरत है समाप्त कर दिया है की गारंटी।

हालाँकि, ऐसा लगता है कि यह बुरा है, क्योंकि मुझे लगता है कि यह डेटा स्रोत को एक ही जानकारी के लिए दो बार (एक बार स्वचालित रूप से, और एक बार reloadDataकॉल के कारण) पूछा जाता है जब यह पहली बार लोड होता है।

कारण यह है कि मैं यह करना चाहता हूं कि मैं स्क्रॉल की स्थिति को संरक्षित करना चाहता हूं UITableView- लेकिन पिक्सेल स्तर के ठीक नीचे, न केवल निकटतम पंक्ति में।

स्क्रॉल स्थिति को पुनर्स्थापित करते समय (उपयोग करके scrollRectToVisible:animated:), मुझे पहले से ही इसमें पर्याप्त डेटा रखने के लिए तालिका दृश्य की आवश्यकता है, या फिर scrollRectToVisible:animated:विधि कॉल कुछ भी नहीं करती है (जो कि यदि आप कॉल को किसी भी viewDidLoad, viewWillAppearया स्वयं के स्थान पर रखते हैं तो क्या होता है viewDidAppear)।


ऐसा लगता है कि आप इस stackoverflow.com/a/11672379/2082172 के समान कुछ देख रहे हैं ।
तैमूर कुचक्रोव

मेरे अनुभव में, UITableView कॉल को पुनः लोड करने के लिए कैश कर सकता है, जैसे कि पंक्तियों और अन्य चीजों को सम्मिलित / हटाने के लिए कॉल कैश करता है। UITableView डेटा स्रोत प्रतिनिधि को कॉल करेगा जब वह तैयार हो जाता है, जो CPU उपयोग और अन्य चीजों पर निर्भर करता है।
वॉल्ट सेलर्स

जवाबों:


61

उत्तर लिखे जाने के बाद से UITableView कार्यान्वयन में किए गए कुछ परिवर्तनों के कारण यह उत्तर अब और काम नहीं करता है। यह टिप्पणी देखें: जब UITableView ने डेटा मांगना समाप्त कर लिया हो तो सूचित करें?

मैं कुछ दिनों के लिए इस समस्या के साथ खेल रहे हैं और लगता है कि उपवर्गीकरण किया गया है UITableViewकी reloadDataसबसे अच्छा तरीका है:

- (void)reloadData {

    NSLog(@"BEGIN reloadData");

    [super reloadData];

    NSLog(@"END reloadData");

}

reloadDataतालिका समाप्त होने से पहले उसका डेटा फिर से लोड नहीं होता है। इसलिए, जब दूसरा NSLogनिकाल दिया जाता है, तो तालिका दृश्य वास्तव में डेटा के लिए पूछना समाप्त कर देता है।

मैंने UITableViewपहले और बाद में प्रतिनिधि को तरीकों को भेजने के लिए उप-वर्ग किया है reloadData। यह एक सम्मोहन की तरह काम करता है।


2
कहना होगा, यह सबसे अच्छा समाधान है। बस इसे लागू किया और, जैसा आप कहते हैं, यह एक आकर्षण की तरह काम करता है। धन्यवाद!
सिद्धांत

2
@EricMORAND आप कहते हैं कि "रीलोडाटा समाप्त नहीं होता है इससे पहले कि तालिका अपना डेटा पुनः लोड कर ले।" क्या आप स्पष्ट कर सकते हैं कि आपका क्या मतलब है? मुझे लगता है कि reloadDataतुरंत लौटता है और मुझे "END reloadData" दिखाई देता है इससे पहले कि कोशिकाओं को वास्तव में पुनः लोड किया जाता है (यानी UITableViewDataSourceतरीकों को बुलाया जाने से पहले )। मेरा प्रयोग आप जो कहते हैं, उसके ठीक विपरीत प्रदर्शित करता है। मुझे गलत समझना चाहिए कि आप क्या कहना चाह रहे हैं।
रॉब

3
क्या एरिक का जवाब समान नहीं है (लागू नहीं करना) (ओवरराइडिंग नहीं करना) रीलोडेडटा, कॉलिंग रीलोडेडटा (जिसे अनिवार्य रूप से [सुपर रीलोडेटा] कहा जाएगा, और फिर इसे कॉल करने के बाद, क्या आप इसके पूर्ण होने पर जो सामान चाहते हैं?
नीरव भट्ट

5
एक बार फिर से लोड होने से पहले पुनः लोड करने की प्रक्रिया को पूरा किया। लेकिन Apple ने किसी समय इसे बदल दिया। अब UITableView वर्ग सभी पंक्ति सम्मिलित करने और कॉल हटाने के साथ पुनः लोड कॉल को कैश कर सकता है। यदि आप UITableView के लिए @interface घोषणा को देखते हैं, तो आपको NSMutableArray सदस्य _reloadItems के ठीक नीचे _insertItems और _deleteItems मिलेगा। (मुझे इस बदलाव के कारण विरासत में मिला कोड पुनः प्राप्त करना पड़ा है।)
वॉल्ट सेलर्स

3
[super reloadData]मेरे लिए काम करने के बाद मुख्य कतार पर एक ब्लॉक में पूरा कोड पोस्ट करना dispatch_async(dispatch_get_main_queue(), ^{NSLog(@"reload complete");});:। यह मूल रूप से छलांग लगाता है कि ब्लॉक ब्लॉक को तालिका दृश्य द्वारा पोस्ट किया जाता है reloadData
टिमोथी मूस

53

मेरे ऐप में मेरे पास एक ही परिदृश्य था और मैंने सोचा कि आप लोगों को अपना उत्तर दूंगा क्योंकि यहाँ वर्णित अन्य उत्तर मेरे लिए 7 और बाद में काम नहीं करते हैं।

अंत में केवल यही एक चीज है जिसने मेरे लिए काम किया।

[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)

})

तो यह कैसे काम करता है।

मूल रूप से जब आप एक पुनः लोड करते हैं तो मुख्य धागा उस समय व्यस्त हो जाता है जब हम एक डिस्पैच async धागा करते हैं, ब्लॉक तब तक इंतजार करेगा जब तक कि मुख्य धागा समाप्त नहीं हो जाता। इसलिए जब एक बार तालिका का विवरण पूरी तरह से लोड हो जाता है तो मुख्य धागा समाप्त हो जाएगा और इसलिए यह हमारी विधि ब्लॉक को भेज देगा

IOS7 और iOS8 में परीक्षण किया गया है और यह बहुत बढ़िया काम करता है;)

IOS9 के लिए अपडेट: यह ठीक काम करता है iOS9 भी है। मैंने एक पीओसी के रूप में जीथब में एक नमूना परियोजना बनाई है। https://github.com/ipraba/TableReloadingNotifier

मैं यहाँ अपने परीक्षण का स्क्रीनशॉट संलग्न कर रहा हूँ।

परीक्षण पर्यावरण: Xcode7 से iOS9 iPhone6 ​​सिम्युलेटर

यहां छवि विवरण दर्ज करें


8
सबसे अच्छा जवाब मुझे मिल गया है!
निकोले शुबेनकोव

@ क्या मैंने iOS9 में टेस्ट किया और यह ठीक काम करता है। क्या आप कृपया github.com/ipraba/TableReloadingNotifier
iPrabu

यह मेरे एमुलेटर पर ठीक काम करता है लेकिन वास्तविक डिवाइस पर काम नहीं करता है। क्या किसी और को भी ये समस्या है?
sosale151

1
यह समाधान आखिरकार मेरे लिए काम करता है! यह iOS 9 पर
मजबूत

1
मैंने रियल डिवाइस, एक iPhone 6s पर परीक्षण किया है। यह ठीक भी काम करता है।
मजबूत

25

EDIT: यह उत्तर वास्तव में एक समाधान नहीं है। यह संभवत: पहली बार में काम करता प्रतीत होता है क्योंकि पुनः लोडिंग बहुत तेजी से हो सकती है, लेकिन वास्तव में पूरा होने वाले ब्लॉक को जरूरी नहीं कहा जाता है क्योंकि डेटा पूरी तरह से लोड होने के बाद फिर से लोड हो जाता है - क्योंकि रीलोडेडटा ब्लॉक नहीं करता है। आपको शायद बेहतर समाधान की तलाश करनी चाहिए।

@ 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
मुझे पर्याप्त ब्लॉक नहीं मिल रहे हैं। जब आपको एक अच्छा ब्लॉक मिला है, तो आपको एक प्रतिनिधि की आवश्यकता है!
बंदीजपायसा

मुझे यह पसंद है, लेकिन उस समय के बारे में क्या है जब सिस्टम पुनः लोड करता है (), उदाहरण के लिए जब तालिका पहली बार प्रदर्शित होती है?
सममित

12
यह समाधान Completition ब्लॉक cellForRowAtIndexPath से पहले निष्पादन शुरू होता नहीं है
zvjerka24

1
यह काम नहीं करेगा; reloadData एक अवरोधन विधि नहीं है। रीलोडेटा कॉल करने के तुरंत बाद इस कोड को कहा जाता है , भले ही कोशिकाओं को अभी तक लोड नहीं किया गया हो। इसके अलावा, इस कोड को देखें, और आप देखेंगे कि आप पुनः लोड होने के बाद अपना कोड डाल सकते हैं
19-22 को कोलिंडा

1
यह मेरे लिए एक मामूली बदलाव के साथ काम करता है। पूर्ण ब्लॉक को सीधे कॉल करने के बजाय, इसे मुख्य कतार पर पोस्ट किए गए ब्लॉक में कॉल करें dispatch_async(dispatch_get_main_queue(), ^{completionBlock();});:। यह मूल रूप से छलांग में तालिका दृश्य द्वारा पोस्ट किए गए ब्लॉक मेंढक है reloadData
तीमुथियुस Moose

11

रीलोडाटा सिर्फ दृश्य कोशिकाओं के लिए डेटा के लिए पूछ रहा है। कहते हैं, जब आपकी तालिका के निर्दिष्ट हिस्से को लोड किया जाता है, तो कृपया सूचित करें, कृपया 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 रिकॉर्ड)।
ट्रैविस एम।

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

यह एक अपवाद के साथ जोश ब्राउन के समाधान के समान है। PerformSelector विधि में किसी भी देरी की आवश्यकता नहीं है। चाहे जितना समय लगे reloadDatatableViewDidLoadData:हमेशा आग जब tableViewखत्म पूछ रहा है dataSource cellForRowAtIndexPath

यहां तक ​​कि अगर आप उप-वर्ग नहीं करना चाहते हैं तो आप UITableViewबस कॉल कर सकते हैं [performSelector:@selector(finishReload) withObject:nil afterDelay:0.0f]और टेबल को फिर से लोड करने के बाद आपके चयनकर्ता को सही कहा जाएगा। लेकिन आपको यह सुनिश्चित करना चाहिए कि चयनकर्ता को केवल एक बार कॉल करने के लिए कहा जाता है reloadData:

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

का आनंद लें। :)


1
PerformSelector कॉल का उपयोग करना शानदार है। सिंपल एंड वर्किंग, थैंक्स
जूलिया

यह बिल्कुल भयानक है। मैं इसके लिए दिनों से संघर्ष कर रहा हूं। धन्यवाद!
डेविड कार्रिको

@MarkKryzhanouski, क्या आपने iOS 9 पर परीक्षण किया है?
विक्टर

@MarkKryzhanouski, शीघ्र प्रतिक्रिया के लिए धन्यवाद! IOS 7 और 8. पर शानदार काम करता है
विक्टर

आईओएस 9 पर काम न करने वाले performSelectorमुख्य धागे पर समाधान या निष्पादन । dispatch_asynch
मैनुअल

8

यह थोड़ा अलग सवाल का जवाब है: मुझे यह जानने की जरूरत है कि UITableViewफोन करना कब समाप्त हुआ cellForRowAtIndexPath()। मैंने layoutSubviews()उपविभाजित किया (धन्यवाद @ EOR 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 प्रतिनिधि" कंपाइलर को इस संपत्ति का उपयोग करने के लिए कहता है। (यहां यह वर्णन करने वाला एक लिंक है: http://farhadnoorzay.com/2012/01/20/objective-c-how-to-add-delegate-methods-in-a-subclass/ )

UITableViewमें संपत्ति MyTableViewControllerचाहिए नई उपयोग करने के लिए परिवर्तित किया जाना SDTableViewवर्ग। यह इंटरफ़ेस बिल्डर आइडेंटिटी इंस्पेक्टर में किया जाता है। के UITableViewअंदर का चयन करें UITableViewControllerऔर इसके "कस्टम क्लास" को सेट करें SDTableView


SDTableView के लिए प्रतिनिधि बनने के लिए आपने अपना MyTableViewController कहां स्थापित किया? SDTableView पर "डेलीगेट" नाम की संपत्ति सेट करना कैसे संभव है, जब इसके सुपरक्लास में पहले से ही उस नाम (UITableView.delegate) की संपत्ति है? जब आप संपत्ति "UITablewView" प्रकार की होती है और ऑब्जेक्ट (SDTableView का एक उदाहरण) "SDTableView" प्रकार का होता है, तो आप अपने कस्टम SDTableView को MyTableViewController.tableView संपत्ति में कैसे जमा कर सकते हैं? मैं एक ही समस्या से लड़ रहा हूं, इसलिए मुझे उम्मीद है कि इन मुद्दों का एक समाधान है :)
अर्ल ग्रे

Symmetric (SDTableView) के कोड में, क्या फिर से लोड नहीं किया जाना चाहिए? क्योंकि reloadData को लेआउटसुब्यू के बाद कहा जाता है और लोडिंग को फिर से लोड करने से पहले नहीं माना जाना चाहिए।
tzuchien.chiu

यह iOS 8 के लिए काम नहीं करता है, iPrabu के उत्तर को शामिल करना था ।
स्टनर

6

मैं में बदलाव के लिए अधिसूचना प्राप्त करने के लिए कुछ इसी तरह मिल गया था contentSizeकी TableView। मुझे लगता है कि यहां काम करना चाहिए और साथ ही सामग्री भी लोडिंग डेटा के साथ बदल जाती है।

इसे इस्तेमाल करे:

में 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
            }
        }


    }
}

परिवर्तन के लिए आपको चेक में थोड़े संशोधन की आवश्यकता हो सकती है। हालांकि यह मेरे लिए काम किया था।

चीयर्स! :)


1
बहुत चालाक। मेरे लिए पूरी तरह से काम करता है। साझा करने के लिए धन्यवाद!
DZenBot

2
सुरुचिपूर्ण! केवल एक चीज जो मैं जोड़ूंगा वह यह है कि आपको अपने आप को और एक पर्यवेक्षक को हटाने की आवश्यकता है (शायद -dealloc विधि में)। या अपने आप को पर्यवेक्षक के रूप में जोड़ें -viewWillAppearऔर अपने आप को -viewWillDisapearविधि में हटा दें ।
लूज

2

यह एक संभव समाधान है, हालांकि यह एक हैक है:

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

जहां आपका -scrollTableViewतरीका टेबल व्यू को स्क्रॉल करता है -scrollRectToVisible:animated:। और, ज़ाहिर है, आप 0.3 से ऊपर के कोड में देरी को कॉन्फ़िगर कर सकते हैं जो भी आपके लिए काम करता है। हाँ, यह हास्यास्पद हैक है, लेकिन यह मेरे iPhone 5 और 4S पर मेरे लिए काम करता है ...


2
यह "हैकी" लग सकता है, लेकिन यह स्क्रॉल करने के लिए वास्तव में एक मानक दृष्टिकोण है: इसे अगले रन चक्र तक सुरक्षित रखें। मैं देरी को 0 में बदल दूंगा, क्योंकि यह ठीक वैसे ही काम करता है और इसमें विलंबता कम होती है।
फतमान

0 के विलंब सेट के साथ मेरे लिए काम नहीं किया; 0.3 सबसे कम मैं जा सकता था और अभी भी डेटा प्राप्त कर सकता हूं।
जोश ब्राउन

@phatmann यह मेरे लिए काम किया। मैं अपनी देरी के लिए 0 का उपयोग करने में सक्षम था। आप दोनों को धन्यवाद।
mcphersonjr

1

मेरा मानना ​​कुछ ऐसा ही था। मैंने उदाहरण के चर के रूप में एक BOOL जोड़ा, जो बताता है कि ऑफसेट को बहाल किया गया है या नहीं और यह जांच लें -viewWillAppear:। जब इसे बहाल नहीं किया गया है, तो मैं इसे उस विधि में पुनर्स्थापित करता हूं और यह इंगित करने के लिए BOOL सेट करता हूं कि मैंने ऑफसेट को पुनर्प्राप्त किया था।

यह एक तरह का हैक है और इसे शायद बेहतर तरीके से किया जा सकता है, लेकिन यह फिलहाल मेरे लिए काम करता है।


हाँ, समस्या यह है कि viewWillAppear बहुत जल्दी (कम से कम मेरे परिदृश्य में) लगता है। ViewWillAppear में ऑफ़सेट को पुनर्स्थापित करने की कोशिश करने से कुछ भी नहीं होता है - जब तक कि मैं कॉलिंग के हैक को पहले से लोड न कर दूं। जैसा कि मैं इसे समझता हूं, viewWillAppear / viewDidAppear केवल तालिका दृश्य को वास्तव में प्रदर्शित होने के रूप में संदर्भित करता है - वे इस बारे में कोई दावा नहीं करते हैं कि क्या दृश्य में तालिका कोशिकाओं की गणना की गई है या आबादी है ... और इससे पहले कि आप ठीक हो सकें, ऐसा होने की आवश्यकता है एक ऑफसेट, जैसा कि अन्यथा आप एक खाली दृश्य पर एक ऑफसेट की वसूली करेंगे (और मुझे समझ में आता है कि क्यों काम नहीं करेगा!)।
kennethmac2000

लेकिन शायद आपका मतलब यह था कि आप पहले भी देखे जा रहे टेबलवैल को लोड करने को मजबूर कर रहे हैं?
kennethmac2000

नहीं, मैं फिर से लोड करने के लिए मजबूर नहीं कर रहा हूं। जब मुझे समस्या थी, तो मैंने ऑफसेट को पुनर्स्थापित करने की कोशिश की -viewDidLoad(जहां यह निश्चित रूप से होना चाहिए) लेकिन यह केवल तभी काम करता है जब मैंने ऑफसेट एनिमेटेड सेट किया था। ऑफसेट की सेटिंग को आगे बढ़ाकर -viewWillAppear:काम किया, लेकिन मुझे केवल एक बार सेट करने के लिए एक ध्वज को बनाए रखना था। मुझे लगता है कि तालिका दृश्य एक बार देखने पर एक बार अपने डेटा को पुनः लोड करता है, इसलिए यह पहले से ही है -loadView। क्या आप सुनिश्चित हैं कि आपके पास आपका डेटा दृश्य लोड पर उपलब्ध है? या यह एक अलग धागे या कुछ और में लोड किया जा रहा है?
जोस्ट

ठीक है, शायद आप यहाँ मेरी समझ की सहायता कर सकते हैं। यह तब होता है जब मैं UITableView निर्मित होने पर कॉल के अनुक्रम को समझता हूं। 1) viewDidLoad को पहले निकाल दिया जाता है। यह इंगित करता है कि UITableView मेमोरी में लोड है। 2) viewWillAppear आग के बगल में है। यह इंगित करता है कि UITableView प्रदर्शित किया जाएगा, लेकिन जरूरी नहीं कि सभी दृश्य UITableViewCell ऑब्जेक्ट पूरी तरह से त्वरित / समाप्त रेंडरिंग होंगे।
kennethmac2000

2
और इसके बाद के संस्करण के सभी सच है, सवाल यह है: UITableView ने अपने डेटा स्रोत से पर्याप्त जानकारी प्राप्त करने के लिए यह जानने के लिए कि गैर-हैक करने के विकल्प क्या हैं, यह गारंटी देने के लिए कि एक स्क्रॉल अनुरोध (यानी, एक स्क्रॉलरवॉटिब्युलर: एनिमेटेड: कॉल ) वास्तव में काम करेगा (और सिर्फ कुछ नहीं करना)?
kennethmac2000

1

ऐसा लगता है कि आप सेल सामग्री को अपडेट करना चाहते हैं, लेकिन बिना अचानक कूदता है जो सेल सम्मिलन और विलोपन के साथ हो सकता है।

ऐसा करने पर कई लेख हैं। यह वही है।

मेरा सुझाव है कि setContentOffset का उपयोग करें: एनिमेटेड: स्क्रॉल की जगह। अदृश्य: एनिमेटेड: एक स्क्रॉल दृश्य के पिक्सेल-सही सेटिंग्स के लिए।


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. बस यह सुनिश्चित करें कि "स्क्रॉलटॉ रॉटएंडएंडएक्सपैथ" संदेश यूआईटेबल व्यू के प्रासंगिक उदाहरण के लिए भेजा गया है, जो निश्चित रूप से इस मामले में माईटेबलव्यू है।
  3. मेरे मामले में UIView वह दृश्य है जिसमें UITableView का उदाहरण है
  4. साथ ही, यह प्रत्येक सेल लोड के लिए कहा जाएगा। इसलिए, एक से अधिक बार "ScrollToRowAtIndexPath" कॉल करने से बचने के लिए "cellForRowAtIndexPath" के अंदर एक तर्क रखें।

और बस यह सुनिश्चित करें कि इस टुकड़े को एक से अधिक बार नहीं कहा जाता है। यदि यह स्क्रॉल को लॉक नहीं करता है।
स्माइल.डल.डब्लू।

यह काम कर सकता है, लेकिन यह निश्चित रूप से सुरुचिपूर्ण नहीं है और न ही वह समाधान है जिसकी मुझे तलाश है। दुर्भाग्य से, यह निर्धारित करने के लिए एक बेहतर तरीका प्रतीत नहीं होता है कि क्या -reloadData वास्तव में डेटा प्राप्त कर रहा है ...
जोश ब्राउन

0

सभी डेटा लोड होने पर आप इस तालिका में अपना आकार बदल सकते हैं या इस सामग्री का आकार सेट कर सकते हैं:

- (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

मैं सिर्फ शेड्यूल किए गए टाइमर को दोहराता हूं और इसे तभी अमान्य करता हूं जब टेबल का कंटेटसाइज बड़ा होता है जब टेबलहैडर व्यू हाइट (मतलब टेबल में पंक्तियों की सामग्री होती है)। 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;
                    }
                }));
        }
    }

0

क्या UITableView layoutSubviewsतालिका दृश्य इसे सामग्री प्रदर्शित करने से ठीक पहले कहा जाता है? मैंने देखा है कि टेबल व्यू के डेटा को लोड करने के बाद इसे कहा जाता है, हो सकता है कि आप उस दिशा में जांच करें।


0

IOS 6 के बाद से, UITableviewप्रतिनिधि पद्धति को बुलाया जाता है:

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

एक बार आपकी तालिका सफलतापूर्वक लोड होने पर निष्पादित होगी। आप इस विधि में आवश्यकतानुसार अनुकूलन कर सकते हैं।


0

सबसे अच्छा समाधान मैंने स्विफ्ट में पाया है

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];
    }
}];

बहुत सारे डेटा के साथ परीक्षण नहीं किया गया

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.