Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use weak references to objects in iOS

2025-02-23 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article mainly shows you "how to use weak references to objects in iOS". The content is simple and clear. I hope it can help you solve your doubts. Let me lead you to study and learn "how to use weak references to objects in iOS".

NSObject retainCount

When you create an object in iOS, the reference count for that object is incremented by 1, such as the following example:

NSObject * obj = [NSObject alloc] init]; NSLog (@ "obj retain count:% zd", [obj retainCount])

The output of the above example is 1. Of course, retainCount cannot be used under ARC, only under non-ARC conditions. If you want to run the above example, the corresponding file needs to be set to-fno-objc-arc.

-(NSUInteger) retainCount OBJC_ARC_UNAVAILABLE

As you can see in usr/include/objc/NSObject.h, retainCount is a method defined in the NSObject protocol (@ protocol NSObject), and the NSObject class implements the protocol, as follows:

@ interface NSObject

Therefore, any OC object has a retainCount method. In addition, if you add a view, the view is actually referenced by the container, and its count will be added by 1 to be held by the container. For example, adding an object to the array will increase the reference count of the object by 1 and be held by the array.

NSValue valueWithNonretainedObject

In iOS, NSValue's class method valueWithNonretainedObject maintains weak references to objects.

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

This method is useful if you want to add an object to a Collection but don't want the collection to create a strong reference to it.

It roughly means that the method can not hold a strong reference to an object, in other words, only a weak reference to an object.

Give me a chestnut.

MZDog.h

@ interface MZDog: NSObject@end

MZDog.m

# import "MZDog.h" @ implementation MZDog- (NSString *) description {return [NSString stringWithFormat:@ "MZDog-obj retain count:% zd", [self retainCount]];} @ end

Here MZDog is set to non-ARC, as shown in the figure:

Use MZDog in the test file as follows:

/ / retainCount-> 1MZDog * dog = [MZDog new]; NSLog (@ "dog:% @", dog); / / A pair of dog uses weak references, and the reference count is still 1NSValue * value = [NSValue valueWithNonretainedObject:dog]; NSLog (@ "dog:% @, value:% @", dog, value); / / get the object id obj = value.nonretainedObjectValue;NSLog (@ "obj isKindOfClass MZDog:% I", [obj isKindOfClass: [MZDog class]]) corresponding to value If (obj = = dog) {NSLog (@ "The obj is same dog object.");}

The corresponding console output is as follows:

Dog: MZDog-obj retain count: 1dog: MZDog-obj retain count: 1, value: obj isKindOfClass MZDog: 1The obj is same dog object.

As can be seen from the above example, valueWithNonretainedObject does not have a strong application to the MZDog object dog. Modify the code, for example:

/ / retainCount-> 1MZDog * dog = [MZDog new]; NSLog (@ "dog:% @", dog); / / A pair of dog uses weak references, and the reference count is still 1NSValue * value = [NSValue valueWithNonretainedObject:dog]; NSLog (@ "dog:% @, value:% @", dog, value) / / after being wrapped by NSValue, you can put it in the corresponding collection objects (such as arrays, dictionaries, etc.), so that these collections do not strongly reference dog. NSArray * array = [NSArray arrayWithObjects:value, nil]; / / the reference count of dog is still 1NSLog (@ "dog:% @, array:% @", dog, array)

Corresponding output log:

