12

在Objective-C中是否有任何反射手段可以让您通过检查对象的公共属性并生成encodeWithCoder:和initWithCoder:的通用实现来编写通用的NSCoding实现。通用的NSCoding实现的Objective-C反射

我正在考虑类似于XStream的Java,它允许使用反射来对Java对象进行序列化和反序列化。更好的做法可能是将属性标记为你想要序列化的东西或者是暂时的(比如Java中的transient关键字)。

我一直在阅读有关Cocoa Archives and Serializations Programming Guide的文档。我知道你需要对你的对象的序列化进行一些控制,但是它通常是一个对称的过程,并且为了反序列化它而需要将序列化的代码进行反编译似乎很奇怪。我是干的信徒(不要重复自己)。

回答

12

这不仅是可能的,但我有一个朋友被刺伤了。 (您可以看到他的blog about it here。)使用Objective-C 2.0 Runtime Reference中记录的Objective-C运行时功能完成反射。看一看。

但是,请注意,只有当您希望保存所有实例变量的通用行为时,这才会起作用。不过,您可能不希望NSView保存其超级视图;在这种情况下,通用情况将不起作用。

通过为要保存的任何实例变量声明属性并保留任何其他变量为“隐藏”,您可以区分事物序列化和事物不序列化,但这是扭曲属性的整体目的收益不大。我不会推荐它。

6

(我是博客文章的作者,链接到BJ荷马的评论)。有几个使用代码的注意事项:

  1. 目标类必须符合KVC。如果你为你的ivars使用Objective-C 2.0属性,那么你就全部设置好了。否则,您需要确保您的类设置为正确响应valueForKey:和setValue:forKey:方法。
  2. 该代码使用运行时的未记录“特征”递归地将伊娃类别符合NSCoding。编译时,几乎所有的打字信息(AFAIK)都从代码中删除,但为了保存ivars,也必须符合NSCoding。我发现,如果ivar是一个对象,并且我调用它的ivar_getTypeEncoding(),则会返回一个类似于以下内容的c字符串:{#IVAR_CLASS}(示例:{#NSString})。我所做的是获取#和}之间的字符串,使用NSClassFromString创建一个Class对象,并对其进行递归。
  3. 此代码将保存所有的ivars。在您自己的风险(当然)
  4. 使用

我写这主要是作为一个概念证明,并有在该代码会失败壮观许多实例。例如,在对象A中有一个用于B的ivar,并且B有一个用于A的ivar,那么使用该代码序列化一个或另一个会(我相信)会导致无限循环。尽管如此,我认为Objective-C甚至可以让你像第一个那样做东西,这真是太令人震惊了。