autoreleasepool still gives me a memory leak

So I have this program that displays events on the window using NSWindow and a NSTextField. Basically it tracks the mouse position and the keyboard state.

I created a simple class named MyEventWindow:

//
//  MyEventWindow.h
//  AppTest

#ifndef MyEventWindow_h
#define MyEventWindow_h

@interface MyEventWindow : NSWindow
{
	
}

@property(nonatomic, strong) NSTextField* label;
@property(nonatomic, strong) NSString* labelText;

- (BOOL)windowShouldClose:(id)sender;
- (instancetype) init;
- (void) setLabelText:(NSString *)labelText;


@end

@implementation MyEventWindow

-(instancetype) init
{

	
	self = [super initWithContentRect:NSMakeRect(100, 100, 300, 300)
							styleMask:(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable)
							  backing:NSBackingStoreBuffered
								defer:NO];
	if( !self )
	{
		return nil;
	}
	
	[self setTitle: @"Event tracker"];
	[self setIsVisible: YES];
		
	_label = [[NSTextField alloc] initWithFrame:NSMakeRect(5, 100, 290, 100)];
	[_label setBezeled: NO];
	[_label setDrawsBackground: NO];
	[_label setEditable: NO];
	[_label setSelectable: YES];


	NSFont *currentFont = [_label font];


	NSFont *resizedFont = [NSFont fontWithName:[currentFont fontName] size:18];

	
	NSFont *boldFont = [[NSFontManager sharedFontManager] convertFont:resizedFont toHaveTrait:NSFontBoldTrait];

	// convert the bold font to have the italic trait
	NSFont *boldItalicFont = [[NSFontManager sharedFontManager] convertFont:boldFont toHaveTrait:NSFontItalicTrait];

	
	[_label setFont:boldItalicFont];
	
	[_label setTextColor:[NSColor colorWithSRGBRed:0.0 green:0.5 blue:0.0 alpha:1.0]];
	
	// attach label to the damn window
	[[self contentView] addSubview: _label];

	return self;
}

-(BOOL)windowShouldClose:(id)sender
{
	return YES;
}

-(void) setLabelText:(NSString *)newText
{
	[_label setStringValue: newText];
}


@end

#endif /* MyEventWindow_h */

Then in the main file I try to handle event loop manually:

//
//  main.m

#import <Cocoa/Cocoa.h>
#import "MyEventWindow.h"

NSString* NSEventTypeToNSString(NSEventType eventType);
NSString* NSEventModifierFlagsToNSString(NSEventModifierFlags modifierFlags);

int main(int argc, char* argv[])
{
	@autoreleasepool 
	{
	
		[NSApplication sharedApplication];
	
		MyEventWindow* eventWindow = [[MyEventWindow alloc] init];
	
		[eventWindow makeKeyAndOrderFront:nil];
		NSString* log = [NSString string];
	
		// my own message loop
	
		[NSApp finishLaunching];
	
		while (true)
		{
			@autoreleasepool
			{
	
				NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate: [NSDate distantFuture] inMode:NSDefaultRunLoopMode dequeue:YES];
				
				log = [NSString stringWithFormat:@"Event [type=%@ location={%d, %d} modifierFlags={%@}]", NSEventTypeToNSString([event type]), (int)[event locationInWindow].x, (int)[event locationInWindow].y, NSEventModifierFlagsToNSString([event modifierFlags])];
				
				//NSLog(@"log: %@", log);
				[eventWindow setLabelText: log];
				
				[NSApp sendEvent:event];
				//[NSApp updateWindows]; // redundant?
			}
		}
	}
	
	return 0;
}

