UICollectionXem tải lại Dữ liệu không hoạt động bình thường trong iOS 7


93

Tôi đã cập nhật các ứng dụng của mình để chạy trên iOS 7, phần lớn diễn ra suôn sẻ. Tôi đã nhận thấy trong nhiều ứng dụng rằng reloadDataphương thức của một UICollectionViewControllerkhông hoạt động như trước đây.

Tôi sẽ tải UICollectionViewController, điền vào UICollectionViewmột số dữ liệu như bình thường. Điều này hoạt động tuyệt vời trong lần đầu tiên. Tuy nhiên, nếu tôi yêu cầu dữ liệu mới (điền UICollectionViewDataSource) và sau đó gọi reloadData, nó sẽ truy vấn nguồn dữ liệu cho numberOfItemsInSectionnumberOfSectionsInCollectionView, nhưng dường như nó không gọi cellForItemAtIndexPathsố lần thích hợp.

Nếu tôi thay đổi mã để chỉ tải lại một phần, thì nó sẽ hoạt động bình thường. Điều này không có vấn đề gì đối với tôi khi thay đổi những điều này, nhưng tôi không nghĩ rằng tôi nên làm thế. reloadDatanên tải lại tất cả các ô hiển thị theo tài liệu.

Đã có người khác nhìn thấy điều này?


5
Tương tự ở đây, nó trong iOS7GM, hoạt động tốt trước đây. Tôi nhận thấy rằng việc gọi reloadDatasau viewDidAppear dường như giải quyết được vấn đề, cách giải quyết tồi tệ của nó và cần sửa chữa. Tôi hy vọng ai đó giúp đỡ ở đây.
jasonIM

1
Có cùng một vấn đề. Mã được sử dụng để hoạt động tốt trong iOS6. bây giờ không gọi cellforitematindexpath mặc dù trở về số thích hợp của các tế bào
Avner Barr

Điều này có được khắc phục trong bản phát hành sau 7.0 không?
William Jockusch

Tôi vẫn đang đối mặt với các vấn đề liên quan đến vấn đề này.
Anil

Vấn đề tương tự sau khi thay đổi [collectionView setFrame] khi đang di chuyển; luôn xếp hàng trước một ô và đó là ô bất kể số trong nguồn dữ liệu. Đã thử mọi thứ ở đây và hơn thế nữa, và không thể vượt qua nó.
RegularExpression

Câu trả lời:


72

Buộc điều này trên chuỗi chính:

dispatch_async(dispatch_get_main_queue(), ^ {
    [self.collectionView reloadData];
});

1
Tôi không chắc nếu tôi có thể giải thích thêm. Sau khi tìm kiếm, nghiên cứu, thử nghiệm và thăm dò. Tôi cảm thấy đây là một lỗi iOS 7. Buộc luồng chính sẽ chạy tất cả các thông báo liên quan đến UIKit. Tôi dường như gặp phải điều này khi bật chế độ xem từ một bộ điều khiển chế độ xem khác. Tôi làm mới dữ liệu trên viewWillAppear. Tôi có thể thấy dữ liệu và cuộc gọi tải lại chế độ xem bộ sưu tập, nhưng giao diện người dùng không được cập nhật. Buộc luồng chính (luồng giao diện người dùng) và nó bắt đầu hoạt động một cách kỳ diệu. Đây là chỉ trong IOS 7.
Shaunti Fondrisi

6
Điều đó không có ý nghĩa lắm vì bạn không thể gọi reloadData ra khỏi chuỗi chính (bạn không thể cập nhật các lượt xem ra khỏi chuỗi chính) vì vậy đây có thể là một tác dụng phụ dẫn đến những gì bạn muốn do một số điều kiện chủng tộc.
Raphael Oliveira

7
Điều phối trên hàng đợi chính từ hàng đợi chính chỉ làm chậm quá trình thực thi cho đến vòng chạy tiếp theo, cho phép mọi thứ hiện đang xếp hàng có cơ hội thực thi trước.
Joony

2
Cảm ơn!! Vẫn không hiểu đối số Joony có đúng không vì yêu cầu dữ liệu cốt lõi tiêu tốn thời gian và câu trả lời của nó bị trì hoãn hoặc vì tôi đang tải lại dữ liệu tại willDisplayCell.
Fidel López

