Подклассы в Objective C — Xcode Mac OS

Подклассы в Objective C, это один из важнейших механизмов программирования. Я не очень сильно буду распинаться, что это такое и с чем едят, но для того, чтобы у вас возникло общее понимание предмета, самые важные и основные моменты я обязательно здесь затрону. Моя основная цель, это дать конкретные ответы, на вполне конкретные вопросы, пусть даже на очень простые, но ответы на которые бывает иногда ищут очень долго. Проще говоря, опишу все простыми словами, по принципу - как просто.

Для чего нужны подклассы?

Причина существования подклассов достаточно весомая, если кратко, то это наследование, т.е. возможность нескольким классам совместно использовать имеющуюся функциональность. Подробнее:

  • Подкласс наследует методы другого класса (суперкласса).
  • Подкласс наследует переменные экземпляра суперкласса.
  • Подкласс может переопределять методы, унаследованные от его суперкласса. Это называется замещением (overriding). Если подкласс переопределяет метод, унаследованный от его суперкласса, то когда соответствующее сообщение отправляется экземпляру этого подкласса, вызывается версия метода, определенная в подклассе.
  • Подкласс может определять свои собственные методы. Подкласс состоит из методов, наследуемых от своего суперкласса, а также может иметь некоторые собственные методы.
  • Подкласс может также определять свои собственные переменные экземпляра.

 

Что такое наследование?

Наследование - это механизм языка, позволяющий описать новый класс на основе уже существующего (родительского, базового) класса или интерфейса. Потомок может добавить собственные методы и свойства, а также пользоваться родительскими методами и свойствами всех вышестоящих классов. Наследование передается от вышестоящего класса к нижестоящему классу и только в одном направлении от суперкласса к дочернему классу (подклассу). Например суперкласс Class1 не может воспользоваться методами и переменными нижестоящих классов Class2 и Class3, но зато Class3 может использовать все методы и переменные классов Class1 и Class2.

 

Как создать подкласс?

Благодаря имеющимся возможностям подклассы (субклассы) например часто используют для кастомизации элементов интерфейса. Ниже живой пример создания подкласса для класса NSView.

 

Готовый пример:

Заголовочный файл .h подкласса NSView в Objective-C

//
//  CustomView.h
//
//  Created by Saveliy Severniy on 03.03.18.
//  Copyright © 2018 Saveliy Severniy. All rights reserved.
//

#import <Cocoa/Cocoa.h>

// CustomView - это ваше произвольное имя подкласса.
// В нашем примере это имя будет CustomView.
@interface CustomView : NSView

/* Наш индивидуально созданный метод подкласса для примера */
- (NSString *)parceMyString:(NSString *)string;

@end

Файл реализации .m подкласса NSView в Objective-C

//
//  CustomView.m
//
//  Created by Saveliy Severniy on 03.03.18.
//  Copyright © 2018 Saveliy Severniy. All rights reserved.
//

#import "CustomView.h"

@implementation CustomView

- (void)drawRect:(NSRect)dirtyRect {
    [super drawRect:dirtyRect];
    
    // Drawing code here.
}


/* Наш индивидуально созданный метод подкласса для примера */
- (NSString *)parceMyString:(NSString *)string {
    if ([string length] >= 1) {
        string = [string stringByReplacingOccurrencesOfString: @ "," withString: @ "."];
    }
    return string;
}

@end

 

Выше созданный класс (подкласс для класса NSView) пока почти ничего не делает, это лишь "шапка", в котором мы реализовали для примера наш собственный один метод parceMyString:string, но этот подкласс уже можно подключить к вашему коду и начать реализовывать свои идеи. Чтобы создать подкласс для любого другого класса, как правило, достаточно лишь изменить в шаблоне имя суперкласса, для которого вы хотите создать подкласс. Например, чтобы создать субкласс для NSButton, нужно и вписать это имя суперкласса вместо NSView (в заголовочном файле .h).

 

Как подключить подкласс в Interface Builder?

Чтобы подключить свой кастомный подкласс к объекту View в Interface Builder, выделите нужный View мышкой и справа в инспекторе свойств в разделе Custom Class введите имя свое нового подкласса или выберите его из списка и сохраните изменения. Все, теперь при запуске приложения к данному объекту будет применен ваш подкласс, в котором автоматически будут вызываться те методы, которые вы переопределили относительно существующих методов из суперкласса.

Если к примеру вас интересует только кастомная реализация интерфейса, этого вполне достаточно. Но если вы в своем новом подклассе дополнительно реализовали некоторые методы, которые требуется вызывать из основного кода контроллера, вам также потребуется выполнить еще некоторые действия. Для получения подробностей переходим ниже к следующему разделу.

 

Как получить доступ к методам подкласса?

Не всегда бывает достаточно только создать кастомный подкласс, иногда еще нужно иметь возможность обращаться к методам этого подкласса из основного кода. Теперь по порядку. Чтобы из основного класса можно было вызвать некий метод из подкласса, нужно правильно подключить подкласс к основному классу:

1. Через директиву #import в файле реализации нужного нам контроллера мы подключаем заголовочный файл нашего подкласса. Например к классу ViewController мы подключили подкласс CustomView, вписав строку: #import "CustomView.h".

2. В заголовочном файле ViewController.h через ключевое слово @class указываем имя нашего кастомного класса (подкласса).

3. Ниже, в разделе @interface добавляем аутлет IBOutlet CustomView* myCustomView;

4. Теперь из кода реализации основного контроллера (в данном случае естественно из ViewController.m) мы спокойно можем вызвать метод из нашего нового подкласса следующим образом: [myCustomView parceMyString:@"It works,,!"];

 

Готовый пример с подключенным подклассом CustomView:

Заголовочный файл ViewController.h

//
//  ViewController.h
//
//  Created by Saveliy Severniy on 03.02.18.
//  Copyright © 2018 Saveliy Severniy. All rights reserved.
//

#import <Cocoa/Cocoa.h>

@class CustomView;

@interface ViewController : NSViewController {
    // Ссылка на наш кастомный класс CustomView
    IBOutlet CustomView *myCustomView;
}

Файл реализации ViewController.m

//
//  ViewController.m
//
//  Created by Saveliy Severniy on 03.02.18.
//  Copyright © 2018 Saveliy Severniy. All rights reserved.
//


#import "ViewController.h"
#import "CustomView.h"

 

Как в подкласс добавить свои переменные?

Бывает необходимость в добавлении в подкласс некоторых своих переменных. Это делается очень просто, также, как и в любом другом классе. А чтобы получить доступ к переменным подкласса из основного класса, достаточно выполнить настройки, которые мы уже проходили чуть выше, то есть нужно правильно подключить подкласс к вашему базовому классу.

1. В заголовочном файле CustomView.h в разделе @interface добавляем переменную экземпляра класса - NSCursor *cursor;

2. Дальше, под разделом @interface объявляем (описываем) свойства переменной экземпляра класса - @property (strong) NSCursor *cursor;

3. Последний шаг, в файле реализации CustomView.m после раздела @implementation синтезируем нашу переменную - @synthesize cursor;

 

Результат нашего урока

Итоговый заголовочный файл .h подкласса NSView

//
//  CustomView.h
//
//  Created by Saveliy Severniy on 03.03.18.
//  Copyright © 2018 Saveliy Severniy. All rights reserved.
//

#import <Cocoa/Cocoa.h>

@interface CustomView : NSView {
    // Переменная экземпляра класса
    NSCursor *cursor;
}

// Указываем свойство переменной экземпляра класса
@property (strong) NSCursor *cursor;

// Наш индивидуально созданный метод. Используя этот метод,
// мы в string заменяем все запятые на точку.
- (NSString *)myAddTitle:(NSString *)string;

@end

Итоговый файл реализации .m подкласса NSView

//
//  CustomView.m
//
//  Created by Saveliy Severniy on 03.03.18.
//  Copyright © 2018 Saveliy Severniy. All rights reserved.
//

#import "CustomView.h"

@implementation CustomView
@synthesize cursor;

- (void)drawRect:(NSRect)dirtyRect {
    [super drawRect:dirtyRect];
    
    // Drawing code here.
}

// Применяем курсор, если он задан.
- (void)resetCursorRects
{
    if (self.cursor) {
        [self addCursorRect:[self bounds] cursor: self.cursor];
        NSLog(@"resetCursorRects 1: %s %d", (strrchr(__FILE__, '/') ?: __FILE__ - 1) + 1, __LINE__);
    } else {
        [super resetCursorRects];
        NSLog(@"resetCursorRects 2: %s %d", (strrchr(__FILE__, '/') ?: __FILE__ - 1) + 1, __LINE__);
    }
}

//------------------------------------------------------------------------//
// viewWillMoveToWindow:newWindow
//------------------------------------------------------------------------//
// Сообщает, что он добавляется в иерархию представления указанного
// объекта окна (он может быть равно нулю). Этот метод вызывается при
// изменении окна представления.
//------------------------------------------------------------------------//

- (void)viewWillMoveToWindow:(NSWindow *)newWindow {
   
    // Задаем вид курсора по умолчанию. Реализация в методе viewWillMoveToWindow
    // представлена для примера. Вы можете установить переменную cursor в любом
    // другом методе или даже это сделать из основного класса. По нашему уроку
    // вызов из ViewController будет выглядеть так:
    // [myCustomView setCursor:[NSCursor dragLinkCursor]];
    
    cursor = [NSCursor pointingHandCursor];
}

// Наш индивидуально созданный метод. Используя этот метод,
// мы в string заменяем все запятые на точку.
- (NSString *)parceMyString:(NSString *)string {
    if ([string length] >= 1) {
        string = [string stringByReplacingOccurrencesOfString: @ "," withString: @ "."];
    }
    return string;
}

@end

 

На этом вроде все. На что хватило времени и сил, я постарался разжевать, но надеюсь, я все же до вас донес основные моменты в полном объеме. Если найдете ошибки в тексте, в уроке, или что-то захотите дополнить, буду рад вашим комментам.

 

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *