【问题标题】:Caching asynchronous responses in iOS在 iOS 中缓存异步响应
【发布时间】:2014-07-13 03:06:45
【问题描述】:

如何将完成处理程序的响应保存在静态变量中?在示例代码中

GTLQueryTictactoe *query = [GTLQueryTictactoe queryForScoresList];
[service executeQuery:query completionHandler:^(GTLServiceTicket *ticket, GTLTictactoeScores *object, NSError *error) {
  NSArray *items = [object items];
  // Do something with items.
}];

上面写着// Do something with items 我想将items 保存在一个静态变量中 以便任何人都可以致电getMyItems 获取物品。我该怎么做?我的意思是在 Objective-c 意义上的静态变量,其中值被记住。

图像上面的 sn-p 在类 Dog 内。而Paper 类将需要使用这些项目,以便从Paper 类内部调用getMyItems。我希望不必将这些项目保存在 Core Data 中。

现在我认为我的解决方案涉及在块外声明static NSArray *items。但是那么其他方法将如何访问它呢?这甚至是一个好的解决方案吗?

下面的“解决方案”会因为我在块内调用self而导致内存泄漏吗?

@implementation Dog

static NSArray *items;

-(void) callToServer
{
GTLQueryTictactoe *query = [GTLQueryTictactoe queryForScoresList];
    [service executeQuery:query completionHandler:^(GTLServiceTicket *ticket, GTLTictactoeScores *object, NSError *error) {
      self.items = [object items];
    }];
}


-(NSArray *) getMyItems
{
  return items;
}
@end

【问题讨论】:

  • 我认为这个实现不会很好。如果有人运行 callToServer 然后立即调用 getMyItems 会发生什么?
  • 您的目标是缓存响应,以便将来无需等待数据吗?即使数据可能被缓存,您也不应该假设它是这样的,因此您的“getter”方法需要使用回调块进行异步。
  • @CrimsonChris callToServer 将包含一个 NSNotification。为简单起见,我将其省略。假设以userInfo 发送数据是不够的,我希望能够缓存数据,以便以后调用getMyItems 可以工作。所以真的不用担心比赛条件。如何使用静态变量进行缓存?
  • 似乎是一个糟糕的设计。块比通知更简单,更不容易出错。考虑将您的两种方法合二为一。您的签名可能类似于getDataWithCallback:,并且可以从服务器加载或使用缓存的响应(如果可用)。
  • @CrimsonChris 你所说的刚刚飞过我的脑海。我不太清楚该怎么做。你介意显示一个代码 sn-p 吗?

标签: ios objective-c callback objective-c-blocks completionhandler


【解决方案1】:

请注意,此解决方案绝不是线程安全的。将其作为更灵活解决方案的起点。

MyLoader.h

typedef void(^CallbackBlock)(id object);

@interface MyLoader : NSObject
+ (void)loadItemsWithCallback:(CallbackBlock)callback; //callback takes an NSArray* of MyData*
+ (void)invalidateCache;
@end

MyLoader.m

#import "MyLoader.h"

static NSArray *myCachedItems;

@implementation MyLoader

+ (void)loadItemsWithCallback:(CallbackBlock)callback {
    if (myCachedItems == nil) {
        [self executeQuery:query completionHandler:^(GTLServiceTicket *ticket, GTLTictactoeScores *object, NSError *error) {
            myCachedItems = [object items];
            if (callback) callback(myCachedItems);
        }];
    } else {
        if (callback) callback(myCachedItems);
    }
}

+ (void)invalidateCache {
    myCachedItems = nil;
}

@end

使用 MyLoader

[MyLoader loadItemsWithCallback:^(NSArray *items) {
    /* When this callback executes, we have either just received data from the server
     * or cached data depending on if this request has been run already */
    self.items = items;
    [self reloadData]; //if this is for a UITableView
}];

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-02-11
    • 2011-07-01
    • 1970-01-01
    • 2014-07-05
    • 2011-10-05
    • 1970-01-01
    • 2020-05-16
    • 2013-08-29
    相关资源
    最近更新 更多