1
Wow suốt thời gian qua và điều này vẫn xuất hiện. Đây thực sự là một điều kiện đua hoặc liên quan đến vòng đời của sự kiện chế độ xem. xem "Di chúc" xuất hiện hẳn đã được vẽ rồi. Cái nhìn sâu sắc tốt Joony, Cảm ơn. Hãy nghĩ rằng chúng ta có thể đặt mục này thành "đã trả lời" cuối cùng?
Shaunti Fondrisi,

64

Trong trường hợp của tôi, số ô / phần trong nguồn dữ liệu không bao giờ thay đổi và tôi chỉ muốn tải lại nội dung hiển thị trên màn hình ..

Tôi đã xoay sở để giải quyết vấn đề này bằng cách gọi:

[self.collectionView reloadItemsAtIndexPaths:[self.collectionView indexPathsForVisibleItems]];

sau đó:

[self.collectionView reloadData];

6
Dòng đó khiến ứng dụng của tôi gặp sự cố - "*** Xác nhận không thành công trong - [UICollectionView _endItemAnimations], /SourceCache/UIKit_Sim/UIKit-2935.137/UICollectionView.m:3840"
Lugubrious

@Lugubrious Có thể bạn đang thực hiện các hoạt ảnh khác cùng lúc .. hãy thử đặt chúng vào một performBatchUpdates:completion:khối?
liamnichols

Điều này có hiệu quả với tôi, nhưng tôi không chắc mình hiểu tại sao nó lại cần thiết. Bất kỳ ý tưởng vấn đề là gì?
Jon Evans

@JonEvans Rất tiếc, tôi không biết .. Tôi tin rằng đó là một loại lỗi nào đó trong iOS, không chắc liệu nó có được giải quyết trong các phiên bản sau hay không mặc dù tôi chưa thử nghiệm kể từ đó và dự án tôi gặp sự cố là không. còn vấn đề của tôi :)
liamnichols

1
Con bọ này chỉ là chuyện nhảm nhí! Tất cả các ô của tôi - một cách ngẫu nhiên - biến mất khi tôi tải lại collectionView của mình, chỉ khi tôi có một loại ô cụ thể trong bộ sưu tập của mình. Tôi đã mất hai ngày trên nó vì tôi không thể hiểu chuyện gì đang xảy ra, và bây giờ tôi đã áp dụng giải pháp của bạn và nó hoạt động, tôi vẫn không hiểu tại sao nó lại hoạt động. Thật là bực mình! Dù sao cũng cảm ơn sự giúp đỡ: D !!
CyberDandy

26

Tôi đã gặp chính xác vấn đề tương tự, tuy nhiên tôi đã cố gắng tìm ra điều gì đang xảy ra. Trong trường hợp của tôi, tôi đang gọi reloadData từ collectionView: cellForItemAtIndexPath: có vẻ không đúng.

Việc gửi lệnh gọi reloadData đến hàng đợi chính đã khắc phục sự cố một lần và mãi mãi.

  dispatch_async(dispatch_get_main_queue(), ^{
    [self.collectionView reloadData];
  });

1
bạn có thể cho tôi biết dòng này là gì cho [self.collectionData.collectionViewLayout validateLayout];
iOSDeveloper

Điều này cũng giải quyết được nó cho tôi - trong trường hợp của tôi reloadDatalà một người quan sát thay đổi gọi.
sudo thực hiện cài đặt

Ngoài ra điều này áp dụng chocollectionView(_:willDisplayCell:forItemAtIndexPath:)
Stefan Arambasich

20

Tải lại một số mục không hiệu quả với tôi. Trong trường hợp của tôi, và chỉ vì collectionView tôi đang sử dụng chỉ có một phần, nên tôi chỉ cần tải lại phần cụ thể đó. Lần này nội dung được tải lại chính xác. Kỳ lạ là điều này chỉ xảy ra trên iOS 7 (7.0.3)

[self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];

12

Tôi đã gặp sự cố tương tự với reloadData trên iOS 7. Sau phiên gỡ lỗi dài, tôi đã tìm thấy sự cố.

Trên iOS7, reloadData trên UICollectionView không hủy các bản cập nhật trước đó chưa hoàn thành (Các bản cập nhật được gọi là bên trong performanceBatchUpdates: block).

Giải pháp tốt nhất để giải quyết lỗi này là dừng tất cả các bản cập nhật hiện đang được xử lý và gọi reloadData. Tôi không tìm thấy cách nào để hủy hoặc dừng một khối performanceBatchUpdates. Do đó, để giải quyết lỗi, tôi đã lưu một cờ cho biết liệu có khối performanceBatchUpdates hiện đang được xử lý hay không. Nếu không có khối cập nhật nào hiện được xử lý, tôi có thể gọi reloadData ngay lập tức và mọi thứ hoạt động như mong đợi. Nếu có một khối cập nhật hiện đang được xử lý, tôi sẽ gọi reloadData trên khối hoàn chỉnh của performanceBatchUpdates.


