background

The text is derived from a comment in a piece of source code in the read Runtime. There is a special logic for calculating the size of memory required by an object. If the object needs less than 16 bytes of memory, it will still allocate 16 bytes. The CF layer requires all objects to be at least 16 bytes long.

size_t instanceSize(size_t extraBytes) const {
    if (fastpath(cache.hasFastInstanceSize(extraBytes))) {
        return cache.fastInstanceSize(extraBytes);
    }

    size_t size = alignedInstanceSize() + extraBytes;
    // CF requires all objects be at least 16 bytes.
    if (size < 16) size = 16;
    return size;
}
Copy the code

CF, the CoreFoundation layer, is the API of the c language and can be bridged with the Foundation framework.

The comment here reminds us that this processing has to do with bridging between the two layers.

The CF layer requires at least 16 bytes

The clue above says that CF requires at least 16 bytes, so we can take a look at the creation of a CF object. Many CF objects are found to allocate memory via the _CFRuntimeCreateInstance function. In the header file for this function declaration, follow the comment to find the following sentence:

A CFRuntimeBase structure is initialized at the beginning of the returned instance.

Every instance starts with a CFRuntimeBase structure. Search for a specific definition of this structure:

/* All CF "instances" start with this structure. Never refer to * these fields directly -- they are for CF's use and may  be added * to or removed or change format without warning. Binary * compatibility for uses of this struct is not guaranteed from * release to release. */
typedef struct __CFRuntimeBase {
    uintptr_t _cfisa;   // The pointer is 8 bytes for 64-bit systems
    uint8_t _cfinfo[4];  // 4 bytes
#if __LP64__
    uint32_t _rc;       // On 64-bit systems, the additional 4 bytes are useless to align with the pointer length
#endif
} CFRuntimeBase;
Copy the code

In a 64-bit system, CFRuntimeBase occupies exactly 16 bytes. Each CF object starts with a CFRuntimeBase structure. CFRuntimeBase can be considered as the base class of all CF layer objects. Base classes all need 16 bytes, so objects at the CF layer need at least 16 bytes.

why

After bridging the OC object to a CF object, many operations on the CF object are forcefully converted to CFRuntimeBase. For example, the current reference count of the object can be obtained by using the CFGetRetainCount function. In these operations, The _cfinfo or _rc field of CFRuntimeBase is accessed. If the object allocated by OC layer is less than 16 bytes, in some extreme cases, invalid memory is accessed and a segment error is raised.

Memory management in Bridges

The bridge keyword is

The title use
__bridge It could be OC to CF, or CF to OC
__bridge_retained OC to CF
__bridge_transfer CF to OC

__bridge can be used in both directions, and the other two will be used in the opposite direction.

OC is for memory management in the ARC environment

The __bridge semantics does not add any additional operations to the ARC management semantics. That is, obj holds the object. If the object is obtained by methods starting with new/copy/init/alloc, the object is directly held. If the object is obtained by other methods, the retain message is sent. After going out of scope, a release message is sent.

Using __bridge from OC to CF, obj gets the object via new, the reference count is 1, and out of scope the release reference count is called -1.

NSObject *obj = [NSObject new];
CFTypeRef ref = (__bridge CFTypeRef)(obj);
Copy the code

Using __bridge from CF to OC, OBj holds the object by other methods, sends a retain message to the object, ends the scope, and sends a release message.

NSObject *obj = (__bridge NSObject *)(ref);
Copy the code

The remaining two complement the semantics of __bridge and handle special cases that are slightly different from the normal __bridge case.

Retained from OC to CF using __bridge_retained (CFBridgingRetain), the OC object will be retained and the reference count will be increased by 1, so that the CF ref will retain the object. If the REF does not use the object, the CF will retain the object. The object is released by calling the CFRelease operation. Retained operations will be retained, but ARC can’t call release manually, so it’s still necessary to call CFRelease in the CF layer to balance the reference count.

NSObject *obj = [NSObject new];
CFTypeRef ref = (__bridge_retained CFTypeRef)(obj);
Copy the code

Use __bridge_transfer to go from CF to OC(you can also use CFBridgingRelease). During the conversion, OBj holds the object, but does not retain it. Out of scope, a release message is sent to OBj. Obj holds objects that are not acquired by increasing the reference count. Instead, they are transferred from the CF layer. When they are out of scope, ARC directly releases them by calling release.

In BOTH CFBridgingRetain and CFBridgingRelease, the semantics of retain and release are for the object before the transformation.

CFBridgingRetain converts an OC object to a CF object and retains the OC object one more time to increase the reference count.

CFBridgingRelease converts a CF object into an OC object, which is equivalent to doing a CFRealse operation on an object in the CF layer. Although the CFRealse function is not called to actually release from assembly, the compiler’s operation is to call retain when the OC object is held by the OC pointer, and the release method is called to count the reference to -1 when the OC pointer goes out of scope, which also maintains the reference count balance. The reference count held by the CF layer is transferred to the OC pointer. The goal is to save one CFRealse call and one RETAIN operation for OC.

Welcome everyone to correct and add.