Instance variable declared in an @interface block instead of a property

ID

objectivec.maintainability.property_data_member

Severity

low

Remediation Complexity

medium

Remediation Risk

low

Remediation Effort

medium

Resource

Encapsulation

Language

Objective-C

Description

Reports an @interface - a class declaration or a class extension - that declares instance variables in a brace block, where a property declaration would do. Both brace placements are recognised, on the @interface line and on the line below it. An interface with no brace block, and an empty brace block, are not reported. One finding is reported per interface, at the @interface line.

Rationale

An instance variable in the interface block is raw storage: it has no accessors, so nothing can be validated, observed or made thread-safe at the point of access, and every read and write in the class touches the field directly. It is also part of the declaration rather than the implementation, so adding, removing or reordering one changes the layout of the class - the reason Apple moved ivar declarations into the implementation and made the compiler synthesise them from properties. A property gives the same storage a name that key-value observing, copy semantics and atomic can all attach to.

The following code illustrates the pattern detected by this rule:

// A class extension declared in the implementation file carries the same block.
// FLAGGED: Instance variable declared in an @interface block instead of a property
@interface Widget () {
    NSMutableArray *_pending;
}
@end

// FLAGGED: Instance variable declared in an @interface block instead of a property
@interface Widget : NSObject {
    NSInteger _count;
    NSString *_title;
}
@property (nonatomic, copy) NSString *name;
@end

/*
@interface Commented : NSObject {
    NSInteger _old;
}
@end
 */

@implementation Widget
- (void)work {
    NSInteger local = 1;
    _count = local;
    NSLog(@"%@ %@", _title, _pending);
}
@end

Remediation

Declare a property instead - @property (nonatomic, copy) NSString *title; - and let the compiler synthesise the backing ivar; the underscore-prefixed name stays available inside the implementation. Where the storage is genuinely private, put the property in a class extension in the implementation file rather than in the public header.

Configuration

This detector does not need any configuration.

© 2026 Xygeni. All rights reserved