NSString* NSEventTypeToNSString(NSEventType eventType) 
{
  	switch (eventType)
	{
		case NSEventTypeLeftMouseDown: return @"LeftMouseDown";
		case NSEventTypeLeftMouseUp: return @"LeftMouseUp";
		case NSEventTypeRightMouseDown: return @"RightMouseDown";
		case NSEventTypeRightMouseUp: return @"RightMouseUp";
		case NSEventTypeMouseMoved: return @"MouseMoved";
		case NSEventTypeLeftMouseDragged: return @"LeftMouseDragged";
		case NSEventTypeRightMouseDragged: return @"RightMouseDragged";
		case NSEventTypeMouseEntered: return @"MouseEntered";
		case NSEventTypeMouseExited: return @"MouseExited";
		case NSEventTypeKeyDown: return @"KeyDown";
		case NSEventTypeKeyUp: return @"KeyUp";
		case NSEventTypeFlagsChanged: return @"FlagsChanged";
		case NSEventTypeAppKitDefined: return @"AppKitDefined";
		case NSEventTypeSystemDefined: return @"SystemDefined";
		case NSEventTypeApplicationDefined: return @"ApplicationDefined";
		case NSEventTypePeriodic: return @"Periodic";
		case NSEventTypeCursorUpdate: return @"CursorUpdate";
		case NSEventTypeScrollWheel: return @"ScrollWheel";
		case NSEventTypeTabletPoint: return @"TabletPoint";
		case NSEventTypeTabletProximity: return @"TabletProximity";
		case NSEventTypeOtherMouseDown: return @"OtherMouseDown";
		case NSEventTypeOtherMouseUp: return @"OtherMouseUp";
		case NSEventTypeOtherMouseDragged: return @"OtherMouseDragged";
		default:
			return [NSString stringWithFormat:@"%lu", eventType];
  	}
}

NSString* NSEventModifierFlagsToNSString(NSEventModifierFlags modifierFlags) 
{
  	NSString* result = @"";
  	if ((modifierFlags & NSEventModifierFlagCapsLock) == NSEventModifierFlagCapsLock) 
		result = [result stringByAppendingString:@"CapsLock, "];
  	if ((modifierFlags & NSEventModifierFlagShift) == NSEventModifierFlagShift)
		result = [result stringByAppendingString:@"NShift, "];
  	if ((modifierFlags & NSEventModifierFlagControl) == NSEventModifierFlagControl)
		result = [result stringByAppendingString:@"Control, "];
  	if ((modifierFlags & NSEventModifierFlagOption) == NSEventModifierFlagOption)
		result = [result stringByAppendingString:@"Option, "];
  	if ((modifierFlags & NSEventModifierFlagCommand) == NSEventModifierFlagCommand)
		result = [result stringByAppendingString:@"Command, "];
  	if ((modifierFlags & NSEventModifierFlagNumericPad) == NSEventModifierFlagNumericPad)
		result = [result stringByAppendingString:@"NumericPad, "];
  	if ((modifierFlags & NSEventModifierFlagHelp) == NSEventModifierFlagHelp)
		result = [result stringByAppendingString:@"Help, "];
  	if ((modifierFlags & NSEventModifierFlagFunction) == NSEventModifierFlagFunction)
		result = [result stringByAppendingString:@"Function, "];
  	return result;
}

in main I added a second @autoreleasepool inside the while loop it seemed to decrease memory usage significanly, however if I keep moving my mouse a lot the memory usage will still increase.

I don't think this should be happening since the labelText is being destroying and recreated each iteration, is something wrong with my code? Why do I have a memory leak here?

Any feedback regarding the code is also appreciated

Cheers

Answered by DTS Engineer in 803545022
Any feedback regarding the code is also appreciated

My main feedback here is “Don’t do this.”

Running AppKit’s event loop by hand might’ve made sense back in the day but it’s a bad idea these days; things are just so much more complicated than they used to be.

If you run the event loop in the normal way, by calling NSApplicationMain, do you still see the problem?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Accepted Answer
Any feedback regarding the code is also appreciated

My main feedback here is “Don’t do this.”

Running AppKit’s event loop by hand might’ve made sense back in the day but it’s a bad idea these days; things are just so much more complicated than they used to be.

If you run the event loop in the normal way, by calling NSApplicationMain, do you still see the problem?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

autoreleasepool still gives me a memory leak
 
 
Q