Nơi bạn thực hiện tất cả các nội dung đã cập nhật của mình bên trong performanceBatchUpdate? Một số trong một số ra? Tất cả đi ra? Bài rất thú vị.
VaporwareWolf

Tôi đang sử dụng dạng xem bộ sưu tập với NSFetchedResultsController để hiển thị dữ liệu từ CoreData. Khi người được ủy quyền NSFetchedResultsController thông báo về các thay đổi, tôi thu thập tất cả các bản cập nhật và gọi chúng bên trong PerformBatchUpdates. Khi vị từ yêu cầu NSFetchedResultsController được thay đổi, reloadData phải được gọi.
user2459624

Đây thực sự là một câu trả lời tốt cho câu hỏi. Nếu bạn chạy reloadItems () (được làm động) và sau đó reloadData (), nó sẽ bỏ qua các ô.
bio

12

Swift 5 - 4 - 3

// GCD    
DispatchQueue.main.async(execute: collectionView.reloadData)

// Operation
OperationQueue.main.addOperation(collectionView.reloadData)

Swift 2

// Operation
NSOperationQueue.mainQueue().addOperationWithBlock(collectionView.reloadData)

4

Tôi cũng đã từng gặp phải vấn đề này. Thật tình cờ, tôi đã thêm một nút trên đầu collectionview để buộc tải lại để thử nghiệm - và đột nhiên, các phương thức bắt đầu được gọi.

Ngoài ra, chỉ cần thêm một cái gì đó đơn giản như

UIView *aView = [UIView new];
[collectionView addSubView:aView];

sẽ khiến các phương thức được gọi

Ngoài ra, tôi đã thử với kích thước khung hình - và thì các phương thức đã được gọi.

Có rất nhiều lỗi với iOS7 UICollectionView.


Tôi rất vui khi thấy (theo những cách xác thực) rằng những người khác cũng đang gặp phải vấn đề này. Cảm ơn về giải pháp.
VaporwareWolf

3

Bạn có thể sử dụng phương pháp này

[collectionView reloadItemsAtIndexPaths:arayOfAllIndexPaths];

Bạn có thể thêm tất cả indexPathcác đối tượng của mình UICollectionViewvào mảng arrayOfAllIndexPathsbằng cách lặp lại vòng lặp cho tất cả các phần và hàng bằng cách sử dụng phương thức dưới đây

[aray addObject:[NSIndexPath indexPathForItem:j inSection:i]];

Tôi hy vọng bạn hiểu và nó có thể giải quyết vấn đề của bạn. Nếu bạn cần giải thích thêm, vui lòng trả lời.


3

Giải pháp mà Shaunti Fondrisi đưa ra gần như hoàn hảo. Nhưng một đoạn mã như vậy hoặc các đoạn mã như xếp hàng thực thi UICollectionView's reloadData()đến NSOperationQueue' mainQueuethực sự đặt thời gian thực thi vào đầu vòng lặp sự kiện tiếp theo trong vòng lặp chạy, điều này có thể thực hiện UICollectionViewcập nhật với một cú nhấp chuột.

Để giải quyết vấn đề này. Chúng ta phải đặt thời gian thực thi của cùng một đoạn mã vào cuối vòng lặp sự kiện hiện tại nhưng không phải là đầu của phần tiếp theo. Và chúng ta có thể đạt được điều này bằng cách tận dụng CFRunLoopObserver.

CFRunLoopObserver quan sát tất cả các hoạt động chờ đợi của nguồn đầu vào và hoạt động vào và ra của vòng chạy.

public struct CFRunLoopActivity : OptionSetType {
    public init(rawValue: CFOptionFlags)

    public static var Entry: CFRunLoopActivity { get }
    public static var BeforeTimers: CFRunLoopActivity { get }
    public static var BeforeSources: CFRunLoopActivity { get }
    public static var BeforeWaiting: CFRunLoopActivity { get }
    public static var AfterWaiting: CFRunLoopActivity { get }
    public static var Exit: CFRunLoopActivity { get }
    public static var AllActivities: CFRunLoopActivity { get }
}

Trong số các hoạt động đó, .AfterWaitingcó thể được quan sát khi vòng lặp sự kiện hiện tại sắp kết thúc và .BeforeWaitingcó thể được quan sát khi vòng lặp sự kiện tiếp theo vừa bắt đầu.

