@autoreleasepool при расширении NSData? - PullRequest
0 голосов
/ 04 марта 2019

Я работаю над расширением 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, возвращенный объект получает владение указателем байтов и освобождает его при освобождении.

Но я не уверен, относится ли это к моей ситуации.

Спасибо за любую помощь.

1 Ответ

0 голосов
/ 04 марта 2019

Я не вижу никаких проблем.

Автопреложение только для объектов Objective-C.По сути, это немного задерживает фактический вызов -release, помещая объект в пул авто-релиза, который сбрасывается после каждой итерации основного цикла выполнения, вызывая -release для каждого объекта в пуле.Объекты, возвращаемые из методов, как правило, автоматически высвобождаются, хотя в ARC есть механизм, который часто позволяет избежать накладных расходов фактического пула, выясняя, что значение требуется только вызывающей стороне, и может отслеживать ссылку и просто вызывать -release там.В режиме ARC компилятор выясняет, когда требуется autorelease vs release, и не позволяет вам вызывать эти методы самостоятельно.

В большинстве случаев вам не нужны ваши собственные пулы autorelease, хотя есливы делаете что-то в цикле, где каждая итерация может создавать множество временных объектов, вам может потребоваться autorelease_pool для каждой итерации цикла, чтобы память не создавалась, а очищалась каждый раз, чтобы следующая итерация могла использовать ее повторнообъем памяти.Если вы пишете программу командной строки или какой-либо другой инструмент, который не имеет своей собственной поддержки Objective-C, то да, вам нужен пул автоматического выпуска по крайней мере вокруг точки входа.

Куча памяти C с использованием malloc /free находится вне концепции автоматического выпуска (которая относится только к механизму сохранения / освобождения NSObject).Для каждого malloc () вам нужно в конце концов вызвать free () для этой памяти, когда она больше не нужна, иначе это утечка.Приведенный выше код верен - есть malloc (), а затем при возврате nil вызывается либо free (), либо вызывается метод initWithBytesNoCopy: (это специальный метод, который использует переданные байты в качестве фактического NSDataхранилище, избегая накладных расходов на копию памяти и дальнейшую внутреннюю malloc, а затем вызовет free (), когда сам объект освобожден).

initWithBytesNoCopy: length: просто вызывает -initWithBytesNoCopy: length: freeWhenDone: с параметром YES для freeWhenDone, в основном, согласно его документации.Вы можете вызвать более длинный метод явно, если считаете, что он делает его более читабельным (поскольку он более четко указывает на то, что вы знали о свободном поведении), но он будет работать так же в любом случае.

Метод шифрования NSDataна самом деле не создает никаких объектов, кроме того, который вы возвращаете - весь его код более простой C-код.Так что пул авторелизов ничего бы не помог.Метод шифрования NSString создает несколько временных объектов, поэтому, если объем зашифрованной памяти является значительным, пул автоматического освобождения может помочь, если у вас есть последующая значительная работа (но обязательно иметь сильную ссылку на объект, возвращаемый извнеобъем бассейна).И действительно, ARC, скорее всего, выяснит временную природу большинства из этих объектов и в любом случае более эффективно справится с ними, чем пул автоматического выпуска.

Если вы можете профилировать свой код с помощью Instruments, вы можете увидеть памятьиспользование вашей программы во время ее работы, и это будут только места со значительными всплесками, которые вы могли бы рассмотреть с использованием локального пула автоматического выпуска.

...