message sent to deallocated instance using Pintere

2020-07-18 03:53发布

I'm using the Pinterest iOS SDK to share an item in my iPad app. The following snippet of code will always crash with a message sent to deallocated instance on the line with the comment:

NSString *clientId = [NSMutableString stringWithString:@"1431665"];
NSLog(@"clientId: %@", clientId);
Pinterest *pinterest = [[Pinterest alloc] initWithClientId:clientId];
NSLog(@"gone: %@", clientId); // <- CRASH!

I'm using NSMutableString stringWithString to simulate the conditions in my app. I don't actually use that line in my code.

Even if don't output the clientId on the last line, the app crashes when leaving the block. I assume it's because ARC is trying to release the reference which has already been deallocated.

It seems like the Pinterest SDK must be doing something wonky and trashing the string I'm passing in. Is there some way I can get around this while they fix their code?

EDIT 1

Simplified the test case.

EDIT 2

It looks like the Pinterest SDK is consuming the clientId argument. Based on the clang ARC documentation, the way to indicate this to clang is to indicate this with __attribute((ns_consumed)).

New question: Is it possible to indicate this to ARC without modifying the signature of the method to add the attribute?

EDIT 3

So this works, but it's ugly as sin? Is there another way?

NSString *clientId = [NSMutableString stringWithString:@"1431665"];
[clientId performSelector:NSSelectorFromString(@"retain")]; // <- UGLY!
NSLog(@"clientId: %@", clientId);
Pinterest *pinterest = [[Pinterest alloc] initWithClientId:clientId];
NSLog(@"gone: %@", clientId);

2条回答
爷、活的狠高调
2楼-- · 2020-07-18 04:34

My current workaround, which seems to be the least hacky of the ideas so far is this wrapper class that doesn't use ARC:

+ (void) createPinWithClientId:(NSString *)clientId
                      imageURL:(NSURL *)imageURL
                     sourceURL:(NSURL *)sourceURL
                   description:(NSString *)descriptionText {

    Pinterest *pinterest = [[Pinterest alloc] initWithClientId:clientId];
    [pinterest createPinWithImageURL:imageURL
                           sourceURL:sourceURL
                         description:descriptionText];
}

The key is to disable ARC for the class, which keeps the runtime from deallocating the clientId.

查看更多
祖国的老花朵
3楼-- · 2020-07-18 04:40

What I did was make a static variable that represented the Pinterest class:

//I put this outside my @implementation code at the top of my m file
static Pinterest *_pinterest = nil;

// instantiating
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    _pinterest = [[Pinterest alloc] initWithClientId:clientId];
});

I think that Pinterest assumed that everyone would use their class as a static singleton because that's probably what they do internally. To be fair, I don't foresee using multiple client ID's with a single app in most cases. I agree, though, this is a stupefying oversight on their part. They didn't even document this behavior, what were they thinking?!

查看更多
登录 后发表回答