0

Example project: http://cl.ly/360k3M3a2y05

I'm playing with the Reddit API for a school project, and came across this library for using it in Objective-C/Swift.

The professor wants us to get our toes wet with Swift, which I'm happy to do, and the goal of the project is to add an extra function onto an existing website's API. (I chose Reddit obviously.)

The mentioned library doesn't have a way to get all the subscriptions for a particular user (only to get one page at a time with the option to paginate), so I want to add the option to get them all in one clean call.

I'm leveraging the method in the aforementioned library that allows you to paginate, the method looks like this:

- (NSURLSessionDataTask *)subscribedSubredditsInCategory:(RKSubscribedSubredditCategory)category pagination:(RKPagination *)pagination completion:(RKListingCompletionBlock)completion {
    NSMutableDictionary *taskParameters = [NSMutableDictionary dictionary];
    [taskParameters addEntriesFromDictionary:[pagination dictionaryValue]];

    NSString *path = [NSString stringWithFormat:@"subreddits/mine/%@.json", RKStringFromSubscribedSubredditCategory(category)];

    return [self getPath:path parameters:taskParameters completion:^(NSHTTPURLResponse *response, id responseObject, NSError *error) {
        if (!completion) return;

        if (responseObject)
        {
            // A crude check to see if we have been redirected to the login page:

            NSString *path = [[response URL] path];
            NSRange range = [path rangeOfString:@"login"];

            if (range.location != NSNotFound)
            {
                completion(nil, nil, [RKClient authenticationRequiredError]);
                return;
            }

            // Parse the response:

            NSArray *subredditsJSON = responseObject[@"data"][@"children"];
            NSMutableArray *subredditObjects = [[NSMutableArray alloc] initWithCapacity:[subredditsJSON count]];

            for (NSDictionary *subredditJSON in subredditsJSON)
            {
                NSError *mantleError = nil;
                RKSubreddit *subreddit = [MTLJSONAdapter modelOfClass:[RKSubreddit class] fromJSONDictionary:subredditJSON error:&mantleError];

                if (!mantleError)
                {
                    [subredditObjects addObject:subreddit];
                }
            }

            RKPagination *pagination = [RKPagination paginationFromListingResponse:responseObject];

            completion([subredditObjects copy], pagination, nil);
        }
        else
        {
            completion(nil, nil, error);
        }
    }];
}

My addition is rather simple, I just call this above method recursively and save the pagination after each successful request, until there's no pages left, and then return the result:

- (void)allSubscribedSubredditsInCategory:(RKSubscribedSubredditCategory)category completion:(void (^)(NSArray *subreddits, NSError *error))completion {
    RKPagination *pagination = [RKPagination paginationWithLimit:100];
    [self recursiveSubscribedSubredditsWithPagination:pagination subredditsSoFar:[NSArray array] completion:completion];
}

- (void)recursiveSubscribedSubredditsWithPagination:(RKPagination *)pagination subredditsSoFar:(NSArray *)subredditsSoFar completion:(void (^)(NSArray *subreddits, NSError *error))completion {
    [self subscribedSubredditsInCategory:RKSubscribedSubredditCategorySubscriber pagination:pagination completion:^(NSArray *newSubreddits, RKPagination *newPagination, NSError *newError) {
        // If pagination is nil, we cannot go any further and have reached the end
        if (newPagination == nil) {
            NSArray *newSubredditsSoFar = [subredditsSoFar arrayByAddingObjectsFromArray:newSubreddits];
            NSArray *subredditsWithoutDuplicates = [[NSSet setWithArray:newSubredditsSoFar] allObjects];
            completion(subredditsWithoutDuplicates, newError);
        } else {
            NSArray *newSubredditsSoFar = [subredditsSoFar arrayByAddingObjectsFromArray:newSubreddits];
            [self recursiveSubscribedSubredditsWithPagination:newPagination subredditsSoFar:newSubredditsSoFar completion:completion];
        }
    }];
}

So it looks like this in my viewDidLoad of my view controller:

RKClient.sharedClient().signInWithUsername("includedinproject", password: "includedinproject") { (error) -> Void in
    RKClient.sharedClient().allSubscribedSubredditsInCategory(.Subscriber, completion: { (subreddits, error) -> Void in
        print(subreddits)
    })          <-- error occurs here?
}

However, whenever I call it, I get an EXC_BAD_ACCESS runtime error that doesn't really provide anything other than a memory address, and it appears to be caused at the end of the method in viewDidLoad, as labeled above.

The weird thing that occurs, however, is that this only occurs seemingly on the iPhone 4s simulator. If I build it to run on say, the newest 6s, it works fine. I'm puzzled (it has to work on all simulators for full points).

I went to my professor about it and he has no idea. We emulated the project in Objective-C (rebuilt the project as an Objective-C one) and the call seems to work fine.

My professor even did something with Instruments (not much experience myself) looking at "Zombies" and enabled it in the project as well, and nothing seemed to give him information either, we're both pretty confused.

What is going on here that's causing it to work great in Objective-C, and in Swift if the device isn't a 4s? Example project is at the top.

Doug Smith
  • 29,668
  • 57
  • 204
  • 388
  • It seems to be a problem with the CoreFoundation framework. I tested it on an iPhone 4S with iOS 8.4 and it crashed without even calling the reddit code; it is simply failing to load the app. There was a similar report listed in beta http://stackoverflow.com/questions/32211894/xcode-7-beta-6-dyld-nsarray0-crash You could try the suggested fix of adding the platform information to your podfile. Personally, this is why I won't use Swift for real projects yet. It is just flakey – Paulw11 Oct 29 '15 at 00:56
  • @Paulw11 I'm seemingly able to get past that error occurring (it sometimes does, not always) by using the `platform` specifier as mentioned in your link, but the error above still occurs without fail. – Doug Smith Oct 29 '15 at 05:33
  • Yep. Stick with Objective C until Apple gets their *stuff* together with Swift – Paulw11 Oct 29 '15 at 05:34
  • @Paulw11 That's unfortunate. I'd still like a solution that I can depend on in Swift though, workaround or otherwise. – Doug Smith Oct 29 '15 at 05:35
  • Swift is probably OK on iOS 9 or on 64 bit devices. Maybe. – Paulw11 Oct 29 '15 at 05:35

0 Answers0