Skip to content

Enrich Auto Synthesizable @dynamic Property Types

WeZZard edited this page Dec 28, 2018 · 3 revisions

Introduction

Typically, you can add support of @dynamic property auto synthesizing to a scalar type with following macros:

@ObjCDynamicPropertyGetter(PROPERTY_TYPE, PROPERTY_ATTRIBUTES) {
    // Implement the getter.
};
@ObjCDynamicPropertySetter(PROPERTY_TYPE, PROPERTY_ATTRIBUTES) {
    // Implement the setter.
};

The PROPERTY_TYPE is required. Only scalar types (C struct or union) make sense. Since Objective-C classes are all recognzied as type of id in Objective-C type encoding system, only adding support of @dynamic auto synthesizing to custom scalar types really have effects on the system.

The PROPERTY_ATTRIBUTES is optional. When left blank, it means an atomic, assign property in normal Objective-C property declaration.

Within the block of @ObjCDynamicPropertyGetter and @ObjCDynamicPropertySetter, you can access the name of the property with a C macro _prop, which is quite like the _cmd derivative in an Objective-C method.

Within the block of @ObjCDynamicPropertySetter, you can access the newly set value with the variable name newValue, just like implementing a setter in Swift.

When implementing the getter or the setter, you can access the primitive value storage with [self primitiveValueForKey:] and [self setPrimitiveValue:forKey].

Available Property Attributes

  • COPY: Equivilant to copy in Objective-C property decalaration.
  • RETAIN: Equivilant to retain or strong in Objective-C property decalaration.
  • NONATOMIC: Equivilant to nonatomic in Objective-C property decalaration.
  • WEAK: Equivilant to weak in Objective-C property decalaration.

If property attributes of @ObjCDynamicPropertyGetter and @ObjCDynamicPropertySetter does not contain COPY, RETAIN and WEAK, it means assign.

Example

There is a detailed example which adds @dynamic property auto synthesizing support to a C struct Version.

Version.h

#import <Foundation/Foundation.h>

typedef struct _Version {
    NSUInteger majorVersion;
    NSUInteger minorVersion;
    NSUInteger patchVersion;
} Version;

Version.m

#import <Foundation/Foundation.h>
#import <ObjCDeepDynamic/ObjCDynamicPropertySynthesizer.h>

#import "Version.h"

@interface _VersionStorage: NSObject
@property (nonatomic, assign) NSUInteger majorVersion;
@property (nonatomic, assign) NSUInteger minorVersion;
@property (nonatomic, assign) NSUInteger patchVersion;

- (instancetype)initWithMajorVersion:(NSUInteger)majorVersion
                        minorVersion:(NSUInteger)minorVersion
                        patchVersion:(NSUInteger)patchVersion;

- (Version)versionValue;
@end

@implementation _VersionStorage
- (instancetype)initWithMajorVersion:(NSUInteger)majorVersion
                        minorVersion:(NSUInteger)minorVersion
                        patchVersion:(NSUInteger)patchVersion
{
    self = [super init];
    if (self) {
        _majorVersion = majorVersion;
        _minorVersion = minorVersion;
        _patchVersion = patchVersion;
    }
    return self;
}
@end

@ObjCDynamicPropertyGetter(Version) {
    @synchronized (self) {
        return [[self primitiveValueForKey:_prop] versionValue];
    }
};

@ObjCDynamicPropertySetter(Version) {
    @synchronized (self) {
        _VersionStorage * versionStorage = [[_VersionStorage alloc] initWithMajorVersion: newValue.majorVersion
                                                                            minorVersion: newValue.minorVersion
                                                                            patchVersion: newValue.patchVersion];
        [self setPrimitiveValue: versionStorage forKey: _prop];
    }
};

@ObjCDynamicPropertyGetter(Version, NONATOMIC) {
    return [[self primitiveValueForKey:_prop] versionValue];
};

@ObjCDynamicPropertySetter(Version, NONATOMIC) {
    _VersionStorage * versionStorage = [[_VersionStorage alloc] initWithMajorVersion: newValue.majorVersion
                                                                        minorVersion: newValue.minorVersion
                                                                        patchVersion: newValue.patchVersion];
    [self setPrimitiveValue: versionStorage forKey: _prop];
};

Config.h

#import <Foundation/Foundation.h>
#import <ObjCDeepDynamic/ObjCDeepDynamic.h>

@interface Config: NSObject
@property (nonatomic, assign) Version version;
@end

Config.m

#import "Config.h"

@implementation Config: NSObject
@dynamic version;
@end

Notes

All the @dynamic properties defined in Swift would be recognized as an atomic property.

This feature only works in Objective-C, because Swift doesn't fully support C macros, which the definition block of @dynamic property auto synthesizing is implemented with.

You can’t perform that action at this time.