尝试使用Twitter ACAccount时出现奇怪的行为

19

最近我一直在尝试使用新的 Social.Framework 和其中的 SLRequest,两者都可以在 iOS 6 及以上版本使用。但是,当我尝试发送请求时,却遇到了一个令人惊讶的崩溃错误。

我在 Facebook 和 Twitter 账户上都遇到了这个问题,所以我知道这不是与某一个账户特定问题有关。它必须与 ACAccount 对象有关,我是通过以下方式获取该对象:

if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"6.0")) {
    //iOS 6
    if (_twitterEnabled) {
        if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeTwitter]) {
            //Set up account
            [accountStore requestAccessToAccountsWithType:accountTypeTwitter options:nil completion:^(BOOL granted, NSError *error) {
                if (granted && !error) {
                    //Get account and get ready to post.
                    NSArray *arrayOfAccounts = [accountStore accountsWithAccountType:accountTypeTwitter];
                    if ([arrayOfAccounts count] > 0) {
                        _twitterAccount = [arrayOfAccounts lastObject];
                    }
                }
            }];
        }
    }
    if (!_facebookEnabled) {
        ACAccountType *accountTypeFacebook = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
        if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) {
            NSArray *permissions = @[@"user_about_me",@"user_likes",@"email"];
            NSMutableDictionary *options = [NSMutableDictionary dictionaryWithObjectsAndKeys:kFacebookAppIDString, ACFacebookAppIdKey, permissions, ACFacebookPermissionsKey, ACFacebookAudienceFriends, ACFacebookAudienceKey, nil];
            [accountStore requestAccessToAccountsWithType:accountTypeFacebook options:options completion:^(BOOL granted, NSError *error) {
                if (granted && !error) {
                    [options setObject:@[@"publish_stream",@"publish_actions"] forKey:ACFacebookPermissionsKey];
                    [accountStore requestAccessToAccountsWithType:accountTypeFacebook options:options completion:^(BOOL granted, NSError *error) {
                        if (granted && !error) {
                            NSArray *arrayOfAccounts = [accountStore accountsWithAccountType:accountTypeFacebook];
                            if ([arrayOfAccounts count] > 0) {
                                _fbAccount = [arrayOfAccounts lastObject];
                            }

                        }
                    }];
                }
            }];
        }
    }
}

_twitterAccount和_fbAccount都是ACAccount对象,在从Account Store检索到相关帐户时我会将其存储在这些对象中。

问题出现在后来我尝试使用这些对象时(为了简洁起见,这里只发布Twitter方法):

        NSDictionary *twitterMsg = @{@"status" : message};
        if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"6.0")) {
            SLRequest *postRequest = [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodPOST URL:kTwitterUpdateStatusURL parameters:twitterMsg];
            [postRequest setAccount:_twitterAccount];
            [postRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
                NSLog(@"Twitter HTTP response: %d", [urlResponse statusCode]);
            }];
        }

当我在postRequest中调用setAccount:时,我收到了一个异常,错误信息为“该请求的帐户类型无效”,显然这是错误的。我尝试调试代码,奇怪的是_twitterAccount上的accountType在被发送到ACAccount对象之前被设置为nil。更奇怪的是,如果我放置

NSLog(@"%@",_twitterAccount);

就在下方

_twitterAccount = [arrayOfAccounts lastObject]

在第一段代码中,它能正常工作。

我已经检查了我的代码,我不认为我做错了任何事情,所以我认为这可能是框架的一个bug?看起来ACAccountType被释放了,但它不应该被释放,但我想检查一下是否有人能发现我的代码有什么问题引起了这个问题,并/或者找到一个解释这个问题的解决方法,而我自己无法解决。

谢谢

更新

似乎还有其他人遇到了同样的问题,我接受了其中一个答案,因为它实际上解决了问题,但我会继续寻找任何人能够找到这个问题的解释。

4个回答

31

当我使用SLRequest对通过以下两种方式检索到的帐户进行操作时,也会收到“此请求的帐户类型无效”的错误提示:

ACAccountStore *account_store = [[ACAccountStore alloc] init];
ACAccountType *account_type_twitter = [account_store accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
// A.
NSArray *accounts = [account_store accountsWithAccountType:account_type_twitter]; 
// B.
NSString *account_id = @"id from doing account.identifier on one of the above";
ACAccount *account = [account_store accountWithIdentifier:account_id];

NSLog打印的帐户所有信息都按预期填充,但类型设置为null。猜测这是苹果SDK的一个错误。按照以下步骤对我的帐户进行了修复,因此我可以在SLRequest中使用它们:

ACAccountType *account_type_twitter = [account_store accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
account.accountType = account_type_twitter;

嗨,谢谢您的回答。我已经得出了这个结论,明确设置accountType似乎会保留ACAccountType对象。(就像将其打印到NSLog一样)。我会进一步研究此主题并看看发生了什么。 - Alejandro Benito-Santos
哇,这解决了我几个小时的工作,只用了2分钟。谢谢。 - Natan R.
1
这似乎有点像黑客行为;你应该首先尝试下面的解决方案(即保留帐户存储)。 - Jesse Rusak
1
就像其他解决方案所说,您需要保留帐户存储对象(ACAccountStore)。 - Daniel

17

你需要保留 ACAccountStore:

@property (nonatomic, strong) ACAccountStore *accountStore;

ACAccount文档从未明确说明必须保留ACAccountStore,但它指出:

"要从账户数据库创建和检索帐户,必须创建ACAccountStore对象。每个ACAccount对象都属于单个ACAccountStore对象。"

当您调用时:

NSArray *accounts = [accountStore accountsWithAccountType:accountType]

数组中的这些accountStore对象不一定从数据库中获取其所有属性。有些属性(如accountType)只在需要时从Accounts数据库中检索。这就是你记录账户并且一切都神奇地工作的奇怪行为所在。当你记录账户时,ACAccountStore对象仍然存在于内存中,并且日志记录导致检索AccountType属性。此时,AccountType与ACAccount一起保留,并且即使ACAccountStore被释放后,一切仍能正常工作。

这是真正的修复方法,而不是尝试已接受答案中建议的修复方法。 - DD_

5
你是否保留了用于获取账户数组的ACAccountStore?

1

我使用这个代码没有问题。(只针对Twitter)

ACAccountStore *accountStore = [[ACAccountStore alloc] init];
ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
[accountStore requestAccessToAccountsWithType:accountType options:nil completion:^(BOOL granted, NSError *error) {
    if (!granted) {
        NSLog(@"Access denied.");
    }
    else {
        NSArray *accounts = [accountStore accountsWithAccountType:accountType];
        if (accounts.count > 0) {
            twitterAccount = [accounts objectAtIndex:0];
        }
    }
}];

我觉得是关于accountStore初始化问题的事情吧?

Twitter的官方参考文档在这里。 Twitter: 使用TWRequest进行API请求


嗨,感谢您的回复。 肯定不是这样的,如果是这种情况,那么更可能是accountType的问题。我已经在运行您的代码,但是如果您仔细阅读我的问题,问题在于此代码正在单例中运行,这可能是问题所在。 - Alejandro Benito-Santos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接