标签: nscoding

如何对NSCoding进行单元测试?

我有一个iOS应用程序,使用NSCoding持久化数据,更确切地说是NSKeyedArchiver.此应用程序已在App Store上提供.

我正在研究应用程序的第2版,数据模型应该改变.所以我需要处理数据模型迁移.我希望它由单元测试覆盖.

在我的测试中,我想用旧数据模型动态生成持久化数据,启动迁移并查看是否一切顺利.

目前,归档对象如下所示:

MyDataModelObject *object = ....
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:object forKey:key];
[archiver finishEncoding];
Run Code Online (Sandbox Code Playgroud)

问题是,MyDataModelObject可能会在应用程序的版本2中重新计算甚至删除.所以我不能在我的测试中使用这个类来生成"旧版本档案".

有没有办法在encodeWithCoder:不使用此类的情况下模拟类方法中的操作?


我想要实现的目标如下

- testMigrationFrom_v1_to_v2 {
    // simulate an archive with v1 data model
    // I want this part of the code to be as simple as possible
    // I don't want to rely on old classes to generate the archive
    NSDictionary *person = ... // { firstName: John, lastName: Doe }
    NSDictionary *adress = ... // { …
Run Code Online (Sandbox Code Playgroud)

cocoa unit-testing objective-c nscoding ios

6
推荐指数
1
解决办法
2011
查看次数

initWithCoder:在NSObject中不可见?

我有一个界面:

#import <Foundation/Foundation.h>

@interface Picture : NSObject;

@property (readonly) NSString *filepath;
- (UIImage *)image;

@end
Run Code Online (Sandbox Code Playgroud)

和实施:

#import "Picture.h"

#define kFilepath @"filepath"

@interface Picture () <NSCoding> {
    NSString *filepath;
}

@end


@implementation Picture
@synthesize filepath;

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    return self;

}

- (void)encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:filepath forKey:kFilepath];
}

- (UIImage *)image {
    return [UIImage imageWithContentsOfFile:filepath];
}

@end
Run Code Online (Sandbox Code Playgroud)

我收到错误:ARC问题 - 'NSObject'没有可见的@interface声明选择器'initWithCoder:'

使用ARC时,NSCoding有什么不同吗?谢谢

cocoa-touch objective-c nscoding ios

6
推荐指数
1
解决办法
4267
查看次数

检查"NeXT/Apple typedstream"版本4(NSArchiver)类型的文件

对于数据恢复程序,我需要能够从NSArchiver编写的文件中提取值+类型,而无需访问Apple的CF/NS框架.

OS X file命令报告以下文件:

NeXT/Apple typedstream data, little endian, version 4, system 1000
Run Code Online (Sandbox Code Playgroud)

是否有关于如何编码这些文件的文档,或者是否有人提出可以解析它们的代码?

以下是此类数据的示例(也可:可下载):

04 0B 73 74 72 65 61 6D 74 79 70 65 64 81 E8 03  ..streamtyped...
84 01 40 84 84 84 12 4E 53 41 74 74 72 69 62 75  ..@....NSAttribu
74 65 64 53 74 72 69 6E 67 00 84 84 08 4E 53 4F  tedString....NSO
62 6A 65 63 74 00 85 92 84 84 84 …
Run Code Online (Sandbox Code Playgroud)

macos objective-c nscoding ios nsarchiving

6
推荐指数
2
解决办法
1493
查看次数

NSKeyedUnarchiver无法解析swift中的自定义对象

我正在尝试NSCodingswift中协议的基本实现,但似乎我无法成功地在对象被正确存档后取消归档.

这是我的尝试

import Cocoa

class User: NSObject, NSCoding {
    var name: String

    init(name: String) {
        self.name = name
    }

    init(coder aDecoder: NSCoder!) {
        self.name = aDecoder.decodeObjectForKey("name") as String
    }

