2012-06-19 5 views
1

У меня есть два разных способа представления данных в моем приложении: через UITableView или UIScrollView.
Итак, у меня есть 2 основных класса: AppTableView: UITableView и AppScrollView: UIScrollView. И я хочу реализовать те же дополнения к обоим представлениям. Поэтому я написал два класса: SomeAdditionsTableView: UITableView и SomeAdditionsScrollView: UIScrollView. Код этого класса тот же. Главные классы сейчас выглядят как
AppTableView: SomeAdditionsTableView и AppScrollView: SomeAdditionsScrollView.Как избежать дублирования кода цели-c

Как избежать дубликата этого кода? Заранее спасибо.

+0

что у вас есть в обоих классах? –

+1

Если это вам поможет, вы можете сделать только один SomeAdditionsScrollView: UIScrollView и удалить SomeAdditionsTableView: UITableView, потому что UITableView является UIScrollView. Затем вы можете использовать SomeAdditionsScrollView как суперкласс для приложений AppTableView и AppScrollView –

+0

@AdrianAncuta Я не верю, что это сработает. Если подкласс UIScrollView (SomeAdditionsScrollView: UIScrollView) UITableView будет по-прежнему напрямую подклассифицировать UIScrollView и не получит преимущества SomeAdditionsScrollView. Если AppTableView подклассы SomeAdditionsScrollView, он больше не будет tableView. –

ответ

4

Да, это проблема с отсутствием множественного наследования в Objective-c. У меня была такая же проблема при необходимости некоторых методов в подклассе UIView и UIScrollView отдельно здесь: Subclassing UIView vs UIScrollView. Есть 3 возможных решений я знаю:

  1. Если вам не нужно хранить какое-либо переменный экземпляр, просто объявить категорию на UIScrollView и убедитесь, чтобы импортировать эту категорию в двух подклассов. Это самое простое решение, но с наименьшей вероятностью работать, так как вам, вероятно, нужно хранить информацию о состоянии, если вы все-таки подклассифицируете.
  2. Создайте подкласс UITableView и просто не используйте его как UITableView, если вы не хотите UITableView. Вы можете технически просто использовать UITableView в качестве UIScrollView без использования каких-либо методов tableView. Конечно, вы будете в конечном итоге переносить «вес» таблицыView (все переменные экземпляра), но нет причин, по которым вы должны использовать UITableView как UITableView, а не только UIScrollView.
  3. Делегируйте как можно больше кода на отдельный объект, чтобы свести к минимуму дублирование кода. В каждом отдельном подклассе несут переменную экземпляра, которая является делегатом метода, и вызов метода прямого вызова этому делегату. Теперь вот, где это получает удовольствие. Вы можете использовать протоколы для объявления методов делегата в вашем подклассе и переопределить специальный метод NSObject: - (id) forwardingTargetForSelector:(SEL)aSelector, чтобы убедиться, что эти вызовы методов отправляются делегату. Вы используете категорию подкласса, которая соответствует протоколу, объявленному в классе делегата. Это откроет все методы класса делегата в подклассе, не требуя, чтобы вы фактически реализовали эти методы в подклассе. Когда среда выполнения не может найти объявленный метод в подклассе, она вызовет - (id) forwardingTargetForSelector:(SEL)aSelector, которую вы можете использовать для возврата класса делегирования/пересылки. Это предотвратит необходимость переадресации каждого индивидуального метода. В зависимости от того, что делают эти вызовы методов, это может занять немного больше «проводки», но в итоге это сэкономит вам много кода. По сути, это «имитирует» множественное наследование в объектно-с использованием протоколов. См. Мой вопрос/ответ здесь для получения более подробной информации: https://stackoverflow.com/a/9419587/1147934.

Из трех последних вариантов, как правило, работает лучше всего для меня. Требуется небольшая работа, чтобы получить голову, но значительно уменьшит дублирование кода. Я также использую его, когда хочу подкласс без подкласса. Однако самым большим требованием является любой класс, который вы хотите сделать, и ему придется перенести его декларации методов из своего интерфейса в отдельный протокол.Но это действительно неважно, и преимущества получения «множественного наследования, такого как поведение» велики.

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

+0

Я думаю, что метод 3 - это своего рода реализация mixins для языков с одним наследованием; Раньше я использовал это в PHP; в языках MI, mixins действительно мощны и устраняют тонну кода dup. Я действительно думаю, что mixins можно использовать для реализации аспектно-ориентированного программирования. В любом случае ... Мне нравится ваш подход. –

0

Если ваши дополнения не требуются ни при каких условиях, вы можете сделать их category по телефону UIScrollView. Тогда, поскольку UITableView является типом UIScrollView, вы можете использовать методы категорий и на одном из них.

Если им нужно определить новые переменные, то я бы сделал его независимым классом и имел подкласс MyTableView : UITableView с свойством SomeAdditions и, аналогично, MyScrollView : UIScrollView.

0

Вы можете добиться многого, используя протоколы и отношения «has_a», а не привязки «is_a» наследования.
Один очень распространенный шаблон является делегатом, но протоколы также полезны для переадресации вызовов методов для инкапсулированных или обернутых объектов.
в следующем примере классам, которые не связаны друг с другом, совместно используют общий объект, но также возможно, что объекты одного и того же типа используют объекты разных классов, которые реализуют общий протокол, поэтому равные объекты может сделать совсем другой материал.

@interface ClassA : NSObject 
@property (strong) id<BrainProtocol> *brain 
@end 

@@implementation ClassA 
@synthezise brain; 

-(void)theMethod 
{ 
    [brain theMethod]; 
} 
@end 

@interface ClassB : NSObject 
@property (strong) id<BrainProtocol> *brain 
@end 

@@implementation ClassB 
@synthezise brain; 

-(void)theMethod 
{ 
    [brain theMethod]; 
} 
@end 

ClassA *a = [[ClassA alloc] init]; 
ClassB *b = [[ClassB alloc] init]; 

//A object, that implements the BrainProtocol 

Brain *brain = [[brain alloc] init]; 
[a setBrain:brain]; 
[b setBrain:brain]; 
Смежные вопросы