Внедрение категории в реализацию другого интерфейса в Obj-C

#objective-c #inheritance

#objective-c #наследование

Вопрос:

У меня есть пользовательский класс в Obj-C под названием RouteManager, который содержит массив NSStrings. Каждая строка представляет собой название автобусной остановки, которое используется в качестве ключа для словаря, чтобы получить остальную информацию для автобусной остановки (в основном, просто [busStopDictionary allkeys]). В одной из ситуаций, когда мое приложение использует этот массив, я хочу вернуть массив, отсортированный по расстоянию от пользователя. Я начал настраивать код, чтобы иметь возможность вызывать sortedArrayUsingSelector в моем массиве с помощью следующего метода:

 - (NSComparisonResult)compareByDistance:(NSString*) otherStop
{
    // Return appropriate NSOrdered enum here based on comparison of
    // self and otherStop
}
  

Моя проблема заключается в том, что в случае, когда compareByDistance является методом RouteManager, self ссылается на экземпляр RouteManager. Однако мне нужно, чтобы self ссылался на NSString, по которому вызывается compare. Итак, я предположил, что мне нужно настроить категорию как таковую:

 @interface NSString (Support)
-(NSComparisonResult) compareByDistance:(NSString*)otherStop;
@end
  

Это дало правильную ссылку на себя, однако в этом сравнении используются значения из класса RouteManager. При реализации, как показано выше, реализация NSString (Support), очевидно, жалуется на то, что эти значения не объявлены.

Это должно предоставить достаточно справочной информации для моего вопроса. Как мне это сделать? Я хотел бы, чтобы моя категория NSString, которая состоит исключительно из метода compareByDistance, могла использовать значения из текущего экземпляра моего класса RouteManager, который наследуется от NSObject. В идеале, я чувствую, что категория должна каким-то образом находиться в RouteManager. Я чувствую, что должен быть какой-то способ выполнить это, который чище, чем передача необходимых значений в compareByDistance. Заранее спасибо за любую помощь.

Комментарии:

1. Можете ли вы показать пример того, как вы ожидаете comparebyDistance: использования? Как есть, похоже, что вы хотите, чтобы метод принадлежал к NSString , и он принимал бы NSString параметр, так как же RouteManager можно было бы что-то вводить?

2. // stopNames — это массив названий автобусных остановок из [busStopDictionary allkeys] NSArray *stopsSortedByDistance = [stopNames sortedArrayUsingSelector:@selector (compareByDistance:)]; compareByDistance необходимо использовать переменные из экземпляра RouteManager, чтобы проводить сравнения.

Ответ №1:

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

Придайте классу BusStop свойства для имени, местоположения и всего остального. Реализуйте метод compareByDistance: в классе BusStop.

Вы все еще можете использовать словарь, если вам нужно найти их по имени. Просто сохраните их с именем в качестве ключа словаря и объектом BusStop в качестве значения словаря.

Комментарии:

1. Я не против делать это таким образом, и, возможно, это «правильный» способ, которому я придаю довольно большое значение. Теперь имеет смысл, что моя категория NSString на самом деле не была правильным способом сделать это, поскольку это, по-видимому, является нарушением инкапсуляции данных. Я использовал метод category для сравнения других данных, когда категория должна относиться только к типу данных, от которого она наследуется. Прав ли я в этом рассуждении?

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

3. Есть несколько других мест, где класс bus stop мог бы очистить некоторый код, так что это определенно направление, в котором я буду двигаться. Еще раз спасибо!