    func encodeWithCoder(aCoder: NSCoder!) {
        aCoder.encodeObject(name, forKey: "name")
    }
}

let user = User(name: "Gabriele")
let encodedUser = NSKeyedArchiver.archivedDataWithRootObject(user)
let decodedUser = NSKeyedUnarchiver.unarchiveObjectWithData(encodedUser) as User
Run Code Online (Sandbox Code Playgroud)

在操场上运行它,它会在最后一行启动一个例外.这是细节

Execution was interrupted, reason: signal SIGABRT.
The process has been left at the point where it was interrupted, use "thread return -x" to return …
Run Code Online (Sandbox Code Playgroud)

nscoding nskeyedarchiver nskeyedunarchiver swift

6
推荐指数
1
解决办法
3808
查看次数

使用NSCoding时如何处理字段类型更改

我有以下实现的类,NSCoding我已经创建了它的几个实例并将它们保存到文件中.

@interface BiscuitTin ()
@property NSString *biscuitType;
@property int numBiscuits;
@end

@implementation BiscuitTin

- (id)initWithCoder:(NSCoder *)coder {
    self = [super init];
    if (self) {
        self.biscuitType = [coder decodeObjectForKey:@"biscuitType"];
        self.numBiscuits = [coder decodeIntForKey:@"numBiscuits"];
    }
    return self;
}

- (void)encodeWithCoder:(NSCoder *coder) {
    [coder encodeObject:self.biscuitType forKey:@"biscuitType"];
    [coder encodeInt:self.numBiscuits forKey:@"numBiscuits"];
}

@end
Run Code Online (Sandbox Code Playgroud)

我现在决定将其表示numBiscuitsfloat(因为可能有部分吃过的饼干).更新属性类型并且encodeWithCoder工作正常但是当我尝试从文件加载现有实例时,应用程序崩溃,因为它正在尝试解码a int和a float.

有一个很好的方法来处理这个?理想情况下,我可以加载现有int值并将其转换为a float,但我不介意只使用默认值而不是崩溃.

我已经考虑decode在try-catch中包装适用的行,但在我的实际用例中,大约有50个左右的属性正在被编码/解码,并且不必为每个有变化的每个属性进行显式处理类型.

objective-c nscoding

6
推荐指数
2
解决办法
300
查看次数

如何从decodeIntegerForKey而不是0获取可选项?

我的应用程序通过归档具有属性的类的实例将设置保存到iOS设备上的文件.该类使用NSCoding协议,因此,我使用encodeWithCoder对这些属性进行编码.然后我尝试使用诸如的命令将这些文件读回内存tempInt = decoder.decodeIntegerForKey("profileFlags") as Int

到目前为止,这种方法运行良好,但现在我需要能够存储其他属性并检索它们.本质上,这个存档对象的结构正在改变,但用户已经拥有旧结构(具有较少属性)的文件.如果用户有一个具有新结构的文件(附加属性),那么我想阅读它们.如果没有,我希望能够执行代码来处理它并提供默认值.

我尝试使用不存在的密钥tempInt = decoder.decodeIntegerForKey("nonExistentKey") as Int,期望得到一个零值,但它返回零.不幸的是,这是我真正需要一个可选的地方,因为0是一个有效的值.

我能找到的最接近的帮助文章是Swift:如果key不存在则decodeObjectForKey崩溃, 但这似乎不适用于此处.似乎decodeObjectForKey返回一个可选项,而decodeIntegerForKey返回一个Integer.

关于如何做到这一点的任何想法?

nscoding ios swift

6
推荐指数
1
解决办法
658
查看次数

如何以编程方式添加可重用的自定义视图?(迅速)

我创建了一个可重用的xib文件,其中包含一个表,并将其加载到如下TableView.swift文件中:

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)    
    Bundle.main.loadNibNamed("TableView", owner: self, options: nil)
}
Run Code Online (Sandbox Code Playgroud)

我只是提到这一点来澄清我对如何加载xib文件并不感到困惑


