Создание подклассов и переопределение UIView, созданного с помощью nib-файла - PullRequest
1 голос
/ 08 марта 2012

Допустим, я создал подкласс UIView и загружаю его с помощью файла nib.
Я делаю это:

MySubView.m  

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"MySubView" owner:self options:nil];

        [self release];
        self = [[nib objectAtIndex:0] retain];
        self.tag = 1;
        [self fire];
    }
    return self;
}

- (void)fire {
   NSLog(@"Fired MySubView");
}

Теперь я хочу создать несколько вариантов, но яне хочу копировать nib-файл, поэтому я пытаюсь создать подкласс MySubView следующим образом, изменив цвет фона:

RedMySubView.m  


- (id)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
    if (self) {
       self.backgroundColor = [UIColor redColor];
       [self fire];
    }
    return self;
}

- (void)fire {
   NSLog(@"Fired RedMySubView");
}

Представление создано, цвет фона изменился, но действие огня непереопределено подклассом.Если я вызову метод fire, результат будет Fired MySubView в консоли.
Как мне решить эту проблему?
Я хочу сохранить макет пера, но присвоить ему новый класс.

Ответы [ 2 ]

1 голос
/ 20 марта 2012

Когда вы вызываете self = [[nib objectAtIndex:0] retain], вы в основном переопределяете свой объект "self", чтобы он стал MySubView, поскольку MySubView является базовым объектом в файле пера.Это нежелательно, потому что если вызывающим классом является RedMySubView, то он будет переопределен в MySubView.

Вместо этого вы хотите изменить - (id)initWithFrame:(CGRect)frame в MySubView на следующее:

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"MySubview" owner:self options:nil];

        // The base of the nib file. Don't set self to this, instead copy all of its
        // subviews, and "self" will always be the class you intend it to be.
        UIView *baseView = [nib objectAtIndex:0];

        // Add all the subviews of the base file to your "MySubview". This
        // will make it so that any subclass of MySubview will keep its properties.
        for (UIView *v in [baseView subviews])
            [self addSubview:v];

        self.tag = 1;
        [self fire];
    }
    return self;
}

Теперь все должно работать в инициализаторе «MyRedSubView», за исключением того, что огонь будет срабатывать дважды, поскольку вы вызываете его как в MySubView, так и в RedMySubView.

1 голос
/ 20 марта 2012

Я бы сказал, что с помощью [self release] в инициализаторе MySubview initWithFrame вы отбрасываете класс, который вы хотите создать с помощью инициализатора.Класс загружается методом loadNibName и поэтому имеет тот же класс, который определен в кончике.Поэтому бесполезно вызывать инициализатор в подклассе.

Попробуйте реализовать свой собственный конструктор пера в MySubview (например, initWithNibFile):

- (id) initWithNibFile:(NSString *) nibName withFrame:(CGRect) frame

и т. Д.и вызовите этот конструктор в RedMySubview

- (id) initWithNibFile:(NSString *) nibName withFrame:(CGRect) frame {
self = [super initWithNibFile:mynib withFrame:MyCGRect];
if (self)
....

Если вы теперь посмотрите, что ваш nib-файл действительно имеет RedMySubview в качестве класса, fire должен быть переопределен.Если вы используете и MySubview и RedMySubview, вы должны продублировать xib.Или вы создаете абстрактный класс (заглушку), который реализует только инициализатор initWithNibFile, а UIViews, которые вы хотите создать, являются его подклассами:

MyAbstractNibUIView initWithNibFile:withFrame:
MyRedSubview : MyAbstractNibUIView        red.xib
MyGreenSubview :MyAbstractNibUIView       green.xib 
MyBlueSubview : MyAbstractNibUIView       blue.xib
...