Чтобы ответить концептуально, ваш таймер, скорее всего, должен быть подклассом UIViewвместо NSObject.
Чтобы создать экземпляр вашего таймера в IB, просто перетащите UIViewего на представление вашего контроллера представления и установите его class равным имени вашего класса таймера.

Не забудьте указать #importсвой класс таймера в контроллере представления.
Изменить: для дизайна IB (для создания экземпляра кода см. Историю изменений)
Я совсем не знаком с раскадровкой, но я знаю, что вы можете создать свой интерфейс в IB, используя .xibфайл, который почти идентичен использованию версии раскадровки; Вы даже должны иметь возможность копировать и вставлять свои представления целиком из существующего интерфейса в .xibфайл.
Чтобы проверить это, я создал новый пустой .xibфайл с именем «MyCustomTimerView.xib». Затем я добавил представление, к которому добавил метку и две кнопки. Вот так:

Я создал новый подкласс класса объектного C под UIViewназванием «MyCustomTimer». В моем .xibя установил для своего класса владельца файла значение MyCustomTimer . Теперь я могу подключать действия и выходы, как и любой другой вид / контроллер. Полученный .hфайл выглядит так:
@interface MyCustomTimer : UIView
@property (strong, nonatomic) IBOutlet UILabel *displayLabel;
@property (strong, nonatomic) IBOutlet UIButton *startButton;
@property (strong, nonatomic) IBOutlet UIButton *stopButton;
- (IBAction)startButtonPush:(id)sender;
- (IBAction)stopButtonPush:(id)sender;
@end
Единственное препятствие, которое нужно преодолеть, - это получить это .xibна моем UIViewподклассе. Использование .xibзначительно сокращает требуемые настройки. И поскольку вы используете раскадровки для загрузки таймеров, мы знаем, -(id)initWithCoder:что это единственный инициализатор, который будет вызван. Итак, вот как выглядит файл реализации:
#import "MyCustomTimer.h"
@implementation MyCustomTimer
@synthesize displayLabel;
@synthesize startButton;
@synthesize stopButton;
-(id)initWithCoder:(NSCoder *)aDecoder{
if ((self = [super initWithCoder:aDecoder])){
[self addSubview:
[[[NSBundle mainBundle] loadNibNamed:@"MyCustomTimerView"
owner:self
options:nil] objectAtIndex:0]];
}
return self;
}
- (IBAction)startButtonPush:(id)sender {
self.displayLabel.backgroundColor = [UIColor greenColor];
}
- (IBAction)stopButtonPush:(id)sender {
self.displayLabel.backgroundColor = [UIColor redColor];
}
@end
Названный метод loadNibNamed:owner:options:делает именно то, что кажется. Он загружает Перо и устанавливает для свойства «Владелец файла» значение self. Мы извлекаем первый объект в массиве, который является корневым представлением Nib. Мы добавляем представление как подвид, и вуаля оно отображается на экране.
Очевидно, это просто меняет цвет фона метки при нажатии кнопок, но этот пример должен помочь вам в этом.
Примечания на основе комментариев:
Стоит отметить, что если у вас возникают проблемы с бесконечной рекурсией, вы, вероятно, упустили тонкую уловку этого решения. Он не делает то, что вы думаете. Представление, помещенное в раскадровку, не отображается, а вместо этого загружает другое представление как подпредставление. Это представление, которое он загружает, определено в пере. «Владелец файла» в пере - это невидимое изображение. Крутая часть заключается в том, что это невидимое представление по-прежнему является классом Objective-C, который можно использовать как своего рода контроллер представления для представления, которое он приносит из пера. Например, IBActionметоды в MyCustomTimerклассе - это то, чего вы ожидаете больше от контроллера представления, чем от представления.
В качестве примечания, некоторые могут возразить, что это не работает, MVCи я в чем-то согласен. С моей точки зрения, это более тесно связано с кастомом UITableViewCell, который также иногда должен быть частью контроллера.
Также стоит отметить, что этот ответ должен был предоставить очень конкретное решение; создайте один наконечник, который можно создавать несколько раз в одном и том же виде, что и на раскадровке. Например, вы легко можете представить шесть из этих таймеров одновременно на экране iPad. Если вам нужно только указать представление для контроллера представления, который будет использоваться несколько раз в вашем приложении, то решение, предоставленное jyavenard для этого вопроса , почти наверняка будет лучшим решением для вас.