UICollectionView reloadData가 iOS 7에서 제대로 작동하지 않음


93

대부분 원활하게 진행되는 iOS 7에서 실행되도록 앱을 업데이트했습니다. 나는 하나 이상의 앱 reloadData에서 a의 UICollectionViewController방법이 예전처럼 작동하지 않는다는 것을 발견했습니다 .

을로드 UICollectionViewController하고을 UICollectionView정상적으로 일부 데이터로 채 웁니다 . 이것은 처음에 훌륭하게 작동합니다. 그러나 새 데이터를 요청하고 (를 채운 다음 UICollectionViewDataSource)를 호출 reloadData하면 데이터 소스에서 numberOfItemsInSectionand를 쿼리 numberOfSectionsInCollectionView하지만 cellForItemAtIndexPath적절한 횟수 를 호출하지 않는 것 같습니다 .

한 섹션 만 다시로드하도록 코드를 변경하면 제대로 작동합니다. 이것은 내가 이것을 바꾸는 데 문제가되지 않지만 내가해야한다고 생각하지 않는다. reloadData문서에 따라 보이는 모든 셀을 다시로드해야합니다.

다른 사람이 본 적이 있습니까?


5
여기에서도 iOS7GM에서 이전에도 괜찮 았습니다. reloadDataviewDidAppear 를 호출 하면 문제와 끔찍한 해결 방법이 해결되고 수정이 필요한 것으로 나타났습니다 . 누군가가 여기서 도움을 주길 바랍니다.
jasonIM

1
같은 문제가 있습니다. iOS6에서 잘 작동하는 데 사용되는 코드. 이제 세포의 적절한 수를 반환하더라도 cellforitematindexpath를 호출하지
애브너 바

7.0 이후 릴리스에서 수정 되었습니까?
William Jockusch

이 문제와 관련된 문제에 여전히 직면하고 있습니다.
Anil

즉석에서 [collectionView setFrame]을 변경 한 후에도 비슷한 문제가 발생합니다. 항상 하나의 셀을 대기열에서 빼고 데이터 소스의 수에 관계없이 그게 전부입니다. 여기에서 모든 것을 시도했지만 주위를 돌 수 없습니다.
RegularExpression 2014 년

답변:


72

메인 스레드에서 강제로 :

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

1
더 설명 할 수 있을지 모르겠습니다. 검색, 조사, 테스트 및 조사 후. 나는 이것이 iOS 7 버그라고 생각합니다. 주 스레드를 강제 실행하면 모든 UIKit 관련 메시지가 실행됩니다. 다른 뷰 컨트롤러에서 뷰로 이동할 때이 문제가 발생하는 것 같습니다. viewWillAppear에서 데이터를 새로 고칩니다. 데이터 및 컬렉션 뷰 다시로드 호출을 볼 수 있지만 UI가 업데이트되지 않았습니다. 주 스레드 (UI 스레드)를 강제 실행하면 마술처럼 작동하기 시작합니다. 이것은 IOS 7에만 있습니다.
Shaunti Fondrisi 2014 년

6
메인 스레드에서 reloadData를 호출 할 수 없기 때문에 (메인 스레드에서 뷰를 업데이트 할 수 없음) 그다지 말이되지 않으므로 이것은 일부 경쟁 조건으로 인해 원하는 결과를 가져 오는 부작용 일 수 있습니다.
Raphael Oliveira

7
메인 큐에서 메인 큐를 디스패치하면 다음 실행 루프까지 실행이 지연되어 현재 큐에있는 모든 항목이 먼저 실행될 수 있습니다.
Joony

2
감사!! 핵심 데이터 요청이 시간을 소비하고 응답이 지연되거나 willDisplayCell에서 데이터를 다시로드하기 때문에 Joony 인수가 올바른지 여전히 이해하지 못합니다.
Fidel López

1
이 모든 시간 동안 와우 그리고 이것은 여전히 ​​나타납니다. 이것은 실제로 경쟁 조건이거나보기 이벤트 수명주기와 관련이 있습니다. 보기 "Will"은 이미 그려졌을 것입니다. 좋은 통찰력 Joony, 감사합니다. 마지막으로이 항목을 "답변"으로 설정할 수 있을까요?
Shaunti Fondrisi

64

제 경우에는 데이터 소스의 셀 / 섹션 수가 변경되지 않았으며 화면에 보이는 내용을 다시로드하고 싶었습니다.

나는 이것을 전화로 해결할 수 있었다.

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

그때:

[self.collectionView reloadData];

6
이 줄로 인해 내 앱이 중단되었습니다- "***-[UICollectionView _endItemAnimations], /SourceCache/UIKit_Sim/UIKit-2935.137/UICollectionView.m:3840"에서 어설 션 실패 "
Lugubrious

