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

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

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

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

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

 

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

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

 

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

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

 

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

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

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

#import <Cocoa/Cocoa.h>

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

/* Наш индивидуально созданный метод подкласса для примера */
- (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 "MyTextLib.h"

@implementation MyTextLib



/* Наш индивидуально созданный метод подкласса для примера */
- (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,,!"];

 

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

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

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

#import <Cocoa/Cocoa.h>

@class MyTextLib;

@interface ViewController : NSViewController {
    // Здесь объявляются переменные. Внизу справка.
    // Здесь объявляются переменные (только для переменных экземпляра класса).
    MyTextLib *myTextLib;
}

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

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


#import "ViewController.h"
#import "MyTextLib.h"

 

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

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

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

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

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

 

Результат текущего урока - отдельная библиотека MyTextLib

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

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

#import <Cocoa/Cocoa.h>

@interface MyTextLib : NSString {
    //------------------------------------------------------------------------//
    // Здесь объявляются переменные (только для переменных экземпляра класса).
    //------------------------------------------------------------------------//
    // 1. Метод со знаком + : имеет доступ только к self объекту.
    // 2. Метод со знаком - : имеет доступ только к методам экземпляра и его переменным.
    
    NSCursor *cursor; // Кстати. Внизу справка!
}


//------------------------------------------------------------------------//
// Здесь объявляются свойства переменных и методы.
//------------------------------------------------------------------------//
 
// Указываем свойство переменной
@property (strong) NSCursor *cursor;


//------------------------------------------------------------------------//
// Методы.
//------------------------------------------------------------------------//
// 1. + для метода класса (метод может быть вызван без создания экземпляра класса)
// 2. - для метода экземпляра (instance)
//------------------------------------------------------------------------//

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

@end


//------------------------------------------------------------------------//
// СПРАВКА
//------------------------------------------------------------------------//
// В настоящее время компания Apple рекомендует помещать ключевое слово IBOutlet в объявлении свойства.
//
// Когда недавно компания Apple изменила компилятор, используемый по умолчанию, с GCC на LLVM,
// объявлять переменные экземпляров для свойств стало необязательным. Если компилятор LLVM
// обнаружит свойство, которому не соответствует ни одна переменная экземпляра, она создаст ее
// автоматически. Но это не освобождает от реализации оператора @synthesize, хотя вы можете и не
// писать @synthesize, однако в этом случае вам придется самому написать реализации геттера и сеттера.
//
// Внимание. Начиная с Xcode 4.5 использование @synthesize в файле реализации стало необязательным.
// В этом случае в файле - заголовке объявляется свойство @property NSInteger vSize; и доступ к самой
// переменной будет начинаться с символа подчеркивания _vSize, а доступ к сеттеру или геттеру внутри класса [self vSize].
//------------------------------------------------------------------------//

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

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

#import "MyTextLib.h"

@implementation MyTextLib
@synthesize cursor;


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

@end

 

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

 

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

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