Проблема в Obj-c для доступа к ранее определенным данным C Struct - PullRequest
1 голос
/ 13 апреля 2011

Я новичок в objc / Cocoa и никогда раньше не использовал C.

У меня проблема с получением ранее определенных данных структуры C ...
Вот мой код:

AppController.h

#import <Cocoa/Cocoa.h>

@interface AppController : NSObject {
    AuthorizationRef authRef;
    AuthorizationRights authRights;
    AuthorizationFlags authFlags;
}
- (IBAction)toggleAuthentification:(id)sender;
@end

AppController.m

#import "AppController.h"

@implementation AppController
    - (id)init {
        if (![super init])
            return nil;

        AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authRef);
        AuthorizationItem rightItems[1] = {{"com.myname.myapp.adminRights", 0, NULL, 0}};
        authRights.count = 1;
        authRights.items = rightItems;
        authFlags = kAuthorizationFlagDefaults | kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagPreAuthorize;

        return self;
    }

    - (IBAction)toggleAuthentification:(id)sender {
        NSLog(@"%d", AuthorizationCopyRights(authRef, &authRights, kAuthorizationEmptyEnvironment, authFlags ^ kAuthorizationFlagInteractionAllowed, NULL));
    }
@end

Когда я нажимаю на кнопку в моем приложении, которая вызывает toggleAuthentification:, я получаю код ошибки -60008 (errAuthorizationInternal).
В отладчике я вижу authRights.count = 1, это правильно, но authRights.items никак не соответствует данным, определенным в init.

Я пытаюсь по-разному, но я неНе могу найти решение.

Пожалуйста, любой может объяснить, почему это не работает, как если бы я работал, и как решить мою проблему.

Bil

1 Ответ

2 голосов
/ 13 апреля 2011

Проблема в вашем коде - управление памятью.

Когда вы создаете rightItems[], массив из AuthorizationItem элементов, он создается в стеке, поскольку rightItems[] является автоматической (локальной) переменной. Это означает, что память, используемая массивом, освобождается в конце метода. Поскольку вы присваиваете rightItems[] для authRights.items, authRights.items указывает на поддельный адрес памяти после завершения -init. Любая дальнейшая ссылка на authRights.items имеет неопределенное поведение и может привести к ошибке в вашей программе.

Что вам нужно сделать, это создать массив в куче, чтобы он не был освобожден после завершения -init. Вы можете сделать это через malloc(). Например:

const size_t numberOfRightItems = 1;
AuthorizationItem *rightItems = malloc(sizeof(AuthorizationItem)
    * numberOfRightItems);
rightItems[0] = (AuthorizationItem){"com.myname.myapp.adminRights", 0, NULL, 0};

authRights.items = rightItems;

Теоретически вы несете ответственность за выпуск authRights.items, когда он больше не нужен, поскольку вы выделили ему память в куче. Следовательно, в вашем -dealloc методе:

- (void)dealloc {
    free(authRights.items);
    super[dealloc];
}

Я сказал в теории , потому что вы сохраняете права авторизации в вашем контроллере приложений. Поскольку контроллер приложения живет на протяжении всего жизненного цикла приложения, технически оно не получит -release или -dealloc. Однако это хорошая практика и потенциально полезно, если вы реорганизуете свое приложение, и этот код оказывается в классе, чьи объекты не обязательно являются живыми, пока приложение не завершится.

Еще одно примечание: вы должны присвоить возвращаемое значение от [super init] до self в вашем -init методе. Это также хорошая практика, поскольку вполне возможно, что [super init] возвращает объект, отличный от текущего self.

...