https://github.com/YouXianMing

ARC中用代码检测一个对象有没有释放掉

ARC中用代码检测一个对象有没有释放掉

你试过在ARC中用代码检测对象有没有释放掉这种事情呢?即使你想过肯定也不知道怎么去实现,因为,这里会用到一个你基本上没怎么接触过的类:NSHashTable.

我们以检测导航控制器push出一个新的控制器为例,以下是效果:

所有你需要的源码:

ObjectDetector.h + ObjectDetector.m

//
//  ObjectDetector.h
//  ARCBlock
//
//  Copyright (c) 2014年 Y.X. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface ObjectDetector : NSObject

+ (void)startWatch;
+ (void)addToWatch:(id)object;
+ (NSArray *)allObjects;

@end
//
//  ObjectDetector.m
//  ARCBlock
//
//  Copyright (c) 2014年 Y.X. All rights reserved.
//

#import "ObjectDetector.h"

#ifndef GCDExecOnce
#define GCDExecOnce(block) \
{ \
static dispatch_once_t predicate = 0; \
dispatch_once(&predicate, block); \
}
#endif

static NSHashTable        *_table          = nil;
static dispatch_source_t   _dispatchSource = nil;
static dispatch_queue_t    _dispatchQueue  = nil;

@implementation ObjectDetector

+ (void)initialize
{
    if (self == [ObjectDetector class])
    {
        _table          = [NSHashTable weakObjectsHashTable];
        _dispatchQueue  = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT);
        _dispatchSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _dispatchQueue);
        
        dispatch_source_set_timer(_dispatchSource,
                                  dispatch_time(DISPATCH_TIME_NOW, 0),
                                  NSEC_PER_SEC,
                                  0);
        
        dispatch_source_set_event_handler(_dispatchSource, ^{
            NSLog(@"\n[==ObjectDetector LIST==]\n%@", _table);
        });
    }
}

+ (void)startWatch
{
    GCDExecOnce(^{
        dispatch_resume(_dispatchSource);
    });
}

+ (void)addToWatch:(id)object
{
    if (object == nil)
    {
        NSLog(@"object should not be nil.");
        return;
    }
    
    if ([_table containsObject:object] == NO)
    {
        [_table addObject:object];
    }
}

+ (NSArray *)allObjects
{
    return [_table allObjects];
}

@end

****-Prefix.pch

//
//  Prefix header
//
//  The contents of this file are implicitly included at the beginning of every source file.
//

#import <Availability.h>

#ifndef __IPHONE_3_0
#warning "This project uses features only available in iOS SDK 3.0 and later."
#endif

#ifdef __OBJC__
    #import <UIKit/UIKit.h>
    #import <Foundation/Foundation.h>

    #import "ObjectDetector.h"
#endif

AppDelegate.h

//
//  AppDelegate.m
//  NSHashTable
//
//  Copyright (c) 2014年 Y.X. All rights reserved.
//

#import "AppDelegate.h"
#import "RootViewController.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    UINavigationController *NC = \
        [[UINavigationController alloc] initWithRootViewController:[RootViewController new]];
    
    self.window.rootViewController = NC;
    
    // 开始检测
    [ObjectDetector startWatch];
    
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    return YES;
}

@end

RootViewController.m

//
//  RootViewController.m
//  NSHashTable
//
//  Copyright (c) 2014年 Y.X. All rights reserved.
//

#import "RootViewController.h"
#import "SecondViewController.h"

@interface RootViewController ()

@end

@implementation RootViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.title               = @"任重而道远";
    UIButton *button         = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 120, 30)];
    button.center            = self.view.center;
    button.layer.borderWidth = 1.f;
    button.titleLabel.font   = [UIFont fontWithName:@"HelveticaNeue-UltraLight"
                                               size:20.f];
    [button setTitle:@"YouXianMing" forState:UIControlStateNormal];
    [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [button addTarget:self
               action:@selector(buttonEvent:)
     forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];
}

- (void)buttonEvent:(UIButton *)button
{
    [self.navigationController pushViewController:[SecondViewController new]
                                         animated:YES];
}

@end

SecondViewController.m

//
//  SecondViewController.m
//  NSHashTable
//
//  Copyright (c) 2014年 Y.X. All rights reserved.
//

#import "SecondViewController.h"

@interface SecondViewController ()

@end

@implementation SecondViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor whiteColor];
    self.title                = @"天道酬勤";
    
    // 添加检测对象
    [ObjectDetector addToWatch:self];
}

@end

核心代码详解:

核心代码包括了用单例创建的GCD定时器以及维护一个弱引用集合

然后开启打印检测:

然后添加被检测对象:

大概就酱紫,是不是很容易呢-_-!,不过我当初想到这个点子可是花了挺长时间的,至于NSHashTable怎么使用,请君自行百度,很容易理解的.

posted @ 2014-07-24 09:12  YouXianMing  阅读(773)  评论(0编辑  收藏  举报