5

In addition to 'var' (see my other post here), one of the things I really like about C# is that I can both declare, then initialize members of a class using braces, like this...

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

or even on one line, like this...

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

This creates an instance of ReallyLongFooClassName and then sets its members 'Name' and 'ID'.

This compiles to the same thing as if you typed this...

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

So does Objective-C/C++ have anything equivalent to the member-brace-initialization of C#?

Note: Thanks to my other post, I already know that 'auto' is the 'var' equivalent in Objective-C++ but Objective-C doesn't have any such equal, which is a shame. Again, see my other post here for more info.)

Update

I'm aware of writing initializers. That is a different beat altogether. The technique I demoed above In C# uses the setters of the properties, or sets the member variables directly without having to write a constructor (their sort-of-equivalent to Objective-C's 'init' members.) Having to write init members forces you to have to pre-specify what you want to set. Member brace-initialization lets you specify any combination of properties/member variables and in any order you want. Again, it's just syntactic sugar for writing multiple lines of code at once. It doesn't actually change the class.

Community
  • 1
  • 1
Mark A. Donohoe
  • 28,442
  • 25
  • 137
  • 286

4 Answers4

1

There are several alternative if you think of using Objective C/C++.

Objective C:

Create initialization method in class A as;

@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;
}

Initializing;

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

Using class or struct;

Using struct;

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

};

Initilializing;

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

Using class;

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

};

I think this should some how answer your question.

Sandeep
  • 20,908
  • 7
  • 66
  • 106
  • 3
    Yes, I know about initializers. But that's not what I'm after. Using member initialization, you can specify any combination, and in any order, the members you want to set. Using the 'init' methods forces you to a) write an init call, and b) explicitly specify what members you want to include. Different thing altogether. – Mark A. Donohoe Jan 13 '13 at 00:18
  • @Marquel You'd be hard pressed to find something like that. You could always cheat and use a pre-processor macro. – CodaFi Jan 13 '13 at 01:14
  • Note declaring iVars in ObjC is passé and you'd generally want to prefix them with `_`. Also, ivars are pretty much never accessed via `->`. All works, but atypical. – bbum Jan 13 '13 at 01:17
  • @bbum I have seen in many apple sample code. They use -> to access ivars and even add observers for ivars. But, is it very unusual to use -> notation? – Sandeep Jan 13 '13 at 08:03
  • It is. And it shouldn't be in example code. Post the link to the sample and I'll file a bug to have it fixed. – bbum Jan 13 '13 at 15:32
  • You will find many such uses in MVC networking sample code from apple http://developer.apple.com/library/ios/#samplecode/MVCNetworking/Introduction/Intro.html. – Sandeep Jan 14 '13 at 06:10
1

You can write a helper function that does something similar (here in Objective-C++, but you can do this in Objective-C easily by taking a Class as parameter):

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;
}

Then use it as follows:

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

I have not tested it, but it should work. Note that it won't work when setters take non-Objective-C-objects (such as int), but it is possible to alter the function to make this work (through reflection).

0

No, there is no such facility.

Objective-C takes the path of providing an initializer. Typically, the initializer takes the required arguments necessary to initialize an instance of the class. Sometimes, some of those arguments will be optional. I.e. you might have:

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

And cover might sometimes be nil.

In Objective-C, instances of classes are generally initialized with the required state to provide a minimal working instance and then you call various setters to then configure the class further.

bbum
  • 162,346
  • 23
  • 271
  • 359
  • I thought Objective-C didn't provide the facility for optional arguments (last sentence of your first para.) You had to define additional init versions with the combinations of parameters you want. Has this changed, or am I mistaken? – Mark A. Donohoe Jan 13 '13 at 01:22
  • Nah -- you are correct. What i meant was that the *values passed to the argument might occasionally be optional*. The argument still exists; Objective-C has neither keyword based parameters nor does it have optional arguments. Sorry for the confusion. – bbum Jan 13 '13 at 01:43
0

Here are a couple approaches used in ComponentKit for inspiration:

              {[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},
                }]
              },

You can take a variable number of named attributes either via

  1. a struct with aggregate initialization (struct CKLabelAttributes)
  2. an std::unordered_map (in this case, typedef std::unordered_map<CKComponentViewAttribute, id>) that contains whatever keys and values you want to use to initialize your class.

This syntax obviates the -initWithA:B:C:, -initWithA:, -initWithB:, ... explosion that usually happens with complicated Obj-C interfaces.

Andrew Pouliot
  • 5,423
  • 1
  • 30
  • 34