Более одного RKObjectManager одновременно (RestKit) - PullRequest
13 голосов
/ 01 июня 2011

Я тестирую RestKit и мне нужен доступ к различным BaseUrls, а также иногда доступ к веб-службе с одним и тем же baseUrl из разных мест "одновременно", наконец, мне также нужно получить доступ к одному и тому же baseUrl с разными ressourcePaths в одном контроллере.

В моем делегате приложения я настроил синглтон RKObjectManager следующим образом.

RKObjectManager *objectManager = [RKObjectManager objectManagerWithBaseURL:kBaseUrl];
[objectManager registerClass:[EntityClass1 class] forElementNamed:@"element1"];
[objectManager registerClass:[EntityClass2 class] forElementNamed:@"element2"];
.
.
.
etc.

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

В MyViewController, который реализует RKObjectLoaderDelegate, у меня будут два метода:

- (void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects:(NSArray *)objects         {
    //stuff with result
}

- (void)objectLoader:(RKObjectLoader *)objectLoader didFailWithError:(NSError *)error {
    //stuff with error    
}

Это не вызывает проблем, когда MyViewController использует один синглтон RKObjectManager для доступа к одному ressourcePath с однимbaseUrl.

Если я запускаю разные запросы следующим образом:

[[RKObjectManager sharedManager] loadObjectsAtResourcePath:FLICKRPath delegate:self]
[[RKObjectManager sharedManager] loadObjectsAtResourcePath:FOURSQUAREPath delegate:self]

и т. д., в пределах одного и того же MyController моя проблема заключается в том, что FLICKRPath и FOURSQUAREPath, конечно, имеют разные baseUrl, ноRKObjectManager только один?

Если я получуэто работает и может иметь разные RKObjectManager другая проблема возникает.Методы делегатов didLoadObjects и didFailWithError будут получать результаты от обоих RKObjectManager, и я не вижу другого способа отличить их, кроме их baseUrls.Потенциальное сравнение каждого возвращаемого значения с baseUrl и, что еще хуже, ressourcePath, в методе делегата меня совсем не привлекает.

Если у меня есть разные RKObjectManagers, я думаю, я мог бы передать им разные делегаты и создать классыпредназначенный для работы с возвращаемыми значениями из различных baseUrls и ressourcePaths.Это означало бы, что мне нужно было построить еще одну абстракцию поверх MyController и RestKit, что также кажется грязным.

У меня сильное чувство, что я поступаю неправильно, источник RestKit очень впечатляет, чтоуказывает, что я борюсь с рамками.Я был бы очень признателен за лучшее понимание практики по этому вопросу.Я просмотрел все ресурсы и примеры, которые мог найти, но не видел описанного выше варианта использования.Это всегда один RKObjectManager, один baseUrl и один ressourcePath.

Заранее спасибо.

Ответы [ 5 ]

10 голосов
/ 07 ноября 2011

Поскольку пока нет принятого ответа: использовать несколько диспетчеров объектов довольно просто, используя RestKit.

из Wiki ( Использование нескольких базовых URL-адресов (и нескольких объектов).Менеджеры ):

Первым созданным вами диспетчером объектов будет общий синглтон RestKit, используемый по умолчанию. Но создавая дополнительные диспетчеры объектов, вы можете извлекать их BaseURL по мере необходимости, просто убедитесь, чточтобы сохранить эти новые менеджеры.

RKObjectManager *flickrManager = 
    [RKObjectManager objectManagerWithBaseURL:flickrBaseUrl]; // <-- shared singleton
RKObjectManager *foursquareManager = 
    [[RKObjectManager objectManagerWithBaseURL:foursquareBaseUrl] retain]; // <-- you must retain every other instance.

В зависимости от вашего приложения вы можете захотеть поместить этот второй менеджер объектов в более доступное место, например, в сохраненное свойство в AppDelegate, поэтомучто его легко извлечь по мере необходимости. В случае, если вам необходимо различать результаты от двух (или более) менеджеров объектов, просто задайте идентификатор в userData для запросов.

- (void)someAction(id)sender {
        // .......
        RKObjectLoader* loader = [[RKObjectManager sharedManager] loadObjectsAtResourcePath:@"/whatever" delegate:self];
        loader.userData = @"foursquare";
        // or do this, if you need a number instead of a string
        loader.userData = [NSNumber numberWithInt:1234];
        // .......
    }

//Then when the delegate comes back you can cast it into a string or number as appropriate:
- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects {
    // .......
    NSString* source = (NSString*) objectLoader.userData;
    // or, if you did the NSNumber instead:
    NSNumber* source = (NSNumber*) objectLoader.userData;
    // .......
}
3 голосов
/ 23 октября 2012

Изменение API:

RKObjectLoader* loader = [[RKObjectManager sharedManager] loadObjectsAtResourcePath:@"/whatever" delegate:self];

не компилируется в RestKit v.0.10.3 (loadObjectsAtResourcePath: делегат: возвращает void).Однако этот метод просто переносит несколько строк кода, так что вы все равно можете получить в загрузчике и добавить userData со следующим:

RKObjectLoader *loader = [[RKObjectManager sharedManager] loaderWithResourcePath:resourcePath];
loader.userData = @"SOMEDATA";
loader.delegate = self;
loader.method = RKRequestMethodGET;
[loader send];

(добавление примечания на случай, если другие новые пользователи столкнутся с тем жепроблемы, которые я сделал).

0 голосов
/ 17 февраля 2014

Возможный подход - , чтобы ввести один синглетон для каждого базового URL .

Вы можете создавать столько RKObjectManager объектов, сколько хотите.Тем не менее, только первый станет общим.Посмотрите на initWithHTTPClient: источники .

if (nil == sharedManager) {
    [RKObjectManager setSharedManager:self];
}

Мы не можем использовать метод sharedManager по умолчанию для определения целевого менеджера объектов, но мы можем легко реализовать наш собственный синглтон.Вот пример для менеджера объектов Google Maps:

@implementation GMObjectManager

+ (GMObjectManager*)sharedManager
{
    static GMObjectManager *manager;  // keep reference
    if (!manager) {
        // init with custom base url
        NSURL *baseUrl = [NSURL URLWithString:kGMBaseUrl];  
        manager = [GMObjectManager managerWithBaseURL:baseUrl];
    }

    return manager;
}

- (id)initWithHTTPClient:(AFHTTPClient *)client
{
    self = [super initWithHTTPClient:client];
    if (self) {
        // additional initialization
    }

    return self;
}

@end

Использование:

CGObjectManager *googleMapsManager = [GMObjectManager sharedInstance];
0 голосов
/ 17 декабря 2012

Как насчет использования objectLoader. Вы найдете тип сопоставленного объекта / Class objectLoader.objectMapping.objectClass и добавите свои условия на его основе вместо URL

-(void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects:(NSArray *)objects {
    // your condition based on -> objectLoader.objectMapping.objectClass   
}

Надеюсь, это поможет

0 голосов
/ 31 августа 2012

И, кстати, поскольку свойство userData также доступно в RKRequest, вы можете использовать тот же подход для загрузки / идентификации запросов.

Например, какой-то пост-запрос:

RKClient * client = [RKClient sharedClient];
[client post:@"/your-api-path" usingBlock:^(RKRequest *request) {
    request.userData = @"<some-object-you-can-check-in-delegate-callback>";
    request.params = someParamsForRequest;
    request.delegate = <delegate you want to call when request is finished>;
}];
...