扩展NSData时@autoreleasepool?

问题描述 投票:0回答:1

我正在研究用密钥加密数据的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为false(意味着它无法加密)则调用。我还注意到方法dataWithBytesNoCopy有一个参数freeWhenDone,其中:

  • 如果为YES,则返回的对象获取字节指针的所有权,并在取消分配时释放它。

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

感谢您的帮助。

ios objective-c automatic-ref-counting
1个回答
0
投票

我没有看到任何问题。

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

大多数情况下,您不需要自己的自动释放池,但如果您在循环中执行某些操作,每次迭代都可以创建大量临时对象,则可能需要为每个循环迭代使用autorelease_pool,以便不会构建内存每次都要清理,所以下一次迭代可以重新使用那个内存。如果您正在编写命令行程序或其他没有自己的Objective-C支持的工具,那么是的,您至少需要在入口点周围自动释放池。

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

initWithBytesNoCopy:length:只调用-initWithBytesNoCopy:length:freeWhenDone:freeWhenDone的YES参数,基本上是根据其文档。你可以明确地调用更长的方法,如果你认为它使它更具可读性(因为它更清楚地表明你知道自由行为),但它将以相同的方式工作。

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

如果您可以使用Instruments对代码进行概要分析,则可以在程序运行时查看程序的内存使用情况,并且只会出现使用本地自动释放池时会考虑的高峰值的地方。

© www.soinside.com 2019 - 2024. All rights reserved.