У меня есть собственный класс / объект, который обрабатывает жесты и выполняет анимацию для данного представления с помощью CADisplayLink. В простейшей форме мой класс выглядит примерно так:
@interface SomeClass : NSObject
@property (strong) UIView *someView;
@end
Когда я добавляю следующий код в свой контроллер представления ...
- (void)viewDidLoad
{
[super viewDidLoad];
SomeClass *someClass = [[SomeClass alloc] init];
someClass.someView = someView;
}
... Я ожидал, что мой объект someClass будет сохранен на время жизни контроллера представления, поскольку я использую сильную ссылку на someView.
Однако someClass немедленно освобождается.
Я уже знаю, что могу преодолеть освобождение, просто добавив someClass в качестве свойства (или даже iVar) контроллера представления, однако в идеале я хотел бы избежать этой дополнительной работы ...
Так есть ли способ сохранить мой класс до тех пор, пока не будет освобожден связанный с ним контроллер представления или представления?
ИЗМЕНИТЬ
Объекты UIGestureRecognizer - это пример класса, который не освобождается, когда я связываю их с представлением ...
- (void)viewDidLoad
{
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] init];
[someView addGestureRecognizer:gestureRecognizer];
}
// tapGestureRecognizer still lives
Предположительно это связано с тем, что UIView становится владельцем объекта UIGestureRecognizer. Есть ли способ добиться этого с помощью моего класса и категории UIView? То есть ....
- (void)viewDidLoad
{
[super viewDidLoad];
SomeClass *someClass = [[SomeClass alloc] init];
[someView addSomeClass:someClass];
}
3 ответа
Если вы хотите связать объект с UIView таким же образом, как это делает UIGestureRecognizer, то это технически возможно с использованием связанныхObjects следующим образом (но я не уверен, что я бы поддержал этот подход, поскольку связанные нахмурился) ...
< Сильный > SomeClass.h
@class SomeClass;
@interface UIView (SomeClass)
- (void)addSomeClass:(SomeClass *)someClass;
- (void)removeSomeClass:(SomeClass *)someClass;
@end
@interface SomeClass : NSObject
@property (strong) UIView *someView;
@end
SomeClass.m
#import "SomeClass.h"
#import <objc/runtime.h>
@implementation UIView (AssociatedObject)
- (void)addSomeClass:(SomeClass *)someClass
{
NSMutableArray *someClasses = [self someClasses];
if (someClasses == nil) {
someClasses = [[NSMutableArray alloc] init];
[self setSomeClasses:someClasses];
}
[someClasses addObject:someClass];
}
- (void)removeSomeClass:(SomeClass *)someClass
{
NSMutableArray *someClasses = [self someClasses];
if (someClasses != nil) {
[someClasses removeObject:someClass];
if (someClasses.count == 0) {
[self setSomeClasses:nil];
}
}
}
#pragma mark - Private Methods
- (NSMutableArray *)someClasses
{
return (NSMutableArray *)objc_getAssociatedObject(self, @selector(someClasses));
}
- (void)setSomeClasses:(NSMutableArray *)someClasses
{
objc_setAssociatedObject(self, @selector(someClasses), someClasses, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
@implementation SomeClass
@end
Реализация
- (void)viewDidLoad
{
[super viewDidLoad];
SomeClass *someClass = [[SomeClass alloc] init];
someClass.someView = someView;
[someView addSomeClass:someClass];
}
Еще немного о связанных объектах из NSHipster ...
http://nshipster.com/associated-objects/
Но вы можете объявить экземпляр SomeClass вместо такого свойства:
@implementation ViewController
{
SomeClass* _someClass;
}
...
- (void)viewDidLoad
{
[super viewDidLoad];
_someClass = [[SomeClass alloc] init];
_someClass.someView = someView;
}
Ваш экземпляр SomeClass
содержит сильную ссылку на someView
, но ничто не содержит ссылки на экземпляр SomeClass
, кроме локальной переменной внутри вашего сообщения viewDidLoad
, поэтому как только при выходе из метода этот экземпляр может быть освобожден. Поскольку это был объект, содержащий единственную ссылку на ваш UIView
, представление также можно освободить.
Единственный вариант - сохранить ссылку на объект SomeClass
в переменной экземпляра (или iVar), как предлагается stosha, или в свойстве. Свойства являются предпочтительным методом, и при автоматическом синтезе они не требуют гораздо больших усилий, чем объявление локальной переменной.
Вы можете объявить свойство внутри файла .m, чтобы оно не было видно другим классам, которые ссылаются на ваш класс ViewController
-
В вашем файле ViewController.m
-
@interface ViewController ()
@property (strong, nonatomic) SomeClass *someClass;
@end
@implementation ViewController
...
(void)viewDidLoad
{
[super viewDidLoad];
self.someClass = [[SomeClass alloc] init];
self.someClass.someView = someView;
}
Похожие вопросы
Новые вопросы
ios
iOS - мобильная операционная система, работающая на Apple iPhone, iPod touch и iPad. Используйте этот тег [ios] для вопросов, связанных с программированием на платформе iOS. Используйте связанные теги [target-c] и [swift] для проблем, характерных для этих языков программирования.