Vì chỉ có một NSRunLoopthể hiện trên mỗi NSThreadNSRunLoopchính xác là ổ đĩa NSThread, chúng ta có thể coi rằng các truy cập đến từ cùng một NSRunLoopthể hiện luôn không bao giờ vượt qua các luồng.

Dựa trên các điểm đã đề cập trước đây, bây giờ chúng ta có thể viết mã: một trình điều phối tác vụ dựa trên NSRunLoop:

import Foundation
import ObjectiveC

public struct Weak<T: AnyObject>: Hashable {
    private weak var _value: T?
    public weak var value: T? { return _value }
    public init(_ aValue: T) { _value = aValue }

    public var hashValue: Int {
        guard let value = self.value else { return 0 }
        return ObjectIdentifier(value).hashValue
    }
}

public func ==<T: AnyObject where T: Equatable>(lhs: Weak<T>, rhs: Weak<T>)
    -> Bool
{
    return lhs.value == rhs.value
}

public func ==<T: AnyObject>(lhs: Weak<T>, rhs: Weak<T>) -> Bool {
    return lhs.value === rhs.value
}

public func ===<T: AnyObject>(lhs: Weak<T>, rhs: Weak<T>) -> Bool {
    return lhs.value === rhs.value
}

private var dispatchObserverKey =
"com.WeZZard.Nest.NSRunLoop.TaskDispatcher.DispatchObserver"

private var taskQueueKey =
"com.WeZZard.Nest.NSRunLoop.TaskDispatcher.TaskQueue"

private var taskAmendQueueKey =
"com.WeZZard.Nest.NSRunLoop.TaskDispatcher.TaskAmendQueue"

private typealias DeallocFunctionPointer =
    @convention(c) (Unmanaged<NSRunLoop>, Selector) -> Void

private var original_dealloc_imp: IMP?

private let swizzled_dealloc_imp: DeallocFunctionPointer = {
    (aSelf: Unmanaged<NSRunLoop>,
    aSelector: Selector)
    -> Void in

    let unretainedSelf = aSelf.takeUnretainedValue()

    if unretainedSelf.isDispatchObserverLoaded {
        let observer = unretainedSelf.dispatchObserver
        CFRunLoopObserverInvalidate(observer)
    }

    if let original_dealloc_imp = original_dealloc_imp {
        let originalDealloc = unsafeBitCast(original_dealloc_imp,
            DeallocFunctionPointer.self)
        originalDealloc(aSelf, aSelector)
    } else {
        fatalError("The original implementation of dealloc for NSRunLoop cannot be found!")
    }
}

public enum NSRunLoopTaskInvokeTiming: Int {
    case NextLoopBegan
    case CurrentLoopEnded
    case Idle
}

extension NSRunLoop {

    public func perform(closure: ()->Void) -> Task {
        objc_sync_enter(self)
        loadDispatchObserverIfNeeded()
        let task = Task(self, closure)
        taskQueue.append(task)
        objc_sync_exit(self)
        return task
    }

    public override class func initialize() {
        super.initialize()

        struct Static {
            static var token: dispatch_once_t = 0
        }
        // make sure this isn't a subclass
        if self !== NSRunLoop.self {
            return
        }

        dispatch_once(&Static.token) {
            let selectorDealloc: Selector = "dealloc"
            original_dealloc_imp =
                class_getMethodImplementation(self, selectorDealloc)

            let swizzled_dealloc = unsafeBitCast(swizzled_dealloc_imp, IMP.self)

            class_replaceMethod(self, selectorDealloc, swizzled_dealloc, "@:")
        }
    }

    public final class Task {
        private let weakRunLoop: Weak<NSRunLoop>

        private var _invokeTiming: NSRunLoopTaskInvokeTiming
        private var invokeTiming: NSRunLoopTaskInvokeTiming {
            var theInvokeTiming: NSRunLoopTaskInvokeTiming = .NextLoopBegan
            guard let amendQueue = weakRunLoop.value?.taskAmendQueue else {
                fatalError("Accessing a dealloced run loop")
            }
            dispatch_sync(amendQueue) { () -> Void in
                theInvokeTiming = self._invokeTiming
            }
            return theInvokeTiming
        }

