We often use Category categories in development to extend functionality to existing classes. Although inheritance can also add new methods to existing classes and has the advantage of adding attributes compared with categories, inheritance is a heavyweight operation after all, and adding unnecessary inheritance undoubtedly increases the complexity of code.

Unfortunately, the OC class does not support adding attributes directly. If we wrote Property properties directly into the class declaration, we would only be able to generate set and GET method declarations, not member variables, and calling these attributes directly would cause a crash.

To add attributes to a class, we also need to use the Runtime’s Associated Objects feature, which allows us to associate arbitrary attributes to an object at Runtime. Here are three related methods:

usr/include/runtime.h

/** * Sets an associated value for a given object using a given key and association policy. * * @param object The source  object for the association. * @param key The key for the association. * @param value The value to associate with the key key for object. Pass nil to clear an existing association. * @param policy The policy for the association. For possible values, See "Associative Object Behaviors." * * @see objc_setAssociatedObject * @see objc_removeAssociatedObjects */ OBJC_EXPORT  void objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key, id _Nullable value, Objc_AssociationPolicy Policy) OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0); /** * Returns the value associated with a given object for a given key. * * @param object The source object for the association. * @param key The key for the association. * * @return The value associated with the key \e key for \e object. * * @see objc_setAssociatedObject */ OBJC_EXPORT id _Nullable objc_getAssociatedObject(id _Nonnull object, Const void * _Nonnull key) OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0); /** * Removes all associations for a given object. * * @param object An object that maintains associated objects. * * Pristine state @Note The main purpose of this function is to make it easy to return an object * to a "pristine state "You should not use this function for general removal of * associations from objects, since it also removes associations that other clients * may have added to the object. Typically you should use \c objc_setAssociatedObject * with a nil value to clear an association. * * @see objc_setAssociatedObject * @see Objc_getAssociatedObject */ OBJC_EXPORT void objc_removeAssociatedObjects(id _Nonnull Object) OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);Copy the code

Note that the key corresponds to the association property one by one, and we must ensure that it is globally unique, usually using @ Selector (methodName) as the key.

Here is the sample code: Add a class for UIImage: UIImage+Tools and set it to urlString(image web link property)

@interface UIImage (Tool)

@property (nonatomic, copy) NSString *urlString;

- (void)clearAssociatedObject;

@end
Copy the code
//
//  UIImage+Tool.m
//  LoadInitializeDemo
//
//  Created by Ternence on 2021/5/12.
//

#import "UIImage+Tool.h"
#import <objc/runtime.h>


@implementation UIImage (Tool)

- (void)setUrlString:(NSString *)urlString {
    objc_setAssociatedObject(self, @selector(urlString), urlString, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (NSString *)urlString {
    return objc_getAssociatedObject(self, @selector(urlString));
}

- (void)clearAssociatedObject {
    objc_removeAssociatedObjects(self);
}

@end

Copy the code

Test call:

    UIImage *image = [[UIImage alloc] init];
    image.urlString = @"http://www.baidu.com";
    NSLog(@"=====urlString: %@", image.urlString);
    [image clearAssociatedObject];
    NSLog(@"=======urlString: %@",image.urlString);
Copy the code

Printout:

The 2021-05-12 16:26:02. 880219 + 0800 LoadInitializeDemo [98906-3244158] = = = = = urlString: http://www.baidu.com 2021-05-12 16:26:02.880376+0800 LoadInitializeDemo[98906:3244158] =======urlString: (null)Copy the code