我可以RootViewController.swift通过添加视图UIViewController并为该视图提供如下自定义类,轻松地在我的文件中加载可重用视图:

在此输入图像描述

然后为这个视图创建一个这样的出口:

在此输入图像描述

所以这是我的问题:

为什么我不能简单地添加这样的视图:

let tableViewView = TableView()
Run Code Online (Sandbox Code Playgroud)

当我这样做时,我得到一个我不完全理解的错误:

在此输入图像描述

nscoding uitableview xib ios swift

6
推荐指数
0
解决办法
1256
查看次数

在iPhone上存储json数据:保存json字符串,因为它是从json创建一个对象并使用NSCoding + NSKeyedArchiver

在我的iPhone应用程序中,我从远程服务器获取json数据,使用Json Framework解析它并将其呈现在UIview中.还希望能够为用户提供将数据存储在设备上的选项,以便也可以脱机查看.我想知道是否直接存储json数据比制作一个对象更好或更差,然后使用NSCoding + NSKeyedArchiver保存它.我认为存储JSON字符串,因为它是的优点在于,它需要较少的空间比光盘存档对象,同时,在另一方面,通过存储归档的对象,你不必解析存储的数据每一次这样使用更少的内存.

有最好的整体选择吗?在这个问题上有没有最佳实践?json文件大小约为8KB.

iphone json nscoding storing-data ios

5
推荐指数
1
解决办法
3766
查看次数

序列化包含对Core Data中NSManagedObjects的引用的多维数组

我有两个实体,ChainStep.Chain有一个属性steps,可以是多维Step实体数组,例如:

[
  step,
  step,
  step,
  [
    step,
    step
  ],
  step
]
Run Code Online (Sandbox Code Playgroud)

每个Step对象都有content一个字符串属性.

如果我使用关系数据库,我只是将该数组存储为JSON,每个step都是step_id特定步骤.

我如何在Core Data中实现类似的功能?我认为我需要让这个Step类符合NSCoding协议,但那会是什么样子?我怎样才能使它只id在Chain.steps的最终值中存储它的等价物,即对它自己的引用?

编辑

下面的评论表明我nextStepStep其他人之间包含了一对多关系(让我们称之为)Steps.然后我会使用这种关系从a中的一步到下一步Chain,因此Chain实体只需要包含Step序列中的第一步.这个问题是a Step可能属于多个Chain,因此它可能并不总是具有相同的nextStep值.

iphone core-data objective-c nscoding ios

5
推荐指数
1
解决办法
956
查看次数

Swift 3 Xcode 8 - SwiftValue encodeWithCoder - 发送到实例的无法识别的选择器

我的自定义对象符合NSCoding协议,具有以下方法

required init(coder decoder: NSCoder) {
    super.init()

    createdDate = decoder.decodeObject(forKey: "created_date") as? Date
    userId = decoder.decodeInteger(forKey: "user_id")
}

func encode(with aCoder: NSCoder) {
    aCoder.encode(createdDate, forKey: "created_date")
    aCoder.encode(userId, forKey: "user_id")
}
Run Code Online (Sandbox Code Playgroud)

这是Swift 3中nscoding协议的正确方法名称,但应用程序因错误而崩溃 SwiftValue encodeWithCoder - unrecognized selector sent to instance

显然这种方法不可用,为什么不被认可?

参考https://developer.apple.com/reference/foundation/nscoding

这是我制作的归档方法

func encodeObject(_ defaults:UserDefaults, object:NSCoding?, key:String) {
    if (object != nil) {
        let encodedObject = NSKeyedArchiver.archivedData(withRootObject: object)
        defaults.set(encodedObject, forKey: key)
    } else {
        defaults.removeObject(forKey: key)
    }
}
Run Code Online (Sandbox Code Playgroud)

nscoding swift3 xcode8

5
推荐指数
1
解决办法
7089
查看次数