UITraitDefinition
A type representing a trait in a trait collection.
Declaration
@protocol UITraitDefinitionMentioned in
Overview
All traits contained in a UITraitCollection conform to this protocol. Three protocols refine UITraitDefinition: UINSIntegerTraitDefinition, UICGFloatTraitDefinition, or UIObjectTraitDefinition. You can create custom traits by defining your own object conforming one of these three protocols, as appropriate for your trait value.
The example below defines a new trait that holds an NSInteger value:
typedef NS_ENUM(NSInteger, Theme) {
ThemeStandard,
ThemeMonochrome
};
@interface MyThemeTrait : NSObject<UINSIntegerTraitDefinition>
@end
@implementation MyThemeTrait
+ (NSInteger)defaultValue { return ThemeStandard; }
@endDefining defaultValue is the minimum requirement to conform to this protocol. The defaultValue must be constant.
The best candidates for trait values are simple scalars: NSInteger and CGFloat. You can also use lightweight objects as trait values, but these are less efficient than simple scalars. Examples of lightweight objects include NSString, NSDate, or a composite of similarly lightweight objects. Make sure the default value never changes, preferably by making the object immutable. The system frequently checks trait values for equality, so classes need an efficient implementation of isEqual(_:).
If you use your custom trait to implement custom dynamic colors, implement affectsColorAppearance and return YES. Returning YES tells the system to update and redraw views automatically when the trait changes. The system responds to changes to your trait similar to changes in system traits contained in systemTraitsAffectingColorAppearance. Changes to traits that affect color appearance are more expensive, so opt in to this behavior only when necessary, and change such traits infrequently.
A trait type serves as a unique key, identifying a trait within a trait collection. Methods such as valueForNSIntegerTrait: and registerForTraitChanges:withHandler: take a trait type to identify the trait in a collection.
Traits in both Swift and Objective-C
If you need to access traits from both Swift and Objective-C code, create a type conforming to UITraitDefinition in both languages. To define a trait that’s accessible from both Swift and Objective-C, follow these guidelines :
In Swift, define a structure that conforms to UITraitDefinition.
In Objective-C, define an NSObject subclass that conforms to UINSIntegerTraitDefinition, UICGFloatTraitDefinition, or UIObjectTraitDefinition.
Implement defaultValue, name, and identifier, and make the values the same in Objective-C and Swift.
If your trait holds an object value, make the class visible to both Swift and Objective-C.
If your trait holds a fundamental value type, make your Objective-C types correspond to Swift types, as in the following table:
Swift | Objective-C |
|---|---|
For Swift Bool values, Objective-C uses 0 for false and 1 for true.
If your Swift trait uses an optional type for the defaultValue, Objective-C represents a Swift nil value with a special Objective-C constant. The table below lists the Objective-C values that correspond to a Swift nil value.
Swift optional type | Swift value | Objective-C type | Objective-C value |
|---|---|---|---|
|
| ||
|
| ||
|
|
In Objective-C, your trait value may require an NSObject subclass if your data model exceeds the simple scalars of NSInteger and CGFloat. To use this value in Swift, import your Objective-C class into Swift, and use it for the value of your custom trait in both languages. Other than bridging with Objective-C, avoid using reference types for Swift trait values.
You can prevent Swift from importing your Objective-C class name by applying the NS_REFINED_FOR_SWIFT macro to your Objective-C interface. This macro allows you to name your Swift trait structure with the same name as your Objective-C trait class.
The example below defines a trait in Objective-C, with a custom Theme type for a trait value.
typedef NS_ENUM(NSInteger, Theme) {
ThemeStandard,
ThemeMonochrome
};
NS_REFINED_FOR_SWIFT @interface ThemeTrait : NSObject<UINSIntegerTraitDefinition>
@end
@implementation ThemeTrait
+ (NSInteger)defaultValue { return ThemeStandard; }
+ (NSString *)name { return @"Theme"; }
+ (NSString *)identifier { return @"com.example.themetrait"; }
@end
The following code example shows the definition of a Swift trait so that UIKit recognizes it as the same trait as defined above in Objective-C:
// The NS_REFINED_FOR_SWIFT macro allows this struct to have
// the same name as the Objective-C trait class.
struct ThemeTrait: UITraitDefinition {
static let defaultValue = Theme.standard
static let name = "Theme"
static let identifier = "com.example.themetrait"
}The NS_REFINED_FOR_SWIFT macro makes your Objective-C class available in Swift by prepending double underscores to the class name. You can use this to make your Swift implementation call your Objective-C class properties. For more details, refer to Improving Objective-C API Declarations for Swift.