MVC — ключевая часть хорошего проектирования на Cocoa. Приложения, использующие MVC, также более легко расширяемы, чем другие приложения. Кроме того, много технологий и архитектур Cocoa основываются на MVC и требуют, чтобы ваши пользовательские объекты играли одну из ролей MVC.

В MVC существует 3 роли:

  • Model: объект, который содержит данные приложения и определяет, как управлять ими.
  • View: объекты, которые отвечают за визуальное представление модели и пользовательские манипуляции. Представлениями, в основном, являются все UIView-производные объекты.
  • Controller: контроллер-посредник, который координирует всю работу. Он получает доступ к данным модели и выводит их на экран с помощью представления, следит за событиями и управляет данными по мере необходимости.

 

Правильная реализация паттерна MVC означает, что в вашем приложении каждый объект попадает только в одну из этих групп. Как показано на схеме.

mvc

 

Чтобы всё это применить на практике, напишем тестовое приложение для просмотра списка книг.

Выделим наши три основных составляющих:

  • Модель — книга, у которой будут поля: название, автор, цена;
  • Представление — это само отображение наших данных, мы их будем отображать их в таблице;
  • Контроллер — это наш координатор между моделью и нашим представлением.

 

Создаём новый файл для нашей модели с названием Book.

В заголовочном файле Book.h пропишем свойства и метод инициализации.


//Book.h

@interface Book : NSObject
@property (strong, nonatomic) NSString* name;        //Название книги
@property (strong, nonatomic) NSString* author;     //Автор книги
@property (assign, nonatomic) CGFloat price;        //Цена книги
- (id) initWithName:(NSString*) name author:(NSString*) author price:(CGFloat) price;  //Метод инициализации нашего объекта Book
@end

В файле реализации Book.m опишем наш метод.


//Book.m
#import "Book.h"

@implementation Book
- (id) initWithName:(NSString*) name author:(NSString*) author price:(CGFloat) price {
    self = [super init];
    if(self) {
        self.name = name;
        self.author = author;
        self.price = price;
    }
    return self;
}
@end

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

Создаём новый файл с названием BookManager.
В заголовочном файле BookManager.h пропишем свойства и метод инициализации.


//BookManager.h
@class Book;

@interface LibraryManager : NSObject
@property (strong, nonatomic) NSArray* books;    //Массив из всех наших книг
+ (id) sharedInstance;                              
@end

В файле реализации LibraryManager.m мы описываем метод инициализации, а так же заполним  небольшим количество данных наш массив books.


//BookManager.m
#import "LibraryManager.h"
#import "Book.h"

@implementation LibraryManager

+ (id) sharedInstance {
    
    static Book* sharedInstance = nil;           //статическая переменная для хранения указателя на объект класса
    static dispatch_once_t onceToken;           //статическая переменная, обеспечивающая выполнение кода инициализации единожды 
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];  //блок инициализации
    });
    return sharedInstance;
}

- (instancetype)init                      //В данном методе мы заполняем наш массив книг
{
    self = [super init];
    if (self) {
        self.books = [NSMutableArray arrayWithArray:
                 @[[[Book alloc] initWithName:@"Harry Potter and the Sorcerer's Stone"
                                       author:@"Joanne Rowling"
                                        price:10.f],
                   [[Book alloc] initWithName:@"Война и мир"
                                       author:@"Лев Толстой"
                                        price:13.f],
                   [[Book alloc] initWithName:@"The Old Man and the Sea"
                                       author:@"Ernest Hemingway"
                                        price:8.4f]]];
    }
    return self;
}
@end

Далее откроем наш Main.storyboard, удалим имеющийся там ViewController и создадим NavigationController.
Выберем наш NavigationController и установим ему свойство isInitialViewController в Attributes Inspector, как показано на рисунке.

bezymyannyj

 

Создадим новый файл для нашего контроллера, назовём его BookViewController, наследник UIViewController. Откроем файл BookViewController.m. Для отображения наших данных в таблице нам необходимо:

  1. Задать количество секций в нашей таблице (по умолчанию 1);
  2. Задать количество ячеек в нашей таблице, у нас их будет столько сколько книг в нашей библиотеке;
  3. Ну и конечно отрисовка самой ячейки.
//BookViewController.m
#import "BookTableViewController.h"
#import "LibraryManager.h"
#import "Book.h"

@interface BookTableViewController () 
@end

@implementation BookTableViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

#pragma mark - UITableViewDataSource

//количество секция в нашей таблице
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 1;
}
 //Считаем какое количество ячеек нужно отрисовать для нашей секции (секций в нашем случае 1) 
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [[[LibraryManager sharedInstance] books] count]; 
} 

//Рисуем наши ячейки, 
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 

//Идентификатор нашей ячейки static NSString* identifier = @"Cell"; 

//Создаем ячейку из нашей таблицы по заданному идентификатору 
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; 

//Если такой ячейки ещё нет, то создаем новую 
if(!cell) { 
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier]; 
} 

//Заполняем поля нашей ячейки 
cell.textLabel.text = [[[[LibraryManager sharedInstance] books] objectAtIndex:indexPath.row] name]; 
cell.detailTextLabel.text = [NSString stringWithFormat:@"%f", 
[[[[LibraryManager sharedInstance] books] objectAtIndex:indexPath.row] price]]; 

return cell; 
} 

@end 

Осталось сделать последний штрих. Нам надо присвоить класс нашему Root View Controller в нашем сториборде как показано на рисунке.

add

 

Ну и наконец мы можем запустить наше приложение и убедиться что оно работает.

new

Исходный код данного примера: alhafram/mvcExample

Автор фото: @madeawkward

Спасибо за внимание.

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.