论坛首页 移动开发技术论坛

NSValue对任何结构体,基本类型,指针的封装

浏览 1399 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2015-08-28  

 

 

任何结构体:

一个NSValue对象是用来存储一个C或者Objective-C数据的简单容器。它可以保存任意类型的数据,比如int,float,char,当然也可以是指pointers, structures, and object ids。NSValue类的目标就是允许以上数据类型的数据结构能够被添加到集合里,例如那些需要其元素是对象的数据结构,如NSArray或者NSSet的实例。需要注意的是NSValue对象一直是不可枚举的。

 

我们可以使用NSValue来辅助我们实现一些简单数据结构的封装。比如我们定义了一个简单的结构体类型

 

typedef struct
{
    int id;   
    unsigned char flag;
}TestStruct;

 

 

 TestStruct test;

 NSValue *value=[NSValue valueWithBytes:&test objCType:@encode(TestStruct)];//对结构体进行封装,,test是基本数据的值,TestStruct是我们要转化的类型

   

 在我们想取出*value 中的数据时,可以使用如下方式:

 TestStruct test2;//声明test2,为了得到test1的值

 [value getValue:&test2];//同类型赋值

 

 

一些结构体的封装:

 

@interface NSValue (NSValueUIGeometryExtensions)

+ (NSValue *)valueWithCGPoint:(CGPoint)point;
+ (NSValue *)valueWithCGVector:(CGVector)vector;
+ (NSValue *)valueWithCGSize:(CGSize)size;
+ (NSValue *)valueWithCGRect:(CGRect)rect;
+ (NSValue *)valueWithCGAffineTransform:(CGAffineTransform)transform;
+ (NSValue *)valueWithUIEdgeInsets:(UIEdgeInsets)insets;
+ (NSValue *)valueWithUIOffset:(UIOffset)insets NS_AVAILABLE_IOS(5_0);

- (CGPoint)CGPointValue;
- (CGVector)CGVectorValue;
- (CGSize)CGSizeValue;
- (CGRect)CGRectValue;
- (CGAffineTransform)CGAffineTransformValue;
- (UIEdgeInsets)UIEdgeInsetsValue;
- (UIOffset)UIOffsetValue NS_AVAILABLE_IOS(5_0);

@end 

 

 

 

基本类型:

int count = 10;

NSValue *value = [NSValue valueWithBytes:&count objCType:@encode(int)]; 

其实基础类型,包括bool,char类型可以有NSValue的子类NSNumber去封装

 

 

 

指针:

@interface NSValue (NSValueExtensionMethods)

+ (NSValue *)valueWithNonretainedObject:(id)anObject;
@property (nonatomic, readonly) id nonretainedObjectValue;

+ (NSValue *)valueWithPointer:(const void *)pointer;
- (void *)pointerValue;

- (BOOL)isEqualToValue:(NSValue *)value;

@end

 

 

+ (NSValue *)valueWithPointer:(const void *)pointer;

- (void *)pointerValue;

保存对象指针

NSObject * baseObj = [[NSObject alloc] init];

NSValue * value = [NSValue valueWithPointer:baseObj];

NSObject *base = [value pointerValue];

 

+ (NSValue *)valueWithNonretainedObject:(id)anObject;

@property (nonatomic, readonly) id nonretainedObjectValue;

NSValue 的valueWithNonretainedObject 和  nonretainedObject 来对弱引用进行封装。

在项目中有某个功能需要用到多个delegate对象,这就需要把delegate放到容器中,但又不想保存强引用导致delegate对象不能被释放。所以希望能在容器中只保存delegate对象的弱引用,就可以用此方法。但是容次必须是弱引用容器,例如:

[NSHashTable weakObjectsHashTable]

[NSPointerArray weakObjectsPointerArray]

[NSPointerArray pointerArrayWithOptions:]

假如使用了NSArray,虽然不会阻止对象的释放,但是对象释放后nonretainedObject 返回的并不是nil。

当然也可以自己实现一个弱引用的封装:

 由于我只是想要一个set,没找到支持弱引用的set容器。所以我就使用第二个方法定义了WeakReferenceWrapper 来对弱引用进行封装。上代码:

==============================================

 @interface WeakReferenceWrapper : NSObject

+(id) wrapNonretainedObject:(id)obj;
-(id) init;
-(id) initWithNonretainedObject:(id)obj;
-(id) get;

-(BOOL) isEqual:(id)object;
-(NSUInteger)hash;

@end

@implementation WeakReferenceWrapper {
    __weak id weakReference;
}

+(id) wrapNonretainedObject:(id)obj {
    return [[WeakReferenceWrapper alloc] initWithNonretainedObject:obj];
}

-(id) init {
    return [self initWithNonretainedObject:nil];
}

-(id) initWithNonretainedObject:(id)obj {
    self = [super init];
    if (self) {
        weakReference = obj;
    }
    return self;
}

-(id) get {
    return weakReference;
}

-(BOOL) isEqual:(id)object {
    if (!object) {
        return NO;
    }
    if (![object isKindOfClass:[self class]]) {
        return NO;
    }
    WeakReferenceWrapper* other = (WeakReferenceWrapper*) object;
    return ([self get] == [other get]);
}

-(NSUInteger)hash {
    if (weakReference) {
        return [weakReference hash];
    }
    return 0;
}
@end
==============================================
测试代码如下:
 @interface Foo: NSObject
-(id) init;
-(void) dealloc;
@end

@implementation Foo
-(id) init {
    self = [super init];
    NSLog(@"init");
    return self;
}
-(void) dealloc {
    NSLog(@"dealloc");
}
@end

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        NSMutableSet* foos = [[NSMutableSet alloc] init];
        Foo* foo1 = [[Foo alloc] init];
        WeakReferenceWrapper* weakFoo1 = [WeakReferenceWrapper wrapNonretainedObject:foo1];
        NSLog(@"%d", [foos containsObject:weakFoo1]);
        [foos addObject:weakFoo1];
        NSLog(@"%d", [foos containsObject:weakFoo1]);
        for (WeakReferenceWrapper* value in foos) {
            NSLog(@"%p", [value get]);
        }
        {
            Foo* foo2 = [[Foo alloc] init];
            [foos addObject:[WeakReferenceWrapper wrapNonretainedObject:foo2]];
            for (WeakReferenceWrapper* value in foos) {
                NSLog(@"%p", [value get]);
            }
        }
        for (WeakReferenceWrapper* value in foos) {
            NSLog(@"%p", [value get]);
        }
    }
    return 0;
} 

 

===========================================================

     一定要注意的是:如果WeakReferenceWrapper 指向的对象被析构了。WeakReferenceWrapper 对象本身不会设置为nil,而是get方法返回nil。这是因为容器类中保存的是WeakReferenceWrapper 强引用,WeakReferenceWrapper 保存的是对象的弱引用。

 

感谢:http://blog.sina.com.cn/s/blog_48d4cf2d0102v1jh.html

http://www.cocoachina.com/industry/20140122/7735.html

 

论坛首页 移动开发技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics