You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS Swift中持久化自定义对象数组的更优实现方案咨询

更优的Plant数组编码解码方案

嘿,你说得对——专门为了编码数组创建一个实现NSCoder的单例类确实有点冗余,这里有两个更简洁的方案,看哪个更适合你的场景:

方案一:让Plant类直接遵守NSCoding协议(推荐)

最符合面向对象设计的方式,就是让Plant自己负责自身的编码和解码逻辑,毕竟它最清楚自己的属性。这样你后续不管是单独存一个Plant还是存数组,都能直接用NSKeyedArchiver/NSKeyedUnarchiver,完全不需要额外的类。

举个OC的代码例子:

Plant.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface Plant : NSObject <NSCoding>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *species;
@property (nonatomic, strong) UIImage *icon;
@end

Plant.m

#import "Plant.h"

@implementation Plant

// 编码方法
- (void)encodeWithCoder:(NSCoder *)coder {
    [coder encodeObject:self.name forKey:@"name"];
    [coder encodeObject:self.species forKey:@"species"];
    // UIImage转成NSData再编码,避免直接编码可能出现的问题
    NSData *imageData = UIImagePNGRepresentation(self.icon);
    [coder encodeObject:imageData forKey:@"iconData"];
}

// 解码方法
- (nullable instancetype)initWithCoder:(NSCoder *)coder {
    if (self = [super init]) {
        self.name = [coder decodeObjectForKey:@"name"];
        self.species = [coder decodeObjectForKey:@"species"];
        NSData *imageData = [coder decodeObjectForKey:@"iconData"];
        self.icon = [UIImage imageWithData:imageData];
    }
    return self;
}

@end

之后存数组就非常简单了:

// 保存Plant数组
NSArray *plants = @[plant1, plant2];
NSString *filePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"plants.archive"];
[NSKeyedArchiver archiveRootObject:plants toFile:filePath];

// 读取Plant数组
NSArray *savedPlants = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];

方案二:不修改Plant类,直接在编码时处理属性

如果你暂时不想修改Plant类的代码,也可以不用单独创建单例,直接在保存/读取的逻辑里手动处理每个Plant的属性:

保存逻辑

NSMutableArray *encodedPlants = [NSMutableArray array];
for (Plant *plant in plantsArray) {
    NSMutableDictionary *plantDict = [NSMutableDictionary dictionary];
    plantDict[@"name"] = plant.name;
    plantDict[@"species"] = plant.species;
    plantDict[@"iconData"] = UIImagePNGRepresentation(plant.icon);
    [encodedPlants addObject:plantDict];
}
// 把字典数组存起来
NSString *filePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"plants.plist"];
[encodedPlants writeToFile:filePath atomically:YES];

读取逻辑

NSString *filePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"plants.plist"];
NSArray *savedDicts = [NSArray arrayWithContentsOfFile:filePath];
NSMutableArray *plants = [NSMutableArray array];
for (NSDictionary *dict in savedDicts) {
    Plant *plant = [[Plant alloc] init];
    plant.name = dict[@"name"];
    plant.species = dict[@"species"];
    plant.icon = [UIImage imageWithData:dict[@"iconData"]];
    [plants addObject:plant];
}

这个方案不用改Plant类,但缺点是每次属性变动都要同步修改保存和读取的代码,扩展性不如方案一。

总的来说,方案一是最推荐的——让对象自己管理编码解码,逻辑更清晰,后续维护也更方便,完全不需要额外的单例类来做这件事~

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:55:36