将自定义对象的NSArray转换为Swift数组

时间:2014-12-22 20:19:48

标签: ios objective-c arrays swift

我有一个Objective-C应用程序工作得很好和流畅,对Swift更舒服我决定在Swift中为这个应用程序编写单元测试。

Swift中的一些概念对我来说很奇怪,例如,在我的app中需要填写服务器提供的内容列表,在Objective-C中,这看起来(不完全)就像这样:

[self.service requestContentsFrom:0 to:10 response:^(NSArray *result, NSArray *errors) {
  ContentModel *firstContent = result[0];
  NSLog("Content name: %@ Content date: %@", firstContent.name, firstContent.date);
}];

我这个简单的请求,如果填写结果列表(NSArray),我将收到ContentModel的列表,因为服务实例实现了一些序列化级别(感谢JSONModel

要在Swift中对此请求进行简单测试,我做了类似的事情:

func testContentsFromZeroToTen() {
  service?.requestContentsFrom(0, 10) { (result, errors) -> Void in

  }
}

我的问题是,在Swift中我的result参数来到[AnyObject]!并看起来这个数组被正确填充,但其中的类型与Objective-C收到的不一样调用

如果我尝试转换为NSArray,例如....

let contents = result as NSArray

...然后在控制台中打印的每个内容如下所示:

(AnyObject) content = (instance_type = Builtin.RawPointer = 0x00007fd605213000 ->     0x000000010fa902c8 (void *)0x000000010fa902f0: __NSCFDictionary)

最奇怪的是,如果我打印contents,我可以看到有关它的更一致的信息:

<__NSCFArray 0x7f95d7608110>(
{
  datetime = 1418855742226;
  id = 1;
  name = "Content 1";
},
{
  datetime = 1418855742326;
  id = 2;
  name = "Content 2";
)

喂!我的模型在那里,但是我输入的模型在哪里,而不是ContentModel,我看到__NSCFDictionary

我希望得到一个像这样的Swift数组:

let contents = result as [ContentModel]

但是当我尝试上面的代码时,当我在控制台中打印时,我的内容看起来像这样:

([ContentModel]) contents = 2 values {
  [0] = <error: use of undeclared identifier 'cocoarr'
error: 1 errors parsing expression
>

  [1] = <error: use of undeclared identifier 'cocoarr'
error: 1 errors parsing expression
>

}

所以问题是,如何正确地转换Swift数组以获得类似Objective-C的类型化NSArray?

更新1:添加了ContentModel界面

#import <Foundation/Foundation.h>
#import "JSONModel.h"
#import "UserModel.h"

@interface ContentModel : JSONModel

@property (nonatomic, assign) NSInteger id;
@property (nonatomic, strong) NSDate *datetime;
@property (nonatomic, strong) NSString *text;

@property (nonatomic, strong) UserModel *user;

@end

1 个答案:

答案 0 :(得分:1)

首先,NSArray未在Objective-C中输入。它是一个任意类的数组。这正是[AnyObject]的内容。 AnyObject是对任何类的引用。


现在,要将AnyObject数组的元素作为另一种更具体的类型进行访问,您有两种选择:

一次转换整个数组:

func testContentsFromZeroToTen() {
  service?.requestContentsFrom(0, 10) { (result, errors) -> Void in
      if let contentModels = result as? [ContentModel] {
          for contentModel in contentModels {
          }
      }
  }
}

或者您可以一次转换一个元素:

func testContentsFromZeroToTen() {
  service?.requestContentsFrom(0, 10) { (result, errors) -> Void in
      for next in result {
          if let contentModel = next as? ContentModel {
          }
      }
  }
}

第二个选项允许某些单个元素不是您期望的类型的场景。在第一种情况下,如果一个元素不是ContentModel,您将跳过整个数组。

注意:您也可以在我的示例中执行强制转换而不是可选的转换:

let contentModels = result as [ContentModel]
let contentModel = next as ContentModel

但如果演员失败,这些会让你失败。


最后,当您在Swift中打印出一个对象时,它会打印出一些默认值(通常不是非常有用的信息)。如果要自定义对象打印的内容,可以让自定义类型实现Printable或DebugPrintable协议:

class ContentModel: Printable {
    var description: String {
        return "Some description"
    }
}