5

我想要一个如下结构:

struct foo {
NSString Title;
NSInteger numberOfBooks;
vector of NSStrings Books;
};

foo bar[50];

现在首先,我想知道如何创建一个字符串数组(每行包含一个书名)。

然后我想知道我写的代码是否正确。

最后,我可以使用 bar[n].Title 访问结构的所述元素吗?


我已经按照您的评论进行了操作,它的外观如下:

@interface Foo : NSObject {
NSString *name;
NSArray *books;
}

@end

A->name = @"Clancy, Thomas";
A->books = [[NSArray alloc] initWithObjects:@"Book 1"
            @"Book2",nil];
self.authors = [[NSArray alloc] initWithObjects:A, nil];

现在它给了我实例变量'name'受到保护。我尝试写 public: 在定义 Foo 时,但它不接受。(是的,我是 Obj-C 的新手)。

4

3 回答 3

7

不幸的是,启用了自动引用计数 (ARC) 的 Objective C 不允许 C 结构中的对象。Objc 也只允许 NSArrays 内的对象(向量的松散等价物)。

解决方案的第一步是创建一个类而不是结构:

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

@interface Foo : NSObject
@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) NSArray *books;
// no need to keep the number of items in an NSArray as a separate variable,
// NSArray does that for you.

- (id)initWithTitle:(NSString *)title books:(NSArray *)books;

@end

// Foo.m
#import "Foo.h"

@implementation Foo
@synthesize title;
@synthesize books;

- (id)initWithTitle:(NSString *)title books:(NSArray *)books
{
  if (self = [super init]) {
    self.title = title;
    self.books = books;
  }
  return self;
}

@end

请注意,所有对象类型都是指针。这是因为 objc 中的所有对象都是堆分配的,因此您不能使用不是指针的对象类型。另请注意,该类型NSArray未参数化。那是因为 objc 没有泛型模板的概念,所以数组的内容可以是任何对象。这通常不是问题,但有时在编译时不会发现类型错误。

Foo保留这些对象的数组很简单。你可以只用它们组成一个 C 数组Foo *bar[50];,但我认为这不适用于 ARC,而且在目标 c 中绝对不是正确的方法。正确的方法是使用另一个 NSArray: NSArray *bar = [[NSArray alloc] init];,或者使用 objc2.0 语法:NSArray *bar = @[];

一些可能对你有帮助的笔记

@property并且@synthesize是为 if 创建实例变量和访问器方法的快捷方式。如果要从类外部(或者更确切地说,实现文件)访问实例变量,则需要访问器方法。该strong标志告诉引用计数器这是一个强引用,就像 c++ boost 库中的 shared_ptr 一样。我不知道有什么用nonatomic,但有人告诉我你需要它。

该方法initWithTitle:books:类似于构造函数,只是 objc 没有构造函数的概念。实现调用超类的构造函数self = [super init](假设 self 是对对象的 c++ 引用)。构造函数可以返回 nil,所以这就是你需要 if 块的原因。

该行在self.title = title;技术上是 的简写,它使用由and[self setTitle:title];自动生成的方法。@property@synthesize

于 2013-06-26T07:25:11.977 回答
4

可以将 Objective-C 中的 C 结构装箱到通用NSValue容器中。您可以使用[NSValue value:withObjCType:]对值进行编码并[NSValue getValue:]取回该值。然后,您可以将新NSValue *对象添加到任何 Objective-C 容器中。

请参阅示例并阅读以获取有关类型编码的更多信息。

请注意,装箱/拆箱不是免费的,因此,如果您正在编写性能关键型应用程序,我建议您在std::vector每次存储/获取项目时使用其他 C++ 容器来避免此过程。

于 2013-06-26T07:39:22.483 回答
0

在 Objective-C 中,您最好使用 NSDictionaries 或自定义对象而不是结构。扩展 H2CO3 的评论 - 你可以声明一个 BookCollection 类

BookCollection.h

#import <Foundation/Foundation.h>


@interface BookCollection: NSObject

@property (nonatomic, strong) NSString* title
@property (nonatomic, strong) NSArray* books
   //use NSArray* for a static array or NSMutableArray* for a dynamic array

@end

BookCollection.m

#import "BookCollection/BookCollection.h"

@implementation BookCollection

@end

您的实现是空的,因为您的对象只有公共属性而没有自定义方法。我们使用@property 语法来声明我们的实例变量,因为这带来了许多优点,例如内置的 getter 和 setter。(详情请看我的回答)

与 C++ 不同,您可以在集合类中混合对象类型,因此如果您添加标题、书籍和其他书籍集合,您的 books 数组不会抱怨:您的代码应确保一致性。我们不声明数组大小。对于静态 NSArray,大小是在创建时隐含的,对于动态 NSMutableArray,没有固定限制。对于 50 本书的集合,创建一个包含 50 个预先存在的集合的 NSArray。或者创建一个 NSMutableArray ,您可以逐步添加它。

BookCollection* joyce = [[BookCollection alloc] init];
joyce.title = @"Books by James Joyce";
joyce.books = @["Ulysses",@"Finnegan's Wake"]; //using static NSArray


BookCollection* tolkein = [[BookCollection alloc] init];
tolkein.title = @"Books by J.R.R. Tolkein";
[tolkein.books addObject:@"The Hobbit"];  //using dynamic NSMutableArray
[tolkein.books addObject:@"Lord of the Rings"];

对于集合的动态数组:

NSMutableArray* collections = [[NSMutableArray alloc] init];
[collections addObject:joyce];
[collections addObject:tolkein];

对于固定数组,您可以使用文字语法:

NSArray* collections = @[joyce, tolkein];

对于 numberOfBooks,只需使用count数组的属性

int numberOfBooks = joyce.books.count;

如果要确保使用标题和书籍创建集合,请按照 adrusi 的回答使用自定义初始化程序。这不是使对象工作所必需的,但如果您想保证您的对象有内容,它会很有用。

要访问实例变量,请使用[message syntax](原始 obj-C 方式)或dot.syntax(与 @properties 一起使用)

[tolkein books]
joyce.books

不要使用->箭头语法。有关详细说明,请参见此处

于 2013-06-26T08:14:30.160 回答