Ошибка UIRfreshControl при выходе на передний план

Я заметил небольшую ошибку (но очень раздражающую), когда я использую UIRefreshControl в своем контроллере представления. Когда приложение возвращается из фона, UIRefreshControl уже загружено, и это выглядит так:

Как видите, я использую собственный навигационный контроллер, который скрывается, как в приложении Facebook (AMScrollingNavBar). Когда перезагружаю данные в UITableView все приходит в норму и этот баг проявляется только после выхода из фона.

Это код, который я использую для инициализации UIRefreshControl в viewDidLoad:

// Initializing generic refresh control
self.refreshControl = [[UIRefreshControl alloc] init];
[self.refreshControl addTarget:self action:@selector(collectData) forControlEvents:UIControlEventValueChanged];
[self.tableView addSubview:self.refreshControl];

person cojoj    schedule 08.03.2014    source источник


Ответы (3)


Это известная ошибка в iOS7. Вы можете увидеть его воспроизведение в почтовом приложении Apple. Я могу подтвердить, что это не было исправлено в iOS7.1 beta 5 iOS8.0 beta 3 iOS 10.0.1.

Сначала откройте отчет об ошибке на странице https://bugreport.apple.com/. Мой номер радара – rdar://14586451, который является дубликатом rdar://14493713 (все еще открытым).

Предлагаемое исправление состоит в том, чтобы зарегистрироваться для уведомлений UIApplicationWillEnterForegroundNotification в вашем контроллере представления и вызвать [self.refreshControl.superview sendSubviewToBack:self.refreshControl];, чтобы несколько исправить проблему, отобразив элемент управления обновлением за содержимым вашей таблицы.

Я вижу на втором снимке экрана, что элемент управления обновлением отображается под вашей ячейкой. Вероятно, это связано с тем, что вы установили чистый цвет в качестве фона своей ячейки. Установите его на белый.

person Leo Natan    schedule 08.03.2014
comment
Жаль, что он до сих пор не анимируется так, как должен. Ваш ответ помог мне, по крайней мере, скрыть этот ужасный вид! В этом случае я снова примирюсь, используя пользовательское обновление по запросу! - person cojoj; 08.03.2014
comment
Есть много других ошибок с UIRfreshControl. Я думаю, что сделал около 10 отчетов об ошибках для этого класса. - person Nilz11; 18.04.2014
comment
Апрель 2016, iOS 9.2 - до сих пор зависает. - person Andrey Solovyov; 07.04.2016

Я нашел один обходной путь для варианта этой ошибки. Это может потенциально помочь и с вашим. В моем приложении переключение на другую вкладку и возврат на вкладку с элементом управления обновлением сломало его — элемент управления больше не анимировался при перетаскивании.

Вместо того, чтобы настраивать UIRefreshControl в viewDidLoad, я устанавливаю его в viewDidAppear, а затем всегда удаляю в viewDidDisappear. Таким образом, он всегда инициализируется свежим и не путается.

Как и в предыдущем ответе на этот вопрос, я запросил UIApplicationDidBecomeActiveNotification, чтобы можно было исправить элемент управления обновлением, когда пользователь возвращается в приложение.

@implementation MYViewController {
    UIRefreshControl *refreshControl;
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    /* Pull down to refresh. iOS bug: If we add this in viewDidLoad and let it
     * stay there for the lifetime of the view, the control will misbehave
     * after going to another view/tab and coming back (will not animate nicely
     * on drag).
     */
    [self setupRefreshControl];

    /* We'll want to be notified for didBecomeActive, to do the pull-down-to-refresh workaround when resuming. */
    [[NSNotificationCenter defaultCenter] addObserver:self
        selector:@selector(setupRefreshControl)
            name:UIApplicationDidBecomeActiveNotification object:nil];
}

- (void)setupRefeshControl
{
    if (refreshControl)
        [refreshControl removeFromSuperview];

    refreshControl = [[UIRefreshControl alloc] init];
    [refreshControl addTarget:self action:@selector(refreshPull:)
        forControlEvents:UIControlEventValueChanged];

    [scrollView addSubview:refreshControl];
}

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];

    [refreshControl removeFromSuperview];
    refreshControl = nil;

    /* We don't need notification for becoming active any more */
    [[NSNotificationCenter defaultCenter] removeObserver:self
        name:UIApplicationDidBecomeActiveNotification
      object:nil];
}

Немного неоптимально, но работает.

person oh7lzb    schedule 22.08.2014
comment
Обнаружен еще один вариант этого для iOS9/XCode 7.2: в управляемом UINavigationController подклассе UIViewController, содержащем UICollectionView, нажатие/выталкивание в стек навигации при одновременном вызове setNavigationBarHidden(_:animated:) приводит к тому, что элемент управления обновлением появляется сразу после содержимого смещение представления коллекции изменяется на 1 пт. Кроме того, элемент управления обновлением находится в полностью непрозрачном состоянии и не анимируется. Но наличие функции, похожей на вашу, в viewDidAppear решает эту проблему. - person Louis Tur; 02.06.2016

Эта ошибка возникает при создании модальной презентации над контроллером табличного представления, а также при возврате приложения из фона.

Самое простое решение — вызвать endRefreshing() в viewWillAppear(_:) и при получении уведомления UIApplicationWillEnterForeground. Вам нужно сделать и то, и другое, потому что viewWillAppear(_:) не вызывается, когда приложение возвращается из фона.

Эффект вызова endRefreshing() для экземпляра UIRefreshControl, по-видимому, заключается в том, чтобы вернуть элемент управления в правильное место в иерархии представлений и убедиться, что он продолжает правильно анимироваться при последующих обновлениях.

Не забудьте проверить, что ваш элемент управления обновлением на самом деле не обновляет.

В Свифте:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    endRefreshing()

    NotificationCenter.default.addObserver(self,
        selector: #selector(endRefreshing),
        name: Notification.Name.UIApplicationWillEnterForeground,
        object: nil)
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    NotificationCenter.default.removeObserver(self,
        name: Notification.Name.UIApplicationWillEnterForeground,
        object: nil)
}

func endRefreshing(_ notification: Notification? = nil) {
    if refreshControl?.isRefreshing == false {
        refreshControl?.endRefreshing()
    }
}

Протестировано в Xcode 7.0 для iOS 8.0 с UITableViewController, настроенным в раскадровке.

person jamesk    schedule 04.10.2015
comment
Привет, я пробовал это, но мое приложение вылетает, когда оно возвращается из фона. Он не может найти селектор. нераспознанный селектор отправлен экземпляру. Только когда возвращаюсь из фона, в остальном работает нормально :/ - person ClockWise; 30.10.2015
comment
Не помогло, но вместо этого я удалил вызовы notificationCenter, и, похоже, это работает. Еще не сталкивался с ошибкой, а это было 3 дня назад. Надеюсь, это работает :) - person ClockWise; 04.11.2015
comment
Модальное окно. Здесь вы неправильно используете термин «окно». - person Leo Natan; 14.09.2016