Dog: MZDog-obj retain count: 1dog: MZDog-obj retain count: 1, value: dog: MZDog-obj retain count: 1, array: (")

Method valueWithNonretainedObject is equivalent to

NSValue * theValue = [NSValue value:&anObject withObjCType:@encode (void *)]

The above example can be rewritten:

/ / retainCount-> 1MZDog * dog = [MZDog new]; NSLog (@ "dog:% @", dog); / / A pair of dog uses weak references, and the reference count is still 1NSValue * value = [NSValue value:&dog withObjCType:@encode (void *)]; NSLog (@ "dog:% @, value:% @", dog, value) / / after being wrapped by NSValue, you can put it in the corresponding collection objects (such as arrays, dictionaries, etc.), so that these collections do not strongly reference dog. NSArray * array = [NSArray arrayWithObjects:value, nil]; / / the reference count of dog is still 1NSLog (@ "dog:% @, array:% @", dog, array)

Output log:

Dog: MZDog-obj retain count: 1dog: MZDog-obj retain count: 1, value: dog: MZDog-obj retain count: 1, array: (")

At this time, the reference count of dog has not increased.

Set classification of self-written weak references

According to the above theory, we can use NSValue to write weakly referenced collection objects, the idea is simple, create a classification of collection classes, and then use NSValue to wrap it. Just look at the sample code below.

NSArray+MZWeak.h

@ interface NSArray (MZWeak)-(id) mz_weak_objectAtIndex: (NSUInteger) index;@end@interface NSMutableArray (MZWeak)-(void) mz_weak_addObject: (id) obj;@end

NSArray+MZWeak.m

# import "NSArray+MZWeak.h" @ implementation NSArray (MZWeak)-(id) mz_weak_objectAtIndex: (NSUInteger) index {NSValue * value = [self objectAtIndex:index]; return value.nonretainedObjectValue;} @ end@implementation NSMutableArray (MZWeak)-(void) mz_weak_addObject: (id) obj {NSValue * value = [NSValue valueWithNonretainedObject:obj]; if (nil! = value) {[self addObject:value];}} @ end

Used in a file, examples are as follows:

/ / retainCount-> 1MZDog * dog = [MZDog new]; NSLog (@ "dog:% @", dog); NSMutableArray * array = [NSMutableArray arrayWithCapacity:1]; / / weak reference [array mz_weak_addObject:dog]; / / the reference count of dog at this time is still 1NSLog (@ "dog:% @", dog)

And so on, for other collection classes NSDictionary, NSSet can be implemented. Of course, there is more than one way to implement it, but here is just an example of an NSValue wrapper object.

Of course, you can also use NSProxy or block to remove strong references to objects. For the method of removing block, you can refer to the open source project HXImage. In addition, NSProxy is used in the open source project YYWeakProxy to remove strong references.

So, in addition to the methods mentioned above, are there any ready-made classes in the system class library? Smart you must have guessed, there must be!

Yes, look down.

NSPointerArray 、 NSMapTable 、 NSHashTable

The collection classes NSArray, NSDictionary, and NSSet, and their corresponding variable versions, can all be used to store OC objects, but all of them are strongly referenced.

From the iOS6.0 version and later versions, the system provides us with NSPointerArray, NSMapTable and NSHashTable corresponding to NSArray, NSDictionary and NSSet, respectively. The biggest difference is that NSPointerArray, NSMapTable and NSHashTable are weak references rather than strong references to objects.

Now most iOS APP or iOS games should be at least above iOS7, so you can make full use of the class libraries provided by these systems.

To save weakly referenced objects using NSPointerArray, you need to create NSPointerArray objects in the following three ways, as follows:

/ / create NSPointerArray objects-NSPointerArray * pointerArray = [NSPointerArray weakObjectsPointerArray]; / / create NSPointerArray objects-NSPointerArray * pointerArray1 = [[NSPointerArray alloc] initWithOptions:NSPointerFunctionsWeakMemory]; / / create NSPointerArray objects-NSPointerArray * Array = [NSPointerArray pointerArrayWithOptions:NSPointerFunctionsWeakMemory]

So let's take MZDog as an example, as follows:

/ / retainCount-> 1MZDog * dog = [MZDog new]; NSLog (@ "dog:% @", dog); / / method 1 for creating NSPointerArray objects / / pay attention to weakObjectsPointerArray instead of strongObjectsPointerArrayNSPointerArray * pointerArray = [NSPointerArray weakObjectsPointerArray]; [pointerArray addPointer: (_ _ bridge void *) (dog)]; / / create NSPointerArray objects: NSPointerArray * pointerArray1 = [[NSPointerArray alloc] initWithOptions:NSPointerFunctionsWeakMemory]; [pointerArray1 addPointer: (_ bridge void *) (dog)] / / three ways to create NSPointerArray objects: NSPointerArray * pointerArray2 = [NSPointerArray pointerArrayWithOptions:NSPointerFunctionsWeakMemory]; [pointerArray2 addPointer: (_ _ bridge void *) (dog)]; / / dog reference count or 1NSLog (@ "dog:% @", dog)

The retainCount of the corresponding output dog object is still 1, and its reference count has not increased.

Examples of NSMapTable and NSHashTable are as follows:

NSMapTable example

/ / retainCount-> 1MZDog * dog = [MZDog new]; NSLog (@ "dog:% @", dog); / / weak application object NSMapTable * map = [NSMapTable weakToWeakObjectsMapTable]; [map setObject:dog forKey:@ "first"]; / / reference count is still 1, unchanged NSLog (@ "dog:% @", dog)

NSHashTable example

/ / retainCount-> 1MZDog * dog = [MZDog new]; NSLog (@ "dog:% @", dog); / / weak application object NSHashTable * hashTable = [NSHashTable weakObjectsHashTable]; [hashTable addObject:dog]; / / reference count is still 1, unchanged NSLog (@ "dog:% @", dog)

NSPointerArray and NULL

The object added in NSMutableArray can not be nil, but NULL can be stored in NSPointerArray (nil is converted to C pointer to NULL), and it can also be used to store weak objects. After an object of type weak is released, the corresponding position of NSPointerArray automatically becomes NULL, and using the count attribute, the NULL element is counted, that is, NULL is one of it. The following example can prove it as follows:

MZDog * dog = nil;NSPointerArray * pointerArray = [NSPointerArray weakObjectsPointerArray]; void * cobj = (_ _ bridge void *) (dog); NSLog (@ "obj:% @", cobj); / / NULL [pointerArray addPointer:cobj]; / / although NULL is stored, count is still 1NSLog (@ "pointerArray count:% zd", [pointerArray count]); NSArray * array = [pointerArray allObjects]; NSLog (@ "pointerArray allObjects:% @", array)

It is common to delete the NULL element in NSPointerArray as follows:

[pointerArray addPointer:NULL]; [pointerArray compact]

Note here that (_ _ bridge void *) is used to convert OC objects to C pointers, rather than (_ _ bridge_retained void *) or CFBridgingRetain, which make strong references to dog objects. The following is an example:

/ / retainCount-> 1MZDog * dog = [MZDog new]; NSPointerArray * pointerArray = [NSPointerArray weakObjectsPointerArray]; / / here the retain dog object will be added to its reference count, and the retainCount will be 2 [pointerArray addPointer: (_ _ bridge_retained void *) dog]; / / the retain dog object will be added here, and its reference count will be 3 [pointerArray addPointer:CFBridgingRetain (dog)]; / / the retainCount at this time will be 3NSLog (@ "dog:% @", dog)

The above is all the content of the article "how to use weak references to objects in iOS". Thank you for reading! I believe we all have a certain understanding, hope to share the content to help you, if you want to learn more knowledge, welcome to follow the industry information channel!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report