创建仅对Objective-C中的子类可见的属性

时间:2013-10-11 14:43:59

标签: ios objective-c inheritance scope

我正在尝试创建一个抽象类,并在子类中继承它的一些属性。如果我将属性保留在抽象类的头文件中,则可以访问所有属性。问题是子类的实例也可以访问这些属性,这在我的情况下并不总是可取的。

例如,我在我的抽象类中有一个委托,它将按钮按下发送到它的子类。我意识到这可能不是构建继承的最佳方式,因此欢迎其他建议。但是,我仍然想知道我的子类如何从其超类继承一些属性而不在其实例中使所有这些属性可用。提前谢谢!

以下是一些示例代码:

@interface AbstractClass : UIView

@property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;

@end

…

@protocol ButtonDelegate

@required
- (void) buttonWasPressed;

@end

…

@interface SubClass() <ButtonDelegate>

- (id)init {
    self = [super init];
    if (self) {
        self.buttonDelegate = self;
    }
    return self;
}

-(void) buttonWasPressed {
    [self doSomething];
}

…

@implementation ViewController

- (void)viewDidLoad {
    SubClass *subClass = [[SubClass alloc] init];
    subClass.buttonDelegate = self; // THIS IS NOT DESIRABLE
}

6 个答案:

答案 0 :(得分:4)

UIGestureRecognizer一样。

  1. 所有公共属性和方法都会进入UIGestureRecognizer.h

  2. 所有受保护的属性和方法都会进入UIGestureRecognizerSubclass.h。 仅在*.m - 文件中导入。切勿将其包含在任何公共标题中。

  3. 所有私有属性和方法都会进入*.m - 文件。使用@interface ClassName ()

  4. 示例https://gist.github.com/hfossli/8041396

答案 1 :(得分:3)

  

我的子类如何从其超类继承一些属性   没有在其实例中提供所有这些属性

这有什么问题?

#import <Foundation/Foundation.h>

@interface Animal : NSObject
{
    @protected
    NSString *name; // default access. Only visible to subclasses.
}
@end

@implementation Animal
-(NSString*)description {
    return name;
}
@end

@interface Cow : Animal
@end

@implementation Cow

-(id)init {
    self=[super init];
    if (self){
        name   = @"cow";
    }
    return self;
}
@end

int main(int argc, char *argv[]) {
    @autoreleasepool {
        Cow *cow = [Cow new];
        NSLog(@"%@", cow); // prints the name through internal access
        // error accessing from the outside: NSLog(@"%@", cow.name);

        Animal *animal = [Animal new];
        // error accessing from the outside: NSLog(@"%@", animal.name);
    }
}

也许我误解了这个问题,你说

  

创建仅对Objective-C

中的子类可见的属性

然后

  

问题是子类的实例也可以访问它们   特性

是哪一个?

答案 2 :(得分:1)

在实施文件(.m)之上创建一个空类别:

@interface AbstractClass()

@property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;

@end

这样,您的子类将继承并可以访问该属性,但不能访问其他外部类,因为它不在标题中。

答案 3 :(得分:1)

我认为使用属性声明无法实现此目的。

一个属性对所有人都可见(在.h文件中声明)或者对所有人都是不可见的(使用类别在.m文件中声明)

我猜一种方法是在.h文件类声明中声明公共/受保护变量:

@interface AbstractClass : UIView {

   ...

   id<ButtonDelegate>buttonDelegate;

   ...
}
@end

我不确定这一点,但试一试。

答案 4 :(得分:1)

我看到一种方法可以适合您的问题,但是,它非常粗鲁。使用Antonio的建议并使用该属性创建私人类别。正如您所提到的,它的范围仅限于.m文件。因此,您可以将子类放入该文件中。如果子类很大,这将很难读取代码,但据我所知,这是你唯一的方法。

编辑:好吧,我有另一个解决方案。复制

@property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;

到你的所有子类。这将为您提供有关缺少属性@synthesize的警告,但应该有效。如果子类不经常更改或添加,我更喜欢这个。

让我描述它是如何运作的。

我们在Abstract类中添加了一个属性,它对所有人都隐藏了(即使对于子类):

// .m file

@interface Abstract ()

@property (nonatomic, strong) id<ButtonDelegate> buttonDelegate;

@end


@implementation Abstract

@synthsize buttonDelegate;

@end;

但是由于Objective-C的运行时功能,我们仍然可以调用该属性,并且不会有任何运行时错误,只有编译器警告。

要消除该警告并添加自动完成功能,我们将没有@synthsize的属性添加到所有子类中:

@interface MySubclass : Abstract

@property (nonatomic, strong) id<ButtonDelegate> buttonDelegate;

@end

这将告诉编译器某处有这样的属性。还会有一个关于缺少@synthesize的警告,但是如果你写了类似

的话,Xcode仍然可以自动完成
MySubclass *subclass = ...
subclass.butto...

答案 5 :(得分:0)

无法做到。在objective-c中没有私有或受保护。在.m文件“private”接口中声明的东西只对该类可见,而不在任何子类中可见。此外,如果您愿意,您也可以随时使用外部的“私人”属性/方法,尽管这样做是不好的做法。