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

如何在Core Data中将CMTime作为Transformable属性存储?

解决Core Data Transformable存储CMTime的问题

我之前也折腾过用Core Data存CMTime这个C结构体,刚好能给你分享下可行的方案,核心是要做自定义值转换器+手动包装C对象,具体步骤如下:

1. 创建自定义NSValueTransformer子类

因为CMTime是C结构体,没法直接被默认的Transformable处理,我们需要写一个转换器来完成「CMTime ↔ NSDictionary」的转换(NSDictionary是Core Data能直接序列化的类型):

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

@interface CMTimeTransformer : NSValueTransformer
@end

@implementation CMTimeTransformer

// 支持反向转换(从存储的字典转回CMTime)
+ (BOOL)allowsReverseTransformation {
    return YES;
}

// 转换后输出的类型是NSDictionary
+ (Class)transformedValueClass {
    return [NSDictionary class];
}

// 将包装了CMTime的NSValue转成可存储的NSDictionary
- (id)transformedValue:(id)value {
    if (!value || ![value isKindOfClass:[NSValue class]]) {
        return nil;
    }
    CMTime time = [value CMTimeValue];
    // 用CoreMedia的API把CMTime转成CFDictionary,再桥接成NSDictionary
    CFDictionaryRef timeDict = CMTimeCopyAsDictionary(time, kCFAllocatorDefault);
    return (__bridge_transfer NSDictionary *)timeDict;
}

// 从存储的NSDictionary转回包装了CMTime的NSValue
- (id)reverseTransformedValue:(id)value {
    if (!value || ![value isKindOfClass:[NSDictionary class]]) {
        // 处理非法值,返回默认的kCMTimeZero
        return [NSValue valueWithCMTime:kCMTimeZero];
    }
    CMTime time = CMTimeMakeFromDictionary((__bridge CFDictionaryRef)value);
    return [NSValue valueWithCMTime:time];
}

@end

2. 改造NSManagedObject子类的属性

Core Data的Transformable属性默认是id类型,但我们要直接用CMTime,所以需要手动实现getter和setter,把CMTime包装成NSValue(因为NSValue是id类型,能被转换器处理):

假设你的实体叫MediaEntity,对应的属性是playbackTime:

@interface MediaEntity : NSManagedObject
@property (nonatomic, assign) CMTime playbackTime;
@end

@implementation MediaEntity

// 保留@dynamic让Core Data管理底层存储
@dynamic playbackTime;

- (CMTime)playbackTime {
    // 从Core Data取出包装后的NSValue,再转成CMTime
    NSValue *storedValue = [self primitiveValueForKey:@"playbackTime"];
    return storedValue ? [storedValue CMTimeValue] : kCMTimeZero;
}

- (void)setPlaybackTime:(CMTime)playbackTime {
    // 把CMTime包装成NSValue再交给Core Data存储
    NSValue *valueToStore = [NSValue valueWithCMTime:playbackTime];
    [self setPrimitiveValue:valueToStore forKey:@"playbackTime"];
}

@end

3. 注册转换器并配置Core Data模型

有两种方式让Core Data知道我们的自定义转换器:

  • 代码注册:在App启动时(比如AppDelegate的didFinishLaunchingWithOptions里)添加:
    [NSValueTransformer setValueTransformer:[CMTimeTransformer new] forName:@"CMTimeTransformer"];
    
  • 可视化配置:打开Core Data模型文件,选中playbackTime属性,在右侧的Data Model Inspector里,找到「Value Transformer」字段,输入CMTimeTransformer即可。

这样整个流程就通了:当你给playbackTime赋值CMTime时,setter把它包装成NSValue,Core Data调用转换器转成NSDictionary存储;读取时,转换器把NSDictionary转回NSValue,getter再提取出CMTime。

另外要注意处理边界情况,比如CMTime是invalid的情况,避免转换时崩溃,上面的代码里已经做了基础的空值判断~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 08:51:58