Исходя из вашего вопроса и вашего ответа на вопрос с высоким содержанием кофеина - чей ответ правильный, но я думаю, что он может быть немного искажен от того, что вы спрашиваете - я думаю, что вы хотите иметь возможность графически создать представление в Интерфейсном Разработчике (так Вы не написали пользовательский подкласс UIView, вы просто упорядочили некоторые UIViews определенным образом, чтобы они все были потомками другого представления), а затем встроили его в несколько контроллеров представления с помощью некоторой косвенной ссылки, чтобы вы могли Вы не копируете и не вставляете одни и те же элементы пользовательского интерфейса, и если вы вносите изменения в одном месте, это изменение вступает в силу везде?
Насколько я знаю, в Interface Builder или Xcode 4 нет встроенного средства для достижения этой цели. XIB - это чистые данные, а у UIViews нет умов для обработки ссылки вне файла.
Что вы можете сделать, так это спроектировать представление, которое вы хотите использовать в одном XIB, называемом, скажем, ReusableView.xib, а затем написать собственный подкласс UIView, который будет выглядеть примерно так:
@implementation ReusableViewTemplate
- (id)initWithCoder:(NSCoder *)aDecoder
{
// initialise ourselves normally
self = [super initWithCoder:aDecoder];
if(self)
{
// load everything in the XIB we created
NSArray *objects = [[NSBundle mainBundle]
loadNibNamed:@"ReusableView" owner:self options:nil];
// actually, we know there's only one thing in it, which is the
// view we want to appear within this one
[self addSubview:[objects objectAtIndex:0]];
}
return self;
}
@end
Затем в ваших NIB вставьте UIView, в который вы хотите переместить многоразовое представление, и установите для 'class' значение 'ReusableViewTemplate' или как вы его назвали.
Если вы откроете ReusableView XIB и установите тип родительского представления на ReusableViewTemplate, то вы можете подключить любые элементы UIControl (например, кнопки или переключатели) для подключения к ним. Вы, вероятно, захотите определить какой-то собственный протокол для своего многоразового шаблона представления и перехватить viewDidLoad в любых контроллерах представления, которые используют повторно используемое представление для установки соответствующего делегата.
РЕДАКТИРОВАТЬ: дальнейшие мысли по этому поводу. Я создал пример проекта (в настоящее время на обычном сайте общего доступа к файлам, поэтому может не существовать вечно) с классом ReusableView, который для целей примера содержит вид сегмента и кнопку и выглядит как это:
@implementation ReusableView
/*
initWithCoder loads the relevant XIB and adds its
only object, which is a UIView, as a subview of this
one. If you don't like the double hierachy, you
could just have a list of views in the XIB and
addSubviews:, but then it'd much more difficult to
edit the thing graphically. You could strip the top
view programmatically, but this is just a simple
example, so...
*/
- (id)initWithCoder:(NSCoder *)aDecoder
{
// initialise ourselves normally
self = [super initWithCoder:aDecoder];
if(self)
{
// load everything in the XIB we created
NSArray *objects = [[NSBundle mainBundle]
loadNibNamed:@"ReusableView"
owner:self
options:nil];
// actually, we know there's only one thing in it, which is the
// view we want to appear within this one
[self addSubview:[objects objectAtIndex:0]];
}
return self;
}
@synthesize delegate;
@synthesize segmentedControl;
@synthesize button;
/*
NSObject contains machinery to deal with the possibility
that a class may be sent a selector to which it doesn't
respond.
As of iOS 4, forwardingTargetForSelector: can be used to
nominate an alternative target for the selector quickly.
In previous versions of iOS, or in iOS 4 if you don't
respond to forwardingTargetForSelector:, you may take
delivery of the problematic invocation and deal with it
yourself.
Dealing with the invocation costs more than providing
a forwarding target for the selector, so its worth having
both.
If you're only targeting iOS 4 or above, you needn't
keep the implementation of forwardInvocation: below.
What we're doing is declaring a bunch of IBActions so
that we can wire changes up to them in Interface Builder.
By failing to implement them and providing the delegate
as the thing to talk to for any selectors we don't know,
we're allowing those wirings to be as though assigned
to the delegate.
*/
- (id)forwardingTargetForSelector:(SEL)aSelector
{
return delegate;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
[anInvocation setTarget:delegate];
[anInvocation invoke];
}
@end
С интерфейсом:
@interface ReusableView : UIView
{
IBOutlet id delegate;
IBOutlet UISegmentedControl *segmentedControl;
IBOutlet UIButton *button;
}
@property (nonatomic, assign) id delegate;
@property (nonatomic, assign) UISegmentedControl *segmentedControl;
@property (nonatomic, assign) UIButton *button;
/*
NB: we're not actually going to implement these. We're
declaring them for the benefit of Interface Builder / Xcode 4.
What we'll actually do is, any time we receive a selector
we don't implement, hand it off to the delegate. So it's a
quick way of avoiding writing any glue code to pass messages
from this little reusable view to its delegate.
A better alternative could define a formal protocol that
forwards both the changed control and self from the
reusable view to its delegate. But that's obvious and
verbose, so has been omitted for the purposes of example.
The implementation as stands will generate compiler warnings,
but such is life. To get rid of the warnings, comment out
the two following lines, but only AFTER you've wired
everything up in Interface Builder / Xcode 4. They're left
uncommented here to help draw attention to the point about
selector/invocation forwarding that you'll see in the
@implementation.
!!!!!!!!!!!!!!!
HENCE:
delegates MUST implement the following methods.
!!!!!!!!!!!!!!!
We could work around that by checking at runtime whether
the actual delegate implements them and forwarding to
a dummy object that implements them to do nothing otherwise,
but that's slightly beyond the point of the example.
*/
- (IBAction)reusableViewSegmentControlDidChange:(id)sender;
- (IBAction)reusableViewButtonWasPressed:(id)sender;
@end
Чистый эффект заключается в том, что если у контроллера представления есть UIView типа ReusableView в XIB, он получает содержимое ReusableVew.xib, вставленное во время выполнения. Если он подключается как делегат ReusableView в Интерфейсном Разработчике / XCode 4 и реализует:
- (IBAction)reusableViewSegmentControlDidChange:(id)sender;
- (IBAction)reusableViewButtonWasPressed:(id)sender;
Затем он получает сообщения от встроенных представлений.
Это достигается очень просто и очень аккуратно в Objective-C с помощью присущей NSObject способности пересылать селекторы (начиная с iOS 4) или вызовы (в более ранних версиях, с более высокой стоимостью), которые он не реализует, а не позволяет исключение.