@autoreleasepool 扩展 NSData 时?

@autoreleasepool when extending NSData?

我正在开发 NSData 使用密钥加密数据的扩展程序,如下所示。我不太了解 Objective-C,但想将它用于此 Cordova 插件,而不是需要另一个插件来桥接 Swift 个文件。

我想知道我是否需要做任何工作来确保我的方法中的所有清理工作都在进行,以便每次调用此方法时都不会发生泄漏。

扩展 NS 对象时,是否需要将其方法包装在 @autoreleasepool {} 中?

这是加密数据的方法(NSData+AES256Encrypt.m):

- (NSData *)AES256EncryptWithKey:(NSString *)key {
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
    char keyPtr[kCCKeySizeAES256 + 1]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeros for padding

    // Get key data
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    NSUInteger dataLength = [self length];

    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128,
                                          kCCOptionPKCS7Padding, keyPtr,
                                          kCCKeySizeAES256, NULL, [self bytes],
                                          dataLength, buffer, bufferSize, &numBytesEncrypted);
    if(cryptStatus == kCCSuccess) {
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }
    free(buffer);
    return nil;
}

NSString+AES256Encrypt.m结合使用:

- (NSString *)AES256EncryptWithKey:(NSString *)key {
    NSData *plainData = [self dataUsingEncoding:NSUTF8StringEncoding];
    NSData *encryptedData = [plainData AES256EncryptWithKey:key];
    NSString *encryptedString = [encryptedData base64Encoding];
    return encryptedString;
}

与我有关的行是 free(buffer) 在上面发布的第一个方法中使用,如果 cryptStatus 为假(意味着加密失败)则调用。我还注意到方法 dataWithBytesNoCopy 有一个参数 freeWhenDone 其中:

但我不确定它是否适用于我的情况。

感谢所有帮助。

我没有发现任何问题。

自动释放仅适用于 Objective-C 个对象。它基本上通过将对象放入自动释放池来稍微延迟实际的 -release 调用,自动释放池在主 运行 循环的每次迭代后刷新,对池中的每个对象调用 -release。从方法返回的对象通常是自动释放的,尽管 ARC 有一种机制通常可以通过确定该值只被调用者需要来避免实际池的开销,并且可以跟踪引用并在那里调用 -release。在 ARC 模式下,编译器会为您计算出何时需要 autorelease 与 release,并且不会让您自己调用这些方法。

大多数时候,你不需要自己的自动释放池,但如果你在循环中做某事,每次迭代都可以创建大量临时对象,你可能需要一个 autorelease_pool循环迭代,这样内存就不会堆积起来,而是每次都被清理干净,这样下一次迭代就可以重新使用该内存。如果您正在编写一个命令行程序或其他一些没有自己的 Objective-C 支持的工具,那么是的,您至少需要一个围绕入口点的自动释放池。

使用 malloc/free 的 C 堆内存在自动释放概念之外(仅适用于 NSObject 的 retain/release 机制)。对于每个 malloc(),一旦不再需要该内存,您最终需要在该内存上调用 free(),否则就是泄漏。上面的代码是正确的——有一个 malloc(),然后在返回 nil 时调用 free(),或者调用 initWithBytesNoCopy: 方法(这是一个特殊的方法,它使用传入的字节作为实际的 NSData存储,避免内存复制和进一步内部 malloc 的开销,然后在对象本身被释放时调用 free())。

initWithBytesNoCopy:length: 只是根据其文档调用 -initWithBytesNoCopy:length:freeWhenDone: 并为 freeWhenDone 设置一个 YES 参数。如果您认为更长的方法使它更具可读性(因为它确实更清楚地表明您知道自由行为),您可以显式调用更长的方法,但无论哪种方式,它的工作方式都是一样的。

NSData 加密方法实际上不会创建除您要返回的对象之外的任何对象 -- 它的所有代码都是更直接的 C 代码。所以自动释放池不会有任何帮助。 NSString 加密方法确实创建了一些临时对象,所以如果被加密的内存量很大,如果你有后续的重要工作,围绕它的自动释放池可能会有所帮助(但一定要对外部返回的对象有一个强引用池范围)。实际上,ARC 很可能会弄清楚大多数这些对象的临时性质,并且无论如何都比自动释放池更有效地处理它们。

如果您可以使用 Instruments 分析您的代码,您可以看到程序的内存使用情况,因为它 运行s,并且只有在有显着峰值的地方您才会考虑使用本地自动释放池.