MCSession занимает много времени для освобождения

Я использую Multipeer-Connectivity.

Когда сеанс заканчивается, приложение переходит в главное меню, и все сетевые данные освобождаются, а затем освобождаются.

Но мой метод Dealloc вызывается в основном потоке, и объекту MCSession требуется очень много времени, чтобы освободить себя, я не знаю почему, и, следовательно, экран главного меню зависает.

Если кто-то знает, почему MCSession может быть таким длинным, мне интересно. Но если это исходит от самой MCSession, является ли это хорошим решением для этого?

-(void) dealloc
{
    //... other release

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [_session release];
        _session = nil;
    });

    [super dealloc];
}

EDIT: нет, это определенно не очень хорошее решение, потому что оно приводит к сбою моего приложения. В любом случае, другие идеи?


person Martin    schedule 31.01.2014    source источник


Ответы (2)


Когда вы вызываете [_session release], поскольку _session является Ivar, компилятор заменит эту строку на [self->_session release], а блок сохранит self вместо iVar _session. Здесь у вас есть 2 проблемы:

  1. Попытка сохранить объект (я), который освобождается.

  2. Когда очередь будет выполнена, она вызовет self, который уже освобожден.

Следующее решение создает локальную переменную, которая указывает на тот же адрес, что и iVar, и освобождает ее внутри блока, блок не будет захватывать себя.

-(void) dealloc
{
    //... other release
    MCSession* localSession = _session;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [localSession release];
    });

    [super dealloc];
}
person bsarr007    schedule 03.02.2014
comment
Вы можете объяснить, почему это работает? - MCSession нормально работает в основном потоке. Отключение занимает много времени, и это то, что он делает, прежде чем отпустить. В течение этого длительного времени основной поток блокируется. При размещении этой задачи в отдельном потоке основной поток не блокируется, и ваше приложение продолжает работу, пока MCSession блокирует новый поток. В качестве альтернативы вы можете поместить свою следующую задачу в новую ветку. Блокировка потока не препятствует выполнению следующих строк кода, но не будет анимаций вроде UIAlerts или presentViewController. - person Peter B. Kramer; 08.04.2014
comment
Как вы можете видеть, решение, которое я предложил, состоит в том, чтобы просто не пытаться сохранить себя (используя iVar) внутри Dealloc, что является ошибкой. - person bsarr007; 09.04.2014

Решение bsarr007 будет работать для проектов, не связанных с ARC. Если вы используете ARC, вы можете попробовать следующее:

__block MCSession *localSession = _session;
_session = nil;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
    oldSession = nil;
});

Меня устраивает. Что я здесь делаю, так это увеличиваю количество ссылок на объект MCSession, создавая новую локальную переменную, которая указывает на этот объект, поэтому она не будет немедленно освобождена при установке _session = nil. После этого я запускаю асинхронно код, который уменьшает счетчик ссылок моего объекта MCSession, используя фоновую очередь.

person Darrarski    schedule 20.03.2014
comment
Да, мое решение, как и вопрос, относится к проекту, отличному от ARC. - person bsarr007; 09.04.2014