避免在不向UIViewController添加Property / iVar的情况下释放对象

时间:2014-06-09 08:17:46

标签: ios objective-c dealloc

我有一个自定义类/对象,可以使用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 个答案:

答案 0 :(得分:0)

但你可以声明SomeClass实例而不是像这样的属性:

@implementation ViewController
{
    SomeClass* _someClass;
}

...


- (void)viewDidLoad
{
    [super viewDidLoad];

    _someClass = [[SomeClass alloc] init];
    _someClass.someView = someView;
}

答案 1 :(得分:0)

您的SomeClass实例持有对someView的强引用,但除了SomeClass消息中的局部变量之外,没有任何内容引用viewDidLoad实例,因此,只要方法退出,就可以释放该实例。因为那是持有UIView唯一引用的对象,视图也可以被释放。

您唯一的选择是将实例变量(或iVar)中的SomeClass对象的引用存储为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;
}

答案 2 :(得分:0)

如果你想以与UIGestureRecognizer相同的方式将对象与UIView相关联,那么使用关联对象可以技术,如下所示(但我不确定我是否会提倡这种方法,因为关联对象经常不赞成)...

<强> 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/