Сбой назначения элемента класса NSStringto - PullRequest
1 голос
/ 20 марта 2019

Я работаю над приложением C ++ и Objective-C ++. Там у меня есть класс C ++, который вызывает класс Objective-C ++. В заголовке c ++ я создаю void * следующим образом:

void *m_self;

Затем в конструкторе я создаю экземпляр target-c ++ следующим образом:

m_self = [[InfoForMac alloc] init];

В деструкторе я делаю это:

[(__bridge id)m_self release];

Класс target-c ++ имеет такой интерфейс:

@interface InfoForMac : NSObject  
@property (nonatomic, copy) NSString* data1;
@property (nonatomic, copy) NSString* data2;
@property (nonatomic, assign) int val;

Метод инициализации:

- (id) init
{
 if ( (self = [super init]) ) {
    self.data1 = @"";
    self.data2 = @"";
    self.val = -1;
 }
 return self;
}

И его деструктор:

-(void)dealloc
{
 [self.data1 release];
 [self.data2 release];
 [super dealloc];
}

И я вызываю методы target-c ++ из C ++, например:

 [(__bridge id)m_self getData1];
 QString dataFromMac = QString::from NSString([(__bridge id)m_self data1]);

И соответствующий метод выглядит следующим образом:

- (void) getData1
{
  NSRunningApplication* activeApp = nil;
  activeApp = [[NSWorkspace sharedWorkspace] frontmostApplication];
  if (activeApp) {
    NSString* activeAppLocalizedName = [activeApp localizedName];
    CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
    if (windowList) {
        NSArray *windows = (__bridge NSArray*)(windowList);
        for (NSDictionary *window in windows) {
            NSString* owner = [window objectForKey:@"kCGWindowOwnerName"];
            if (activeAppLocalizedName != nil &&
                [owner isEqualToString:activeAppLocalizedName]) {
                self.data1 = activeAppLocalizedName;
            }
        }
        CFRelease(windowList);
    }
  }
}

Класс C ++ уничтожен и воссоздан. Проблема в том, что после уничтожения класса, когда я воссоздаю его и вызываю метод getData1, я получаю сбой здесь:

self.data1 = activeAppLocalizedName;

Проверка с помощью трассировки стека отладчика показывает этот вызов, а затем objc_msgSend. Я прочитал, и кажется, что сбой может быть из-за дополнительного выпуска или повреждения.

Может кто-нибудь помочь мне понять, что происходит, пожалуйста?

Заранее спасибо и всего наилучшего

1 Ответ

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

Некоторые вещи кажутся мне странными в коде, который вы даете:

литье по мосту в коде MRC

Почему вы ведете кастинг перед выпуском? Вы должны либо соединить (используя ARC), либо освободить. Но вы, кажется, делаете оба. Может ли быть так, что вы на самом деле не отключили ARC в своем коде и теперь выпускаете объекты, которые ARC все еще считает принадлежащими ему?

Обычно вы выполняете бридж в точке, где вы назначаете указатель ObjC для void*, или когда вы хотите переместить void* обратно в указатель ObjC (т. Е. Приведение мостов всех форм указывает на изменения, сделанные вручную. обработка, чтобы позволить ARC сделать это и обратно).

Приведение к мосту указателя ObjC, поддерживающего свойство ObjC, перед его освобождением не требуется.

Освобождение объектов через их методы доступа

Я не думаю, что это ваша большая проблема (она должна быть функционально эквивалентной), но она все еще кажется странной: обычно кто-то выпускает переменную экземпляра

[_data1 release];

или

[self->_data1 release];

или присваивает NIL и позволяет инициатору делать освобождение

self.data1 = nil;

Вы спрашиваете средство доступа для объекта, а затем отпускаете его. Это должно быть хорошо (это должен быть тот же объект), но это странно, и средство доступа обычно добавляет свой объект в текущий пул автоматического выпуска, поэтому ваш объект может быть освобожден позже, чем вы думали.

...