@Lugubrious 당신은 아마 동시에 다른 애니메이션을 수행하고있을 것입니다 .. performBatchUpdates:completion:블록에 넣어 보 시겠습니까?
liamnichols 2014-07-25

이것은 나를 위해 일했지만 왜 필요한지 잘 모르겠습니다. 문제가 무엇인지 아십니까?
Jon Evans

@JonEvans 불행히도 나는 전혀 모른다 .. 나는 그것이 iOS의 일종의 버그라고 생각한다. 이후 버전에서 해결되었는지 여부는 확실하지 않지만 그 이후로 테스트하지 않았기 때문에 문제가 발생한 프로젝트는 아니오 더 이상 내 문제는 :
liamnichols

1
이 버그는 그냥 헛소리 일뿐입니다! 내 컬렉션에 특정 유형의 셀이있는 경우에만 collectionView를 다시로드 할 때 내 모든 셀이 무작위로 사라졌습니다. 무슨 일이 일어나고 있는지 이해할 수 없어서 이틀을 잃었고 이제 솔루션을 적용했고 작동 했으므로 왜 지금 작동하는지 이해하지 못합니다. 너무 답답 해요! 어쨌든 도움을 주셔서 감사합니다 : D !!
CyberDandy

26

나는 똑같은 문제가 있었지만 무엇이 잘못되고 있는지 알 수있었습니다. 제 경우에는 정확하지 않은 collectionView : cellForItemAtIndexPath : 에서 reloadData 를 호출 했습니다 .

reloadData의 호출을 메인 큐로 보내면 문제가 영원히 해결되었습니다.

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

1
이 줄이 [self.collectionData.collectionViewLayout invalidateLayout]에 대해 무엇인지 말해 줄 수 있습니까?
iOSDeveloper 2014 년

이것은 나에게도 해결되었습니다. 제 경우 reloadData에는 변경 관찰자가 호출했습니다.
sudo make install

또한이 적용collectionView(_:willDisplayCell:forItemAtIndexPath:)
스테판 Arambasich

20

일부 항목을 다시로드 할 수 없었습니다. 제 경우에는 사용중인 collectionView에 섹션이 하나만 있기 때문에 특정 섹션을 다시로드하기 만하면됩니다. 이번에는 콘텐츠가 올바르게 다시로드됩니다. 이것이 iOS 7 (7.0.3)에서만 발생하는 것이 이상합니다.

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

12

iOS 7에서 reloadData와 동일한 문제가 발생했습니다. 긴 디버그 세션 후 문제를 발견했습니다.

iOS7에서 UICollectionView의 reloadData는 아직 완료되지 않은 이전 업데이트를 취소하지 않습니다 (performBatchUpdates : 블록 내부에서 호출 한 업데이트).

이 버그를 해결하는 가장 좋은 방법은 현재 처리되고있는 모든 업데이트를 중지하고 reloadData를 호출하는 것입니다. performBatchUpdates 블록을 취소하거나 중지하는 방법을 찾지 못했습니다. 따라서 버그를 해결하기 위해 현재 처리중인 performBatchUpdates 블록이 있는지 여부를 나타내는 플래그를 저장했습니다. 현재 처리중인 업데이트 블록이 없으면 즉시 reloadData를 호출 할 수 있으며 모든 것이 예상대로 작동합니다. 현재 처리중인 업데이트 블록이있는 경우 performBatchUpdates의 전체 블록에서 reloadData를 호출합니다.


performBatchUpdate 내부에서 모든 업데이트를 수행하는 곳은 어디입니까? 일부는? 전부 다? 매우 흥미로운 게시물입니다.
VaporwareWolf 2014 년

CoreData의 데이터를 표시하기 위해 NSFetchedResultsController와 함께 컬렉션 뷰를 사용하고 있습니다. NSFetchedResultsController 대리자가 변경 사항을 알릴 때 모든 업데이트를 수집하여 performBatchUpdates 내에서 호출합니다. NSFetchedResultsController 요청 조건자가 변경되면 reloadData를 호출해야합니다.
user2459624 2014-08-27

이것은 실제로 질문에 대한 좋은 대답입니다. reloadItems () (애니메이션)를 실행 한 다음 reloadData ()를 실행하면 셀을 건너 뜁니다.
약력

12

스위프트 5 – 4 – 3

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

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

스위프트 2

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

4

나도이 문제가 있었다. 우연히 테스트를 위해 강제로 다시로드하기 위해 collectionview 위에 버튼을 추가했고, 갑자기 메서드가 호출되기 시작했습니다.

또한 간단한 것을 추가하면

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

메서드가 호출되게합니다.

