5

除了“var”(请参阅​​我的另一篇文章)之外,我真正喜欢 C# 的一件事是我可以同时声明,然后使用大括号初始化类的成员,就像这样......

var reallyLongFooVarName = new ReallyLongFooClassName(){
    Name = "I'm an instance of Foo",
    ID   = 23 };

甚至在一条线上,像这样......

var longFooVarName = new ReallyLongFooClassName(){ Name = "I'm an instance of Foo", ID = 23 };

这将创建一个ReallyLongFooClassName 的实例,然后设置其成员'Name' 和'ID'。

这编译为与您键入此内容相同的内容...

ReallyLongFooClassName reallyLongFooVarName = new ReallyLongFooClassName();
reallyLongFooVarName.Name = "I'm an instance of Foo";
reallyLongFooVarName.ID = 23;

那么Objective-C/C++有什么相当于C#的成员大括号初始化的东西吗?

注意:感谢我的另一篇文章,我已经知道 'auto' 是 Objective-C++ 中的 'var' 等价物,但 Objective-C 没有这样的等价物,这很遗憾。再次,请参阅我的其他帖子以获取更多信息。)

更新

我知道编写初始化程序。那是完全不同的节拍。我在上面在 C# 中演示的技术使用属性的设置器,或者直接设置成员变量而无需编写构造函数(它们相当于 Objective-C 的“init”成员。)必须编写 init 成员迫使你必须预先指定要设置的内容。成员大括号初始化允许您以任何您想要的顺序指定属性/成员变量的任意组合。同样,它只是一次编写多行代码的语法糖。它实际上并没有改变班级。

4

4 回答 4

1

您可以编写一个执行类似操作的辅助函数(在 Objective-C++ 中,但您可以在 Objective-C 中通过使用Classas 参数轻松地做到这一点):

template<class T>
T* NewObject(NSDictionary *fields) {
    static_assert(std::is_convertible<T*, id>::value,
                  "T must be an Objective-C class.");

    auto* obj = [[[[T class] alloc] init] autorelease];
    for (auto* key in fields.keys) {
        auto* capitalizedKey =
            [key stringByReplacingCharactersInRange:NSMakeRange(0, 1)
                                         withString:[key substringToIndex:1].uppercaseString];
        auto* message = [NSString stringWithFormat:@"set%@:", capitalizedKey];
        [obj performSelector:NSSelectorFromString(message) withObject:fields[key]];
    }
    return obj;
}

然后按如下方式使用它:

auto* object = NewObject<MyClass>(@{
    @"foo": @"bar",
    @"baz": @42
});

我没有测试过它,但它应该可以工作。请注意,当 setter 采用非 Objective-C 对象(例如int)时,它不起作用,但可以更改函数以使其工作(通过反射)。

于 2013-01-13T01:57:07.480 回答
1

如果您考虑使用 Objective C/C++,有几种选择。

目标 C:

在类 A 中创建初始化方法为;

@interface ClassA:NSObject
-(id)initWithName:(NSString*)name id:(NSUinteger)id;
@end

@implementation ClassA{
  NSString *name;
  NSUinterger id;
}

-(id)initWithName:(NSString*)name id:(NSUInteger)id{
  self = [super init];
  if(!self)
    return nil;
  self -> name = name;
  self -> id = id;
  return self;
}

初始化;

[[ClassA alloc] initWithName:@"MyName" id:1000];
Objective C alternative,

使用类或结构;

使用结构;

struct MyClass{
    NSString *name;
    NSString *identifier;
    MyClass(NSString *name, NSUInteger identifier):name(name), identifier(identifier);

};

初始化;

MyClass *myclass = new MyClass(@"Sandeep", 1000);

使用类;

class MyClass{
private:
    NSString *name;
    NSString *identifier;
public:
    MyClass(NSString *name = @"", NSUInteger identifier = 0);

};

我认为这应该如何回答你的问题。

于 2013-01-13T00:13:25.060 回答
0

不,没有这样的设施。

Objective-C 采用提供初始化程序的路径。通常,初始化程序采用初始化类实例所需的参数。有时,其中一些参数是可选的。即你可能有:

- (instancetype)initWithCar:(Car*)car tires:(NSArray*)tires cover:(Cover*)cover;

cover有时可能nil是。

在 Objective-C 中,类的实例通常使用所需的状态进行初始化以提供最小的工作实例,然后调用各种 setter 来进一步配置类。

于 2013-01-13T01:20:34.887 回答
0

以下是ComponentKit中用于启发的几种方法:

              {[CKLabelComponent
                newWithLabelAttributes:{
                  .string = (indicatesSuccess ? @"Yes" : @"No"),
                  .color = [UIColor whiteColor],
                  .font = [UIFont fontWithName:@"Cochin-Bold" size:45.0],
                  .alignment = NSTextAlignmentCenter
                }
                viewAttributes:{
                  {@selector(setBackgroundColor:), [UIColor clearColor]},
                  {@selector(setUserInteractionEnabled:), @NO},
                }]
              },

您可以通过以下方式获取可变数量的命名属性

  1. 具有聚合初始化 ( struct CKLabelAttributes)的结构
  2. 一个std::unordered_map(在本例中为typedef std::unordered_map<CKComponentViewAttribute, id>),其中包含您要用于初始化类的任何键和值。

这种语法避免了复杂的 Obj-C 接口通常发生的-initWithA:B:C:, -initWithA:, , ... 爆炸。-initWithB:

于 2015-06-30T01:57:42.967 回答