我知道尝试将属性放在一个类别中并不是一个好主意。我可以从扩展它的类别中访问类的实例变量吗?或者是否有必要在正在扩展的类上公开访问器?
例如,假设我有一个名为“Person”的类,其实现如下:
#import "Person.h"
@interface Person()
{
NSMutableArray *_friends;
}
@end
@implementation Person
- (instancetype)init
{
self = [super init];
if (self) {
_friends = [NSMutableArray array];
}
return self;
}
-(instancetype)initWithFirstname:(NSString *)firstName lastname:(NSString *)lastName
{
self = [self init];
if (self) {
_firstName = firstName;
_lastName = lastName;
}
return self;
}
-(NSString *)getFullName{
return [NSString stringWithFormat:@"%@ %@", _firstName, _lastName];
}
@end
注意ivar _friends
。让我们说(由于某种原因或其他原因)我想将处理一个人的朋友的所有操作分成一个类别,如下所示:
#import "Person.h"
@interface Person (Friends)
-(NSArray *)getFriends;
-(void)addFriend:(Person *)person;
-(void)removeFriend:(Person *)person;
@end
在类别Person(Friends)
中,编译器不会知道Person
的ivar _friends
。
即。
//Person.h
@interface Person
@property(nonatomic, strong) NSMutableArray *friends;
...
@end
最好不要暴露这个。
答案 0 :(得分:5)
一般来说,类别无法访问ivars;从类扩展中合成的ivars和ivars在主要实现之外是私有的和不可见的。
但是,您可以通过在其自己的私有标头中的扩展名中声明ivar并将该标头导入类别的文件中来执行您想要的操作。请务必将私有标头导入到类的主要实现文件中。
答案 1 :(得分:3)
谁告诉过你编译器不会知道Person
_friends
?
它知道。只需在班级_friends
中声明@interface
,而不是在扩展程序中声明。
@interface Person : NSObject
{
@protected
NSMutableArray *_friends;
}
@end
其他对象无法访问@protected
_friends
。
答案 2 :(得分:0)
如果你有很多协议,代理人,数据源等等。 MainViewController ,您希望将回调外包给单独的文件(类别),例如
"MainViewController+DelegateCallbacks.h"
"MainViewController+DelegateCallbacks.m"
但同时仍希望能够从这些类别访问所有控制器的私有 @properties ,而无需在公共接口中公开它们
"MainViewController.h"
最优雅的解决方案仍然是在单独的头文件中创建一个私有接口(扩展名),如
"MainViewController_PrivateInterface.h"
但是 - 而不是 ivars - 就像上面已经解释的Josh Caswell一样,把所有 @properties (这些外包代表需要访问)也在该扩展中。这样你就可以隐藏所有 准私人 ,其他人也无法看到它们。最重要的是不在你的公共界面!而且您甚至可以选择直接在代码中访问@properties的后备存储ivars(而不是方便点表示法),只需在此私有外部接口文件中手动创建相应的后备存储ivars即可。只是不要忘记在你想访问这些ivars的任何地方导入你的私有接口标题(包括你的MainViewController; - )
//
// MainViewController.m
//
#import "MainViewController.h"
#import "MainViewController+DelegateCallbacks.h"
#import "MainViewController_PrivateInterface.h"
@interface MainViewController () <UICollectionViewDelegate,
UICollectionViewDataSource,
UICollectionViewDelegateFlowLayout,
UIGestureRecognizerDelegate>
#pragma mark - <UIGestureRecognizerDelegate>
#pragma mark - <UIContentContainer>
#pragma mark - <UITraitEnvironment>
// etc.
@end
------------------------------------------------------------------------
//
// MainViewController+DelegateCallbacks.h
//
#import "MainViewController.h"
@interface MainViewController (DelegateCallbacks)
@end
------------------------------------------------------------------------
//
// MainViewController+DelegateCallbacks.m
//
#import "MainViewController+DelegateCallbacks.h"
#import "MainViewController_PrivateInterface.h"
@implementation MainViewController (DelegateCallbacks)
#pragma mark <UICollectionViewDataSource>
#pragma mark <UICollectionViewDelegate>
#pragma mark <UICollectionViewDelegateFlowLayout>
// etc.
@end
------------------------------------------------------------------------
//
// MainViewController_PrivateInterface.h
//
#import "MainViewController.h"
@interface MainViewController () {
// NSMutableArray <NSArray *> *_myArray_1;
// NSMutableArray <UIBezierPath *> *_myArray_2;
}
@property (strong, nonatomic) NSMutableArray <NSArray *> *myArray_1;
@property (strong, nonatomic) NSMutableArray <UIBezierPath *> *myArray_2;
@property (weak, nonatomic) IBOutlet MyView *myView;
@property (weak, nonatomic) IBOutlet MyCollectionView *myCollectionView;
@property (nonatomic) CGFloat myFloat;
// etc.
@end