I'm trying to get the URL of the browser with Mac OS X app. I wrote some AppleScript and am trying to use it in Cocoa. The problem is, when I watch it with instruments, memory is increasing, and at the end of 3-4 hours it's nearly 20MB.
- First generation enter image description here
- Second generation (5 min. later) enter image description here
#import "AppDelegate.h"
#import <Carbon/Carbon.h>
@interface AppDelegate ()
@property (weak) IBOutlet NSWindow *window;
@end
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:@selector(collect)
userInfo:nil
repeats:YES];
}
- (void)collect{
[self runWithEvent];
}
- (void)runWithEvent{
NSURL *URL = [[NSBundle mainBundle] URLForResource:@"frontmostapptitle" withExtension:@"scpt"];
if (URL) {
NSAppleScript *appleScript = [[NSAppleScript alloc] initWithContentsOfURL:URL error:NULL];
NSAppleEventDescriptor *returnDescriptor = [self lookUpRunningApp];
NSDictionary *error = nil;
NSAppleEventDescriptor *resultEventDescriptor = [appleScript executeAppleEvent:returnDescriptor error:&error];
if (! resultEventDescriptor) {
NSLog(@"%s AppleScript run error = %@", __PRETTY_FUNCTION__, error);
}
else {
NSLog(@"%@", [self stringForResultEventDescriptor:resultEventDescriptor]);
}
}
}
- (NSAppleEventDescriptor *)lookUpRunningApp{
// target
ProcessSerialNumber psn = {0, kCurrentProcess};
NSAppleEventDescriptor *target = [NSAppleEventDescriptor descriptorWithDescriptorType:typeProcessSerialNumber bytes:&psn length:sizeof(ProcessSerialNumber)];
// function
NSAppleEventDescriptor *function = [NSAppleEventDescriptor descriptorWithString:@"LookUpRunningApp"];
// event
NSAppleEventDescriptor *event = [NSAppleEventDescriptor
appleEventWithEventClass:kASAppleScriptSuite
eventID:kASSubroutineEvent
targetDescriptor:target
returnID:kAutoGenerateReturnID
transactionID:kAnyTransactionID];
[event setParamDescriptor:function forKeyword:keyASSubroutineName];
return event;
}
- (NSString *)stringForResultEventDescriptor:(NSAppleEventDescriptor *)resultEventDescriptor
{
NSString *result = nil;
if (resultEventDescriptor) {
if ([resultEventDescriptor descriptorType] != kAENullEvent) {
if ([resultEventDescriptor descriptorType] == kTXNUnicodeTextData) {
result = [resultEventDescriptor stringValue];
}
}
}
return result;
}
@end
-
\$\begingroup\$ Did you try commenting out lines that don't affect functionality like NSLogs? As the Applescript doesn't change, could you alloc the appleScript once and reuse it? Also the NSAppleEventDescriptor lookUpRunningApp could probably inited once and be reused. In my experience, AppleEvent generally has memory issues. Finally what is your main goal? Could you use NSRunningApplication and CGWindow API? \$\endgroup\$mahal tertin– mahal tertin2015年02月12日 16:42:23 +00:00Commented Feb 12, 2015 at 16:42
-
\$\begingroup\$ What I found more robust is using [[NSAppleScript alloc] initWithSource:@"tell \n -- do work \n end tell" \$\endgroup\$mahal tertin– mahal tertin2015年02月12日 16:48:44 +00:00Commented Feb 12, 2015 at 16:48
-
\$\begingroup\$ For the actual question on memory usage, that feels more appropriate to ask on Stack Overflow, but I'll add that the Instruments app will actually tell you what is consuming your memory, so I recommend checking out what's being allocated and not being deallocated. \$\endgroup\$nhgrif– nhgrif2015年02月13日 00:46:35 +00:00Commented Feb 13, 2015 at 0:46
1 Answer 1
- (NSString *)stringForResultEventDescriptor:(NSAppleEventDescriptor *)resultEventDescriptor
{
NSString *result = nil;
if (resultEventDescriptor) {
if ([resultEventDescriptor descriptorType] != kAENullEvent) {
if ([resultEventDescriptor descriptorType] == kTXNUnicodeTextData) {
result = [resultEventDescriptor stringValue];
}
}
}
return result;
}
This method can be rewritten far more simply:
- (NSString *)stringForResultEventDescriptor:(NSAppleEventDescriptor *)resultEventDescriptor {
return (resultEventDescriptor.descriptorType == kTXNUnicodeTextData) ? resultEventDescriptor.stringValue : nil;
}
- (void)collect{
[self runWithEvent];
}
This method seems entirely unnecessary. Why doesn't the timer just call runWithEvent
directly?
Explore related questions
See similar questions with these tags.