【问题标题】:How to avoid import cycle if I need the protocols imported?如果我需要导入协议,如何避免导入周期?
【发布时间】:2015-07-29 07:46:31
【问题描述】:

在 Objective-C 中,我创建了 11 个类,它们是 RLMObject 的子类,以表示我的数据库模型。 到目前为止,我在用这个构建我的应用程序时遇到了问题,因为正如标题中所述,他们似乎没有看到对方。 另外:它们在同一个文件夹中,#import 本身不会产生任何问题。

作为示例,我想提供两个类 以下是 Books 的类:

#import <Realm/Realm.h>
#import "Chapter.h"

@interface Book : RLMObject

@property NSInteger id;
@property NSString *name;
@property RLMArray<Chapter> *chapters;

@end

// This protocol enables typed collections. i.e.:
// RLMArray<Book>
RLM_ARRAY_TYPE(Book)

以下是我的章节课程:

#import <Realm/Realm.h>

@class Book;

@interface Chapter : RLMObject

@property NSInteger id;
@property NSString *name;
@property Book *book;

@end

// This protocol enables typed collections. i.e.:
// RLMArray<Chapter>
RLM_ARRAY_TYPE(Chapter)

在 Book.h 中我得到:

找不到“章节”的协议声明

有人有想法吗? 这绝对是某种进口圈。但是我该如何解决呢? 如果没有必要,我想避免将所有模型类放在前缀标题中。

编辑:@class 导入在章节文件中有所帮助,但在书本文件中没有

【问题讨论】:

  • 更改了问题的标题,以匹配问题和我的解决方案。
  • 单独使用Chapter.h 中Book 的类前向声明​​,您应该能够打破循环。

标签: ios objective-c realm


【解决方案1】:

您还可以为要在 list 属性中使用的对象进行协议前向声明,如下所示:

#import <Realm/Realm.h>

@protocol Chapter;

@interface Book : RLMObject

@property NSInteger id;
@property NSString *name;
@property RLMArray<Chapter> *chapters;

@end

// This protocol enables typed collections. i.e.:
// RLMArray<Book>
RLM_ARRAY_TYPE(Book)

注意:一对一关系必须使用@class,一对多关系必须使用@protocol


除此之外,我建议在您的场景中使用 a backlink from Chapter to Book 而不是属性。您的问题中有两个独立的属性,它们不会自动同步。

如果你没有正确维护它,这可能会导致这样的事情:

书籍:

  • id:0,名称:“Moby Dick”,章节:[Chapter#0,Chapter#1]
  • id: 1, name: "The Swift Programming Language", 章节: [Chapter#2, Chapter#3]

章节:

  • id: 0, name: "Loomings.", book: Book#0
  • id: 1, name: "The Carpet-Bag.", book: Book#0
  • id: 2, name: "About Swift", book: Book#1
  • id: 3, name: "A Swift Tour", book: Book#0

看看“A Swift Tour”是如何引用“Moby Dick”的,而这显然是 Swift 书的第二章。您的模型目前允许这样做,但您可以定义它以防止这种情况完全存在。

带有反向链接的解决方案如下所示:

@interface Chapter : RLMObject

@property NSInteger id;
@property NSString *name;
@property (readonly) Book *book;

@end

@implementation Chapter
// Define "book" as the inverse relationship to Book.chapters
- (Book *)book {
    return [self linkingObjectsOfClass:@"Book" forProperty:@"chapters"].firstObject;
}
@end

【讨论】:

  • 感谢您撰写本文!我不知道@protocol 前向声明。我喜欢反向链接方法,稍后我将完全实现它!协议和包含是否也适用于多对多关系?
  • 当然可以。事实上,由于 Realm 作为对象存储的性质,一对多和多对多关系之间没有真正的区别。唯一不同的是,您可以自己定义反向链接访问器的多重性。
【解决方案2】:

好的,我想出了一个办法:

我创建了一个头文件 ModelProtocols.h 并将类型化集合的所有协议添加到该文件中:

#ifndef Your_Project_ModelProtocols_h
#define Your_Project_ModelProtocols_h

@class Book;
@class Chapter;

// This protocol enables typed collections. i.e.:
// RLMArray<Book>
RLM_ARRAY_TYPE(Book)

// This protocol enables typed collections. i.e.:
// RLMArray<Chapter>
RLM_ARRAY_TYPE(Chapter)

#endif

一旦我设置了这个文件,我需要将它导入到我的模型类中:

#import "ModelProtocols.h"

并且可以将@class 用于我的其余模型类。这构建得很好,我仍然需要对其进行测试,但它应该可以工作。

【讨论】:

  • 您甚至可能不需要 ModelProtocols.h 之上的 #ifndef 内容。据我所知,#import 和#include 之间的区别在于,使用#import 避免了包含循环,并让您摆脱了每个头文件顶部的额外#ifndef 和#define 行。我不知道 RLM_ARRAY_TYPE 的实现,但我认为它使用 #include insted 的 #import ,这就是为什么你会收到这种错误。不过我可能是错的。这里有一些不错的解释:stackoverflow.com/questions/439662/…
  • 我刚才尝试使用#include,它似乎也可以工作。太好了,谢谢。下次遇到这种问题可能会用到。另一方面,我的解决方案为我的模型带来了某种组织,这也是我喜欢的。
  • RLM_ARRAY_TYPE 不导入或包含任何文件。在单独的头文件中声明数组类型,您从所有其他模型对象类头文件中导入该文件仍然是一个合法的解决方案,但@halileohalilei 在这方面更喜欢#import 而不是#include 是正确的,以避免额外的ifndefs .
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-20
  • 2017-06-23
  • 1970-01-01
  • 1970-01-01
  • 2017-09-16
  • 1970-01-01
相关资源
最近更新 更多