Подтвердить что ты не робот

Несогласованный сбой при отправке в facebook с использованием FBNativeDialogs на iOS6.0

Я уже некоторое время борюсь с этой проблемой, и я просто не могу воспроизвести ее достаточно точно, чтобы описать конкретный вариант использования. По существу, то, что я делаю, выдает запрос на открытие родного диалогового окна общего доступа к iOS 6.0 Facebook (с использованием iOS SDK для Windows 3.1.1):

if ([[SocialManager sharedManager] isNativeFacebookShareDialogAvailable]) {

        if (!url) {
            url = [NSURL URLWithString:@""];
        }

        if (!imageUrl) {
            imageUrl = [NSURL URLWithString:@""];
        }

        dispatch_async(backgroundQueue, ^{

            NSData *imageData  = [NSData dataWithContentsOfURL:imageUrl];
            UIImage *image     = [UIImage imageWithData:imageData];

            if (!image) {
                image = [[UIImage alloc] init];
            }

            if ([FBNativeDialogs canPresentShareDialogWithSession:[FBSession activeSession]]) {

                dispatch_async(dispatch_get_main_queue(), ^{
                    [FBNativeDialogs presentShareDialogModallyFrom:sender initialText:initialText images:@[image] urls:@[url] handler:^(FBNativeDialogResult result, NSError *error) {
                        if (error) {
                            failBlock([[error userInfo] description]);
                        } else {
                            if (result == FBNativeDialogResultSucceeded) {
                                completionBlock();
                            } else if (result == FBNativeDialogResultCancelled) {
                                failBlock(@"User cancelled");
                            } else if (result == FBNativeDialogResultError) {
                                failBlock(@"Unknown error");
                            }
                        }
                    }];
                });

            } else {
                LogErr(@"Can't display native share dialog for active session");
            }
        });
    }

Сразу после вызова presentShareDialogModallyFrom:sender я либо получаю следующий журнал сбоев:

*** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSArrayM: 0x1d161490> was mutated while being enumerated.'
*** First throw call stack:
(0x32ede2a3 0x326b097f 0x32eddd85 0x35da094d 0x32edb62f 0x35da07f5 0x35e7e5e5 0x35e0ccd7 0x35e0cb6d 0x372c490f 0x35e0ca61 0x35e160d5 0x372b783b 0x35e160b1 0x372b711f 0x372b699b 0x372b6895 0x372c5215 0x372c53b9 0x36f5fa11 0x36f5f8a4)
libc++abi.dylib: terminate called throwing an exception

ИЛИ Я не вижу сбоя, и появляется диалоговое окно с родным общим доступом.

Стек подразумевает вызов в потоке с именем UIRemoteViewControllerCreationRequest в этом пункте, вот 2 примера для двух разных сбоев: enter image description hereenter image description here

Спасибо за помощь

4b9b3361

Ответ 1

После большого количества экспериментов с моим приложением и изучения источника SDK в Facebook я понял три вещи:

  • Создание SLComposeViewController самостоятельно не помогает. Facebook SDK довольно прост в этом, он просто создает контроллер точно так же, как код в ответе с бонусом.

  • Когда вы авторизуете сеанс FB, ваше приложение деактивируется один или несколько раз. Это вызвано появлением предупреждений о подтверждении.

  • UIRemoteViewController - это фактически SLComposeViewController, который запускается в другом процессе.

Что вызвало мою ошибку?

  • Пользователь подтверждает разрешения FB
  • Это вызывает applicationDidBecomeActive:
  • Он также вызывает обратный вызов FB для представления диалога.
  • My applicationDidBecomeActive: что-то делал с пользовательским интерфейсом, что не должно было быть сделано, когда появлялись диалоговые окна FB (перезагрузка таблицы).

Кроме того, есть еще одна вещь, о которой нужно быть осторожностью - обработчик presentShareDialogModallyFrom... не вызывается в каком-либо конкретном потоке (см. SLComposeViewController docs). Это означает, что вы должны использовать dispatch_async(dispatch_get_main_queue(), ...) из обработчика, если вы обновляете его.

EDIT: Очевидно, что на предыдущих шагах были зафиксированы некоторые сбои, но одна из аварий не была решена. После многих поисковых запросов и поиска на форумах Apple Developer, я думаю, что в iOS 6 есть ошибка, связанная с удаленными контроллерами, и с помощью UIAppearance, особенно внешний вид UINavigationBar. В настоящее время я удаляю использование UIApperance из своего приложения.

Ответ 2

Это очень странный способ опубликовать сообщение в Facebook. Вот гораздо более простой способ, который никогда не сбой.

ViewController.h

#import <UIKit/UIKit.h>
#import <Social/Social.h>
#import <Accounts/Accounts.h>

@interface ViewController : UIViewController {
SLComposeViewController *mySLComposerSheet;
}
- (IBAction)PostToFacebook:(id)sender;

@end

ViewController.m @implementation ViewController

- (IBAction)PostToFacebook:(id)sender {
mySLComposerSheet = [[SLComposeViewController alloc] init];
mySLComposerSheet = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
[mySLComposerSheet setInitialText:@"Place Text Here"];
[self presentViewController:mySLComposerSheet animated:YES completion:nil];
}
@end

При необходимости здесь есть видео .

Ответ 3

Извините, некоторые из них довольно угадывают, но я думал, что попробую:

Вы уверены, что canPresentShareDialogWithSession безопасен для вызова из потока, отличного от UI?

У вас есть строка в обоих стеках _NSDictionaryEnumerate. Похоже, что из более высоких функций что-то вызывает enumerateKeysAndObjectsUsingBlock:.

Основываясь на вашей заметке о сбоях в работе сразу после [presentShareDialogModallyFrom: отправитель]. Есть ли что-то освобождающееся, когда вид отправителя исчезает?

Переменное "изображение" либо сохраняется, либо автореализовано в зависимости от того, какой путь кода он принял.

Ответ 4

Я думаю, что проблема в том, что Уолт уже сказал. В вашем коде что-то делается вне основного потока.

В журнале сбоев вы можете увидеть, что кто-то устанавливает внешний вид (UIAppearance) на некоторый элемент пользовательского интерфейса из потока, отличного от UI. Это проблема. Эта операция ДОЛЖНА выполняться ТОЛЬКО в потоке пользовательского интерфейса (main).

Ответ 5

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

В вашем случае, я думаю, что-то в SDK для Facebook представляет что-то из фонового потока.

Я обновлю после того, как подтвержу, что мое исправление работает.

Ответ 6

Это ошибка в iOS 6 и Social Framework, посмотрите здесь Внешний вид UINavigationBar и ошибка на Facebook-листах

Как это решить?

Вместо использования [UINavigationBar appearance] используйте [UINavigationBar appearanceWhenContainedIn:...]

Вы можете использовать пользовательский класс для своего навигационного контроллера (например, CustomNavigationController), а затем применить его по внешнему виду:

[UINavigationBar appearanceWhenContainedIn:[CustomNavigationController class], nil]

Из моих экспериментов он должен использоваться для всех методов appearance, а не только UINavigationBar, но также UIBarButtonItem и т.д. (на каждый отправляемый объект appearance)

Ответ 7

Я думаю, что вы знаете, что очевидно, но однажды я встретил эту ошибку, и это был NSMutableArray, который был мутирован, будучи перечисляемым внутри оператора for..in.

Посмотрите на NSMutableArray, вы найдете свою ошибку.

Кстати, если вы нацеливаете ios6, почему бы вам не использовать социальную инфраструктуру с собственной реализацией facebook?