Objective-C Mapping for Structures

On this page:

Basic Objective-C Mapping for Structures

A Slice structure maps to an Objective-C class.

For each Slice data member, the generated Objective-C class has a corresponding property. For example, here is our Employee structure once more:

struct Employee 
    long number;
    string firstName;
    string lastName;

The Slice-to-Objective-C compiler generates the following definition for this structure:

@interface EXEmployee : NSObject <NSCopying>
        ICELong number;
        NSString *firstName;
        NSString *lastName;

@property(nonatomic, assign) ICELong number;
@property(nonatomic, strong) NSString *firstName;
@property(nonatomic, strong) NSString *lastName;

-(id) init:(ICELong)number firstName:(NSString *)firstName lastName:(NSString *)lastName;
+(id) employee:(ICELong)number firstName:(NSString *)firstName lastName:(NSString *)lastName;
+(id) employee;
// This class also overrides copyWithZone,
// hash, isequal, and dealloc.

Mapping for Data Members in Objective-C

For each data member in the Slice definition, the Objective-C class contains a corresponding private instance variable of the same name, as well as a property definition that allows you to set and get the value of the corresponding instance variable. For example, given an instance of EXEmployee, you can write the following:

ICELong number;
EXemployee *e = ...;
[e setNumber:99];
number = [e number];

// Or, more concisely with dot notation:

e.number = 99;
number = e.number;

Properties that represent data members always use the nonatomic property attribute. This avoids the overhead of locking each data member during access. The second property attribute is assign for integral and floating-point types and strong for all other types (such as strings, structures, and so on). If not using automatic reference counting (ARC), the strong property attribute is replaced with retain.

Note that, for types that have immutable and mutable variants (strings, sequences, and dictionaries), the corresponding data member uses the immutable variant. This allows the application to assign an immutable object to the data member. You can safely cast the data member to the mutable variant if the structure was created by the Ice run time: the unmarshaling code always creates and assigns the mutable version to the data member.

Creating and Initializing Structures in Objective-C

Structures provide the typical (inherited) init method:

EXEmployee *e = [[EXEmployee alloc] init];
// ...

As usual, init initializes the instance variables of the structure with zero-filled memory, with the following exceptions:

  • A string data member is initialized to an empty string
  • An enumerator data member is initialized to the first enumerator
  • A structure data member is initialized to a default-constructed value

You can also declare default values in your Slice definition, in which case this init method initializes each data member with its declared value instead.

In addition, a structure provides a second init method that accepts one parameter for each data member of the structure:

-(id) init:(ICELong)number firstName:(NSString *)firstName lastName:(NSString *)lastName;

Note that the first parameter is always unlabeled; the second and subsequent parameters have a label that is the same as the name of the corresponding Slice data member. The additional init method allows you to instantiate a structure and initialize its data members in a single statement:

EXEmployee *e = [[EXEmployee alloc] init:99 firstName:@"Brad" lastName:@"Cox"];
// ...

init applies the memory management policy of the corresponding properties, that is, it calls retain on the firstName and lastName arguments.

Each structure also provides two convenience constructors that mirror the init methods: a parameter-less convenience constructor and one that has a parameter for each Slice data member:

+(id) employee;
+(id) employee:(ICELong)number firstName:(NSString *)firstName lastName:(NSString *)lastName;

The convenience constructors have the same name as the mapped Slice structure (without the module prefix). As usual, they allocate an instance, perform the same initialization actions as the corresponding init methods:

EXEmployee *e = [EXEmployee employee:99 firstName:@"Brad" lastName:@"Cox"];
// ...

If not using ARC, the convenience constructor calls autorelease on the return structure.

Copying Structures in Objective-C

Structures implement the NSCopying protocol. In other words, the copy is shallow:

EXEmployee *e = [EXEmployee employee:99 firstName:@"Brad" lastName:@"Cox"];
EXEmployee *e2 = [e copy];
NSAssert(e.number == e2.number);
NSAssert([e.firstName == e2.firstName]); // Same instance
// ...

Note that, if you assign an NSMutableString to a structure member and use the structure as a dictionary key, you must not modify the string inside the structure without copying it because doing so will corrupt the dictionary.

When not using ARC, structures are copied by assigning instance variables of value type and calling retain on each instance variable of non-value type. With ARC, the copied structure shares ownership of instance variables with the original structure.

Deallocating Structures in Objective-C

When not using ARC, each structure implements a dealloc method that calls release on each instance variable with a retain property attribute. This means that structures take care of the memory management of their contents: releasing a structure automatically releases all its instance variables. The dealloc method is not defined when ARC is enabled since ARC automatically handles the release of instance variables.

Structure Comparison and Hashing in Objective-C

Structures implement isEqual, so you can compare them for equality. Two structures are equal if all their instance variables are equal. For value types, equality is determined by the == operator; for non-value types other than classes, equality is determined by the corresponding instance variable's isEqual method. Classes are compared by comparing their identity: two class members are equal if they both point at the same instance.

The hash method returns a hash value is that is computed from the hash value of all of the structure's instance variables.

See Also