NSStringto class member assignation crashes

72 views Asked by At

I am working on C++ and objective-c++ application. There I have C++ class which calls Objective-c++ class. In c++ header I am creating void* like this:

void *m_self;

Then in constructor I instantiate objective-c++ like this:

m_self = [[InfoForMac alloc] init];

In destructor I do this:

[(__bridge id)m_self release];

The objective-c++ class has this interface:

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

Its init method:

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

And its destructor:

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

And I am calling objective-c++ methods from C++ like this:

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

And the relevant method is as follows:

- (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++ class is destroyed and recreated. The problem is that after destroying the class when I recreate it and call getData1 method I get a crash here:

self.data1 = activeAppLocalizedName;

Checking with debugger stacktrace shows that call and then objc_msgSend. I have read and it seems crash can be due to extra release or corruption.

Could someone help me to understand what is going on please ?

Thanks in advance and regards

1

There are 1 answers

0
uliwitness On

Several things strike me as odd about the code you give:

Bridge-casting in MRC Code

Why are you bridge-casting before the release? You should be either bridging (using ARC) or releasing. But you seem to be doing both. Could it be that you haven't actually turned off ARC in your code, and are now releasing objects that ARC still thinks it owns?

Usually, you bridge-cast at the point where you assign an ObjC pointer to a void*, or when you want to move a void* back into an ObjC pointer (i.e. bridge casts of all forms indicate changes from manual handling to letting ARC do it and back).

Bridge-casting the ObjC pointer backing an ObjC property before releasing it should not be necessary.

Releasing Objects through their Accessors

I don't think this is your big issue (it should be functionally equivalent), but it still seems weird: Usually, one either releases the instance variable

[_data1 release];

or

[self->_data1 release];

or assigns NIL and lets the accessor do the releasing

self.data1 = nil;

You're asking the accessor for an object, then release that. It should be fine (it should be the same object), but it's odd, and the accessor usually adds its object to the current autorelease pool, so your object may be released later than you thought.