• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: ivar access during -finalize
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: ivar access during -finalize


  • Subject: Re: ivar access during -finalize
  • From: "email@hidden" <email@hidden>
  • Date: Fri, 09 Mar 2012 23:15:36 +0000

>
> On 8 Mar 2012, at 16:58, Quincey Morris wrote:
>
>>
>>> A more robust solution is a probably a separate -dispose method.
>>
>> Yes, though knowing when to call it can be a puzzle in itself, if there are multiple references to the object. In general, you'll probably need to invent a reference counting mechanism to keep track of when it's OK for your dispose method to actually dispose of things. That sounds ironic in a GC environment, but there's nothing wrong with reference counting when you need to keep count. :)
>

It turns out that chasing my objects around trying to figure out when to safely dispose of their object resources is indeed a puzzle.
I have implemented the following category to provide a reference counting mechanism for disposable resources.
Using a category makes it easy to add this functionality to an existing class hierarchy.

Some brief commentary and the code repo is at http://github.com/mugginsoft/MGSDisposable

Regards

Jonathan Mitchell
Mugginsoft LLP

#import <Foundation/Foundation.h>

@interface NSObject (MGSDisposable)

- (void)mgsMakeDisposable;
- (BOOL)isMgsDisposable;
- (NSUInteger)mgsDisposalCount;
- (BOOL)isMgsDisposed;
- (void)mgsRetainDisposable;
- (void)mgsReleaseDisposable;
- (void)mgsDispose;
- (BOOL)isMgsDisposedWithLogIfTrue;
- (void)mgsAssociateValue:(id)value withKey:(void *)key;
- (void)mgsWeaklyAssociateValue:(id)value withKey:(void *)key;
- (id)mgsAssociatedValueForKey:(void *)key;
- (void)mgsLogSelector:(SEL)sel;
@end

#import "NSObject+MGSDisposable.h"
#import <objc/runtime.h>

// enable logging
#define MGS_DISPOSAL_LOG

// disable logging
// comment the line below to enable logging
#undef MGS_DISPOSAL_LOG

static char mgsDisposableKey;
NSString * const MGSAllowDisposalKey = @"MGSAllowDisposal";
NSString * const MGSAllowDisposaValue = @"Yes";

@implementation NSObject (MGSDisposable)

/*

 - mgsMakeDisposable

 */
- (void)mgsMakeDisposable
{

#ifdef MGS_DISPOSAL_LOG
    [self mgsLogSelector:_cmd];
#endif

    // check if already disposable
    if ([self isMgsDisposable]) {
        return;
    }

    // assign an initial reference count of 1
    NSNumber *refCount = [NSNumber numberWithUnsignedInteger:1];
    [self mgsAssociateValue:refCount withKey:&mgsDisposableKey];
}

/*

 - isMgsDisposable

 */
- (BOOL)isMgsDisposable
{
    return ([self mgsDisposalCount] == NSUIntegerMax ? NO : YES);
}

/*

 - mgsDisposalCount

 */
- (NSUInteger)mgsDisposalCount
{
    NSNumber *refCount = [self mgsAssociatedValueForKey:&mgsDisposableKey];
    if (!refCount) {
        return NSUIntegerMax;
    }

    return [refCount unsignedIntegerValue];
}

/*

 - isMgsDisposed

 */
- (BOOL)isMgsDisposed
{
    NSUInteger refCount = [self mgsDisposalCount];
    return (refCount == 0 ? YES : NO);
}

/*

 - mgsRetainDisposable

 */
- (void)mgsRetainDisposable
{

#ifdef MGS_DISPOSAL_LOG
    [self mgsLogSelector:_cmd];
#endif

    if (![self isMgsDisposable]) return;
    if ([self isMgsDisposed]) return;

    NSUInteger refCount = [self mgsDisposalCount];
    if (refCount == NSUIntegerMax) {
        return;
    }

    [self mgsAssociateValue:[NSNumber numberWithUnsignedInteger:++refCount] withKey:&mgsDisposableKey];
}

/*

 - mgsReleaseDisposable

 */
- (void)mgsReleaseDisposable
{

#ifdef MGS_DISPOSAL_LOG
    [self mgsLogSelector:_cmd];
#endif

    if (![self isMgsDisposable]) return;
    if ([self isMgsDisposed]) return;

    NSUInteger refCount = [self mgsDisposalCount];
    if (refCount == NSUIntegerMax) {
        return;
    }

    // dispose when reference count == 1
    if (refCount == 1) {
        [self mgsAssociateValue:MGSAllowDisposaValue withKey:MGSAllowDisposalKey];
        [self mgsDispose];
    } else {
        [self mgsAssociateValue:[NSNumber numberWithUnsignedInteger:--refCount] withKey:&mgsDisposableKey];
    }
}

/*

 - mgsDispose

 */
- (void)mgsDispose
{

#ifdef MGS_DISPOSAL_LOG
    [self mgsLogSelector:_cmd];
#endif

    // we must be disposable
    if (![self isMgsDisposable]) return;

    // log and quit if already disposed
    if ([self isMgsDisposedWithLogIfTrue]) return;

    // disposal is only valid when the allow disposal key is found
    if (![self mgsAssociatedValueForKey:MGSAllowDisposalKey]) {
        NSLog(@"Disposal is not valid at this time.");
        return;
    }

    // mark this object as disposed
    [self mgsAssociateValue:[NSNumber numberWithUnsignedInteger:0] withKey:&mgsDisposableKey];

    // remove the allow disposal key
    [self mgsAssociateValue:nil withKey:MGSAllowDisposalKey];
}

/*

 - isMgsDisposedWithLogIfTrue

 */
- (BOOL)isMgsDisposedWithLogIfTrue
{
    if (![self isMgsDisposable]) return NO;

    BOOL disposed = [self isMgsDisposed];
    if (disposed) {
        NSLog(@"mgsDispose already called.");
    }

    return disposed;
}

/*

 - mgsAssociateValue

 */
- (void)mgsAssociateValue:(id)value withKey:(void *)key
{
	objc_setAssociatedObject(self, key, value, OBJC_ASSOCIATION_RETAIN);
}

/*

 - mgsWeaklyAssociateValue

 */
- (void)mgsWeaklyAssociateValue:(id)value withKey:(void *)key
{
	objc_setAssociatedObject(self, key, value, OBJC_ASSOCIATION_ASSIGN);
}

/*

 - mgsAssociatedValueForKey

 */
- (id)mgsAssociatedValueForKey:(void *)key
{
	return objc_getAssociatedObject(self, key);
}

/*

 - mgsLogSelector:

 */
- (void)mgsLogSelector:(SEL)sel
{
     NSLog(@"%@ received %@.", self, NSStringFromSelector(sel));
}

@end


_______________________________________________

Cocoa-dev mailing list (email@hidden)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:

This email sent to email@hidden

  • Follow-Ups:
    • Re: ivar access during -finalize
      • From: Eric Wing <email@hidden>
References: 
 >ivar access during -finalize (From: "email@hidden" <email@hidden>)
 >Re: ivar access during -finalize (From: Quincey Morris <email@hidden>)
 >Re: ivar access during -finalize (From: "email@hidden" <email@hidden>)

  • Prev by Date: Can't log in to Developer Centre
  • Next by Date: Re: Releasing WSMethodInvocationInvoke()
  • Previous by thread: Re: ivar access during -finalize
  • Next by thread: Re: ivar access during -finalize
  • Index(es):
    • Date
    • Thread