        private var _modes: NSRunLoopMode
        private var modes: NSRunLoopMode {
            var theModes: NSRunLoopMode = []
            guard let amendQueue = weakRunLoop.value?.taskAmendQueue else {
                fatalError("Accessing a dealloced run loop")
            }
            dispatch_sync(amendQueue) { () -> Void in
                theModes = self._modes
            }
            return theModes
        }

        private let closure: () -> Void

        private init(_ runLoop: NSRunLoop, _ aClosure: () -> Void) {
            weakRunLoop = Weak<NSRunLoop>(runLoop)
            _invokeTiming = .NextLoopBegan
            _modes = .defaultMode
            closure = aClosure
        }

        public func forModes(modes: NSRunLoopMode) -> Task {
            if let amendQueue = weakRunLoop.value?.taskAmendQueue {
                dispatch_async(amendQueue) { [weak self] () -> Void in
                    self?._modes = modes
                }
            }
            return self
        }

        public func when(invokeTiming: NSRunLoopTaskInvokeTiming) -> Task {
            if let amendQueue = weakRunLoop.value?.taskAmendQueue {
                dispatch_async(amendQueue) { [weak self] () -> Void in
                    self?._invokeTiming = invokeTiming
                }
            }
            return self
        }
    }

    private var isDispatchObserverLoaded: Bool {
        return objc_getAssociatedObject(self, &dispatchObserverKey) !== nil
    }

