任何结构体:
一个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