You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

iOS Objective-C应用优化:减少冗余API调用并本地存储数据的设计方案

优化iOS Objective-C应用的JSON数据缓存与复用方案

看起来你已经把基础功能跑通了,但想优化缓存策略、减少重复API调用——这个需求非常合理,毕竟接口返回的是固定168个对象的数组,完全没必要每次切换UI控件都去请求接口。下面是我整理的几个实用优化方案,都是Objective-C开发里的常用实践:

一、核心优化思路

一次性请求并缓存全量168条数据到本地,后续所有UI控件的展示需求都直接从本地读取对应片段,彻底避免重复API请求。

二、本地存储方案选择(针对你的数据规模)

根据168条结构化数据的特点,推荐两种轻量高效的存储方案,你可以根据后续需求选择:

1. NSUserDefaults(快速上手,适合小体量数据)

优点:代码极简,无需额外依赖,完全能hold住168条数据的存储需求。
缺点:如果未来数据量大幅增长,可能会有性能问题,但当前场景下完全够用。

代码示例:

存储全量数据(请求成功后执行)
// 假设你已经通过GET请求拿到了NSArray *responseArray
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
// 你的数组元素都是NSNumber,直接存就行
[defaults setObject:responseArray forKey:@"CachedHourlyDataset"];
// 给缓存加个过期时间(比如24小时后重新请求,可按需调整)
[defaults setObject:[NSDate date] forKey:@"DatasetCacheTimestamp"];
[defaults synchronize];
读取缓存并判断是否有效
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSArray *cachedData = [defaults objectForKey:@"CachedHourlyDataset"];
NSDate *cacheTime = [defaults objectForKey:@"DatasetCacheTimestamp"];

// 检查缓存是否存在且未过期(这里设为24小时有效期)
NSTimeInterval timeElapsed = [[NSDate date] timeIntervalSinceDate:cacheTime];
BOOL isCacheValid = cachedData != nil && timeElapsed < 24*60*60;

if (isCacheValid) {
    // 直接取对应片段给Button1展示(注意Objective-C数组索引从0开始,obj1对应index0)
    NSRange targetRange = NSMakeRange(0, 10); // obj1到obj10
    NSArray *button1Data = [cachedData subarrayWithRange:targetRange];
    // 把数据传给UI控件渲染
    [self renderButton1Data:button1Data];
} else {
    // 缓存失效,发起新请求,请求成功后再存入本地
    [self fetchLatestDataAndCache];
}

2. Core Data(适合未来扩展场景)

如果后续你需要更复杂的数据查询(比如按day或hour筛选),或者数据规模可能变大,Core Data会更灵活。你可以创建一个HourlyData实体,包含valuedayhour三个属性,把168条数据存入Core Data,后续直接查询对应范围的数据即可。

简单查询示例:

// 获取前10条数据(对应obj1-obj10)
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"HourlyData"];
fetchRequest.fetchLimit = 10;
// 按day和hour排序,保证顺序和接口返回一致
fetchRequest.sortDescriptors = @[
    [NSSortDescriptor sortDescriptorWithKey:@"day" ascending:YES],
    [NSSortDescriptor sortDescriptorWithKey:@"hour" ascending:YES]
];

NSError *error;
NSArray *button1Data = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (!error) {
    [self renderButton1Data:button1Data];
}

三、封装数据管理单例,统一处理逻辑

为了避免各个UI控件重复写缓存判断、数据切片的代码,建议封装一个单例数据管理类(比如DataManager),把缓存读取、数据请求、切片逻辑都集中在这里:

// DataManager.h
@interface DataManager : NSObject
+ (instancetype)sharedManager;
// 获取指定范围的数据
- (NSArray *)dataInRange:(NSRange)range;
// 手动刷新数据(比如用户下拉刷新)
- (void)refreshDataWithCompletion:(void(^)(BOOL success))completion;
@end

// DataManager.m
@implementation DataManager
static DataManager *_sharedInstance;

+ (instancetype)sharedManager {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedInstance = [[DataManager alloc] init];
    });
    return _sharedInstance;
}

- (NSArray *)dataInRange:(NSRange)range {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSArray *cachedData = [defaults objectForKey:@"CachedHourlyDataset"];
    NSDate *cacheTime = [defaults objectForKey:@"DatasetCacheTimestamp"];
    NSTimeInterval timeElapsed = [[NSDate date] timeIntervalSinceDate:cacheTime];
    
    if (cachedData && timeElapsed < 24*60*60) {
        // 防止range越界
        if (range.location + range.length > cachedData.count) {
            range.length = cachedData.count - range.location;
        }
        return [cachedData subarrayWithRange:range];
    }
    // 缓存失效,后台刷新数据,先返回空
    [self refreshDataWithCompletion:nil];
    return nil;
}

- (void)refreshDataWithCompletion:(void(^)(BOOL success))completion {
    // 用NSURLSession发起GET请求(替换成你的API地址)
    NSURL *apiURL = [NSURL URLWithString:@"https://your-api-url.com/data"];
    NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:apiURL completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (!error && data) {
            NSError *jsonError;
            NSArray *responseArray = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
            // 验证数据完整性(必须是168条)
            if (responseArray && responseArray.count == 168) {
                NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
                [defaults setObject:responseArray forKey:@"CachedHourlyDataset"];
                [defaults setObject:[NSDate date] forKey:@"DatasetCacheTimestamp"];
                [defaults synchronize];
                if (completion) completion(YES);
                // 发送通知,告诉UI控件数据已更新
                [[NSNotificationCenter defaultCenter] postNotificationName:@"HourlyDataUpdated" object:nil];
            } else {
                if (completion) completion(NO);
            }
        } else {
            if (completion) completion(NO);
        }
    }];
    [task resume];
}
@end

然后在你的UI控件里,只需要简单调用这个单例的方法:

// Button1点击事件
- (IBAction)button1Tapped:(UIButton *)sender {
    NSArray *targetData = [[DataManager sharedManager] dataInRange:NSMakeRange(0, 10)];
    if (targetData) {
        [self renderButton1Data:targetData];
    } else {
        // 显示加载中,等待数据更新通知
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onDataUpdated:) name:@"HourlyDataUpdated" object:nil];
    }
}

- (void)onDataUpdated:(NSNotification *)note {
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"HourlyDataUpdated" object:nil];
    NSArray *targetData = [[DataManager sharedManager] dataInRange:NSMakeRange(0, 10)];
    [self renderButton1Data:targetData];
}

四、额外优化小技巧

  • 数据完整性校验:每次请求新数据后,一定要检查数组长度是否为168,避免脏数据存入本地。
  • 可配置缓存有效期:把24小时的硬编码改成可配置的参数,方便后续调整。
  • 离线友好:如果缓存过期但没有网络,依然展示旧缓存数据,提升用户体验(可以在refreshDataWithCompletion里判断网络状态)。

内容的提问来源于stack exchange,提问作者humble_pie

火山引擎 最新活动