Передача данных между классами в какао с


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

Я думаю, что понимаю основы работы @property и @synthesise и использования сеттеров и геттеров, но у меня есть проблема.

Скажем, у меня есть 3 класса: функции, Class1 и Class2.

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

Таким образом, если Class1 записывает или "устанавливает" некоторые данные (скажем) 5 в функции, а Class2 "получает" их, Class2 вернет 0, поскольку Class1 написал только 5 в свой экземпляр функций, который Class2 не может видеть.

Я полагаю, во-первых, это верно? Во-вторых, как это сделать, чтобы Class1 и Class2 могли видеть одни и те же данные для получения и установки.

Спасибо за помощь. Я понимаю это. может быть, это тема, которую я еще не выучил, но если это так, я хотел бы знать, что это такое, чтобы я мог ее изучить.

4 5

4 ответа:

У вас есть несколько вариантов, которые все вытекают из того, что Class1 и Class2 используют один и тот же экземпляр "общего объекта".

  1. явно передать один и тот же экземпляр классу 1 и классу 2 извне, вместо того, чтобы позволить классу 1 и классу 2 создать экземпляр самостоятельно; или
  2. предоставьте одноэлементный инициализатор классу функций, затем убедитесь, что Class1 и Class2 используют его; или
  3. используйте шаблон проектирования, известный как шаблон реестра, и обеспечьте класс 1 и Class2 получают свой экземпляр класса функций из реестра; или
  4. используйте инъекцию зависимостей (комплекс).

Сценарий (1) является самым простым для понимания, так как он выглядит именно так:

Functions *funcs = [[Functions alloc] init];

Class1 *obj1 = [[Class1 alloc] initWithFunctions:funcs];
Class2 *obj2 = [[Class2 alloc] initWithFunctions:funcs];
/* or alternatively use setters after initialization */

Сценарий (2) является следующим простейшим и очень распространенным. Cocoa предоставляет синглетные инициализаторы для многих своих классов. Всякий раз, когда вы видите +shared... в качестве префикса для инициализатора, он, вероятно, возвращает синглет.

@implementation Functions

+(id)sharedFunctions {
  static Functions *sharedFunctions = nil;

  @synchronized(self) {
    if (sharedFunctions == nil) {
      sharedFunctions = [[self alloc] init];
    }

    return sharedFunctions;
  }
}

@end

Статическая переменная инициализируется только один раз, что означает, что вы можете лениво загрузить экземпляр объекта в него, используя проверку на его начальное значение (что происходит только один раз). Каждый последующий вызов метода возвращает один и тот же экземпляр.

Functions *f1 = [Functions sharedFunctions];
Functions *f2 = [Functions sharedFunctions];

/* f1 == f2; */ // always

Вариант (3) не очень заметен в objective-C по сравнению с другими языками, и он достигает тех же целей, что и синглет. Идея заключается в том, что у вас есть словарь объектов, которые можно искать по ключу. Все, что нуждается в доступе к элементам реестра, просто запрашивает реестр для собственного экземпляра. Как правило, реестр сам по себе будет синглетным.

Вариант (4), инъекция зависимостей, на самом деле является очень элегантным решением с рядом преимуществ за счет дополнительной сложности. Преимущества заключаются в том, что вы гарантируете, что зависимости всегда слабо связаны (что делает замену реализаций и модульное тестирование зависимостей независимо друг от друга намного проще). Сложность возникает из-за нестандартных механизмов для извлечение экземпляров того, что вам нужно.

Инъекция зависимостей вращается вокруг идеи, что ни один объект не создает свои собственные зависимости. Вместо того, чтобы полагаться на что-то другое, чтобы обеспечить эти зависимости. Это "что-то еще" известно как контейнер для инъекций зависимостей. Контейнер внедрения зависимостей фактически является слоем поверх шаблона реестра, так как контейнер будет либо содержать предварительно построенные экземпляры зависимостей, либо он будет знать, как создавать новые экземпляры экземпляры.

В простейшем случае инъекция зависимостей-это именно то, что я продемонстрировал в варианте (1). Для этого вам даже не нужен контейнер для инъекции зависимостей.

Переходя на более высокий уровень сложности, инъекция зависимостей привносит концепцию контейнера DI, который инкапсулирует ряд существующих шаблонов проектирования (реестр, как показано в варианте (3), синглет (вероятно, но не строго) и фабрику (чтобы знать, как создавать новые экземпляры объектов). управляет).

Демонстрация полной реализации контейнера DI, вероятно, выходит за рамки этого вопроса, но с точки зрения открытого интерфейса одна реализация может выглядеть следующим образом:
DIContainer *container = [DIContainer sharedContainer];

[container registerClass:[ClassA class]];
[container registerClass:[ClassB class]];
[container registerDependentProperty:@selector(setClassA:)
                      withInstanceOf:[ClassA class]
                            forClass:[ClassB class]];

ClassB *obj = [container makeInstanceOfClass:[ClassB class]];
NSLog(@"ClassB's -classA type = %@", [[obj classA] class]);

Я только что напечатал это в середине этого сообщения, так что не думайте, что это 100% точно, но вы получите концепцию. Контейнер был проинструктирован, что при инициализации экземпляров ClassB он должен вызвать -setClassA:, используя экземпляр ClassA, который он также инициализирует в соответствии с правилами, определенными в контейнере (в этом случае нет зависимостей ClassA, поэтому он просто возвращает простой экземпляр.

Если вы больше ничего не заберете из этого ответа, просто запомните варианты (1) и (2);)

Вам нужно прочитать руководство по основам какао. Раздел, относящийся к вашему вопросу, называется общение с объектами.

На самом деле это скорее вопрос об объектно-ориентированном программировании в целом, но решение относится и к Objective-C. То, что вы хотите сделать, - это создать один экземпляр функций. Этот экземпляр должен быть разделен между экземплярами Class1 и Class2.

Functions *f = [[Functions alloc] init];
Class1 *c1 = [[Class1 alloc] init];
Class2 *c2 = [[Class2 alloc] init];
// set the value of a instance variable of f to the value of aValue from c1
[f setSomeValue:[c1 aValue]];
// now change it to c2's aValue
[f setSomeValue:[c2 aValue]];

Есть много ссылок в интернете, но я считаю, что эта книга является большим преимуществом. Программирование в Objective-C 2.0 (2-е изд.) Стивена г. кочана. Это отличное место для начала.