    private func loadDispatchObserverIfNeeded() {
        if !isDispatchObserverLoaded {
            let invokeTimings: [NSRunLoopTaskInvokeTiming] =
            [.CurrentLoopEnded, .NextLoopBegan, .Idle]

            let activities =
            CFRunLoopActivity(invokeTimings.map{ CFRunLoopActivity($0) })

            let observer = CFRunLoopObserverCreateWithHandler(
                kCFAllocatorDefault,
                activities.rawValue,
                true, 0,
                handleRunLoopActivityWithObserver)

            CFRunLoopAddObserver(getCFRunLoop(),
                observer,
                kCFRunLoopCommonModes)

            let wrappedObserver = NSAssociated<CFRunLoopObserver>(observer)

            objc_setAssociatedObject(self,
                &dispatchObserverKey,
                wrappedObserver,
                .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }

    private var dispatchObserver: CFRunLoopObserver {
        loadDispatchObserverIfNeeded()
        return (objc_getAssociatedObject(self, &dispatchObserverKey)
            as! NSAssociated<CFRunLoopObserver>)
            .value
    }

    private var taskQueue: [Task] {
        get {
            if let taskQueue = objc_getAssociatedObject(self,
                &taskQueueKey)
                as? [Task]
            {
                return taskQueue
            } else {
                let initialValue = [Task]()

                objc_setAssociatedObject(self,
                    &taskQueueKey,
                    initialValue,
                    .OBJC_ASSOCIATION_RETAIN_NONATOMIC)

                return initialValue
            }
        }
        set {
            objc_setAssociatedObject(self,
                &taskQueueKey,
                newValue,
                .OBJC_ASSOCIATION_RETAIN_NONATOMIC)

        }
    }

    private var taskAmendQueue: dispatch_queue_t {
        if let taskQueue = objc_getAssociatedObject(self,
            &taskAmendQueueKey)
            as? dispatch_queue_t
        {
            return taskQueue
        } else {
            let initialValue =
            dispatch_queue_create(
                "com.WeZZard.Nest.NSRunLoop.TaskDispatcher.TaskAmendQueue",
                DISPATCH_QUEUE_SERIAL)

            objc_setAssociatedObject(self,
                &taskAmendQueueKey,
                initialValue,
                .OBJC_ASSOCIATION_RETAIN_NONATOMIC)

            return initialValue
        }
    }

    private func handleRunLoopActivityWithObserver(observer: CFRunLoopObserver!,
        activity: CFRunLoopActivity)
        -> Void
    {
        var removedIndices = [Int]()

        let runLoopMode: NSRunLoopMode = currentRunLoopMode

        for (index, eachTask) in taskQueue.enumerate() {
            let expectedRunLoopModes = eachTask.modes
            let expectedRunLoopActivitiy =
            CFRunLoopActivity(eachTask.invokeTiming)

            let runLoopModesMatches = expectedRunLoopModes.contains(runLoopMode)
                || expectedRunLoopModes.contains(.commonModes)

            let runLoopActivityMatches =
            activity.contains(expectedRunLoopActivitiy)

            if runLoopModesMatches && runLoopActivityMatches {
                eachTask.closure()
                removedIndices.append(index)
            }
        }

        taskQueue.removeIndicesInPlace(removedIndices)
    }
}

extension CFRunLoopActivity {
    private init(_ invokeTiming: NSRunLoopTaskInvokeTiming) {
        switch invokeTiming {
        case .NextLoopBegan:        self = .AfterWaiting
        case .CurrentLoopEnded:     self = .BeforeWaiting
        case .Idle:                 self = .Exit
        }
    }
}

Với đoạn mã trước đây, bây giờ chúng ta có thể gửi việc thực thi UICollectionView's reloadData()đến cuối vòng lặp sự kiện hiện tại bằng một đoạn mã như vậy:

NSRunLoop.currentRunLoop().perform({ () -> Void in
     collectionView.reloadData()
    }).when(.CurrentLoopEnded)

Trên thực tế, một trình điều phối tác vụ dựa trên NSRunLoop như vậy đã nằm trong một trong những khuôn khổ được sử dụng cá nhân của tôi: Nest. Và đây là kho của nó trên GitHub: https://github.com/WeZZard/Nest


2
 dispatch_async(dispatch_get_main_queue(), ^{

            [collectionView reloadData];
            [collectionView layoutIfNeeded];
            [collectionView reloadData];


        });

nó đã làm việc cho tôi.


1

Cảm ơn trước hết về chủ đề này, rất hữu ích. Tôi đã gặp sự cố tương tự với Tải lại dữ liệu ngoại trừ triệu chứng là các ô cụ thể không còn có thể được chọn theo cách vĩnh viễn trong khi những người khác có thể. Không có lệnh gọi đến phương thức indexPathsForSelectedItems hoặc phương thức tương đương. Gỡ lỗi được chỉ ra để Tải lại dữ liệu. Tôi đã thử cả hai tùy chọn ở trên; và cuối cùng đã áp dụng tùy chọn Nạp lại đường dẫn vì các tùy chọn khác không hoạt động trong trường hợp của tôi hoặc làm cho chế độ xem bộ sưu tập nhấp nháy trong một mili giây hoặc lâu hơn. Đoạn mã dưới đây hoạt động tốt:

NSMutableArray *indexPaths = [[NSMutableArray alloc] init]; 
NSIndexPath *indexPath;
for (int i = 0; i < [self.assets count]; i++) {
         indexPath = [NSIndexPath indexPathForItem:i inSection:0];
         [indexPaths addObject:indexPath];
}
[collectionView reloadItemsAtIndexPaths:indexPaths];`

0

Nó cũng xảy ra với tôi trong sdk iOS 8.1, nhưng tôi đã hiểu chính xác khi nhận thấy rằng ngay cả sau khi cập nhật datasourcephương pháp numberOfItemsInSection:vẫn không trả lại số lượng mục mới. Tôi đã cập nhật số lượng và làm cho nó hoạt động.


làm thế nào bạn đã cập nhật số đó xin vui lòng .. Tất cả các phương pháp trên đã thất bại trong việc làm việc cho tôi trong nhanh chóng 3.
nyxee

0

Bạn có đặt UICollectionView.contentInset không? Xóa cạnh trái và phải Đặt, mọi thứ đều ổn sau khi tôi xóa chúng, lỗi vẫn tồn tại trong iOS8.3.


0

Kiểm tra xem mỗi một trong các phương thức UICollectionView Delegate có thực hiện những gì bạn mong đợi hay không. Ví dụ, nếu

collectionView:layout:sizeForItemAtIndexPath:

không trả về kích thước hợp lệ, quá trình tải lại sẽ không hoạt động ...


0

thử mã này.

 NSArray * visibleIdx = [self.collectionView indexPathsForVisibleItems];

    if (visibleIdx.count) {
        [self.collectionView reloadItemsAtIndexPaths:visibleIdx];
    }

0

Đây là cách nó hoạt động đối với tôi trong Swift 4

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

let cell = campaignsCollection.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! Cell

cell.updateCell()

    // TO UPDATE CELLVIEWS ACCORDINGLY WHEN DATA CHANGES
    DispatchQueue.main.async {
        self.campaignsCollection.reloadData()
    }

    return cell
}

-1
inservif (isInsertHead) {
   [self insertItemsAtIndexPaths:tmpPoolIndex];
   NSArray * visibleIdx = [self indexPathsForVisibleItems];
   if (visibleIdx.count) {
       [self reloadItemsAtIndexPaths:visibleIdx];
   }
}else if (isFirstSyncData) {
    [self reloadData];
}else{
   [self insertItemsAtIndexPaths:tmpPoolIndex];
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.