Objective-C结构数组

时间:2013-06-26 06:58:08

标签: objective-c arrays vector struct

我希望得到如下结构:

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'受保护。我尝试写公开:在定义Foo时,但它不接受。 (是的,我是Obj-C的新手)。

3 个答案:

答案 0 :(得分:6)

不幸的是,启用了自动引用计数(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对象的数组很简单。你可能只是像Foo *bar[50];那样创建一个C数组,但我认为它不适用于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;在技术上是[self setTitle:title];的简写,它使用由@property@synthesize自动生成的方法。

答案 1 :(得分:2)

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

有关示例,请参阅this,有关类型编码的详细信息,请参阅this

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

答案 2 :(得分: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。 (有关详细信息,请参阅我的回答here

与C ++不同,您可以在集合类中混合对象类型,因此如果添加标题,书籍和其他书籍集,您的图书数组将不会抱怨:您的代码应该确保一致性。我们不声明数组大小。对于静态NSArray,创建时隐含大小,对于动态NSMutableArray,没有固定限制。对于五十本书籍集合的集合,创建一个由五十个预先存在的集合组成的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

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