또한 프레임 크기를 가지고 놀았고 메서드가 호출되었습니다.

iOS7 UICollectionView에는 많은 버그가 있습니다.


다른 사람들도이 문제를 겪고 있다는 것을 (인증적인 방식으로) 보게되어 기쁩니다. 해결 방법에 감사드립니다.
VaporwareWolf 2013 년

3

이 방법을 사용할 수 있습니다

[collectionView reloadItemsAtIndexPaths:arayOfAllIndexPaths];

아래 방법을 사용하여 모든 섹션과 행에 대해 루프를 반복하여 배열 에 모든 indexPath객체를 추가 할 수 있습니다.UICollectionViewarrayOfAllIndexPaths

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

이해하고 문제를 해결할 수 있기를 바랍니다. 더 많은 설명이 필요하면 회신 해주십시오.


3

Shaunti Fondrisi가 제공 한 솔루션은 거의 완벽합니다. 그러나 UICollectionView's reloadData()to NSOperationQueue'의 실행을 대기열에 mainQueue넣는 것과 같은 코드 또는 코드는 실제로 실행 타이밍을 실행 루프의 다음 이벤트 루프의 시작에 놓아 UICollectionView가볍게 업데이트 할 수 있습니다.

이 문제를 해결하기 위해. 동일한 코드의 실행 타이밍을 현재 이벤트 루프의 끝에 배치해야하지만 다음 루프의 시작 부분에는 배치하지 않아야합니다. 그리고 우리는 CFRunLoopObserver.

CFRunLoopObserver 모든 입력 소스 대기 활동과 실행 루프의 시작 및 종료 활동을 관찰합니다.

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

이러한 활동 중 .AfterWaiting현재 이벤트 루프가 종료 .BeforeWaiting되려고 할 때 관찰 할 수 있으며 다음 이벤트 루프가 방금 시작되었을 때 관찰 할 수 있습니다.

NSRunLoop당 하나의 인스턴스 만 NSThread있고를 NSRunLoop정확히 구동 NSThread하므로 동일한 NSRunLoop인스턴스 에서 액세스가 항상 스레드를 교차하지 않는다는 것을 고려할 수 있습니다 .

이전에 언급 한 사항을 기반으로 이제 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
        }
    }
}

이전 코드와 함께, 우리는 지금의 실행이 전달할 수 UICollectionViewreloadData()코드와 같은 조각에 의해 현재의 이벤트 루프의 끝 :

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

실제로 이러한 NSRunLoop 기반 작업 디스패처는 이미 내 개인 사용 프레임 워크 중 하나 인 Nest에 있습니다. 다음은 GitHub의 저장소입니다 : https://github.com/WeZZard/Nest


2
 dispatch_async(dispatch_get_main_queue(), ^{

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


        });

그것은 나를 위해 일했습니다.


1

우선이 스레드에 대해 감사합니다. 매우 도움이됩니다. Reload Data와 비슷한 문제가있었습니다. 증상은 특정 세포를 더 이상 영구적으로 선택할 수없는 반면 다른 세포는 선택할 수 없다는 것입니다. indexPathsForSelectedItems 메서드 또는 이와 동등한 메서드에 대한 호출이 없습니다. 디버깅은 데이터 다시로드를 지적했습니다. 위의 두 가지 옵션을 모두 시도했습니다. 다른 옵션이 제 경우에는 작동하지 않았거나 컬렉션 뷰를 밀리 초 정도 플래시로 만들었 기 때문에 ReloadItemsAtIndexPaths 옵션을 채택했습니다. 아래 코드는 잘 작동합니다.

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

iOS 8.1 sdk에서도 나에게 발생했지만 datasource메서드를 업데이트 한 후에도 numberOfItemsInSection:새 항목 수를 반환하지 않는 것을 알았을 때 올바르게 수정 되었습니다. 카운트를 업데이트하고 작동하게했습니다.


.. 위의 모든 방법은 빠른 3에 나를 위해 작업에 실패하십시오 당신은 어떻게 그 수를 업데이트 한 이유
nyxee

0

UICollectionView.contentInset을 설정합니까? 왼쪽 및 오른쪽 edgeInset 제거, 내가 제거한 후에도 모든 것이 정상이며 버그는 여전히 iOS8.3에 존재합니다.


0

각 UICollectionView Delegate 메서드가 예상 한 작업을 수행하는지 확인합니다. 예를 들어

collectionView:layout:sizeForItemAtIndexPath:

유효한 크기를 반환하지 않으면 새로 고침이 작동하지 않습니다.


0

이 코드를 시도하십시오.

 NSArray * visibleIdx = [self.collectionView indexPathsForVisibleItems];

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

0

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