Skip to content

Commit e6b57c0

Browse files
committed
After testing BookMacster 1.17 in Mavericks
1 parent 85d9fab commit e6b57c0

6 files changed

+117
-83
lines changed

SSYLaunchdGuy.h

+17
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,23 @@ __attribute__((visibility("default"))) @interface SSYLaunchdGuy : NSObject {
169169
+ (BOOL)removeAgentsWithGlob:(NSString*)glob
170170
error_p:(NSError**)error_p ;
171171

172+
/*
173+
@brief Returns the pid of the currently-running process launched in honor
174+
of a given launchd label for the current user, or 0 if there is no such
175+
process currently running.
176+
177+
@details This method relies on the 'list' subcommand of 'launchctl' returning
178+
the three columns {pid, last exit status, label} as documented in the man
179+
page launchctl(1). If that return is not as expected, this method logs a
180+
message to stderr and returns 0. Likewise if launchctl or grep don't exit
181+
with status 0.
182+
183+
If you pass nil or a non-label string, returns 0 and does not log anything.
184+
185+
This method had a bug until BookMacster 1.17. Prior to that, if your label's
186+
last exit status was not 0, and the label's process was not current running,
187+
this method would return the negative of that last exit status, instead of 0.
188+
*/
172189
+ (pid_t)pidIfRunningLabel:(NSString*)label ;
173190

174191
/*!

SSYLaunchdGuy.m

+61-34
Original file line numberDiff line numberDiff line change
@@ -350,40 +350,67 @@ + (pid_t)pidIfRunningLabel:(NSString*)label {
350350
NSInteger result ;
351351
pid_t pid = 0 ;
352352

353-
NSData* stdoutData = nil ;
354-
NSError* error = nil ;
355-
NSString* command = [NSString stringWithFormat:
356-
@"/bin/launchctl list | /usr/bin/grep %@",
357-
[self bashEscapementOfLabel:label]] ;
358-
NSArray* arguments = [NSArray arrayWithObjects:
359-
@"-c",
360-
command,
361-
nil] ;
362-
result = [SSYShellTasker doShellTaskCommand:@"/bin/sh"
363-
arguments:arguments
364-
inDirectory:nil
365-
stdinData:nil
366-
stdoutData_p:&stdoutData
367-
stderrData_p:NULL
368-
timeout:3.0
369-
error_p:&error] ;
370-
if ((result != 0) && error) {
371-
NSLog(@"SSYLaunchdGuy Error 879-1417 label=%@ %@", label, error) ;
372-
}
373-
374-
if (stdoutData) {
375-
NSString* response = [[NSString alloc] initWithData:stdoutData
376-
encoding:NSUTF8StringEncoding] ;
377-
// Next line is defensive programming
378-
NSString* trimmedResponse = [response stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] ;
379-
[response release] ;
380-
NSArray* words = [trimmedResponse componentsSeparatedByString:@" "] ;
381-
if ([words count] > 0) {
382-
NSString* pidString = [words objectAtIndex:0] ;
383-
pid = [pidString intValue] ;
384-
}
385-
}
386-
353+
if ([label length] > 0) {
354+
NSData* stdoutData = nil ;
355+
NSError* error = nil ;
356+
NSString* commandString = [NSString stringWithFormat:
357+
@"/bin/launchctl list | /usr/bin/grep %@",
358+
[self bashEscapementOfLabel:label]] ;
359+
NSArray* arguments = [NSArray arrayWithObjects:
360+
@"-c", // Tells sh: Read commands from next argument
361+
commandString,
362+
nil] ;
363+
result = [SSYShellTasker doShellTaskCommand:@"/bin/sh"
364+
arguments:arguments
365+
inDirectory:nil
366+
stdinData:nil
367+
stdoutData_p:&stdoutData
368+
stderrData_p:NULL
369+
timeout:3.0
370+
error_p:&error] ;
371+
if ((result != 0) && error) {
372+
NSLog(@"SSYLaunchdGuy Error 879-1417 label=%@ %@", label, error) ;
373+
}
374+
375+
if (stdoutData) {
376+
NSString* response = [[NSString alloc] initWithData:stdoutData
377+
encoding:NSUTF8StringEncoding] ;
378+
NSString* trimmedResponse = [response stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] ;
379+
/*
380+
The following line was fixed in BookMacster 1.17 so that it works
381+
if fields are separated by tabs (as they are in Mac OS X 10.8)
382+
instead of spaces. Maybe they were spaces in an earlier OS X
383+
version? Anyhow, we handle either now.
384+
*/
385+
NSArray* words = [trimmedResponse componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] ;
386+
/*
387+
If the 3 "words" (pid, <last exit status>, label) printed by
388+
launchctl are separated by multiple spaces instead of tabs,
389+
'words' will contain bunches of empty strings in addition to these
390+
3 actual "words". This is because
391+
-componentsSeparatedByCharactersInSet: does not coalesce
392+
consecutive separators. However, since we are only interested in
393+
the first object in words (the pid), we still get it OK.
394+
*/
395+
if ([words count] > 2) { // Was "> 0" until BookMacster 1.17
396+
NSString* pidString = [words objectAtIndex:0] ;
397+
pid = [pidString intValue] ;
398+
/* If the label does not have a running process, launchctl will
399+
signify that by a dash ("-") and hence pidString will be "-",
400+
and hence we'll get pid=0 as desired, because -intValue
401+
"Returns 0 if the receiver doesn’t begin with a valid decimal
402+
text representation of a number." */
403+
}
404+
else if ([words count] > 1){
405+
NSLog(@"SSYLaunchdGuy Error 879-1418 label=%@ response=\"%@\"", label, response) ;
406+
}
407+
else {
408+
// Expected if the given label is not registered with launchd.
409+
}
410+
[response release] ;
411+
}
412+
}
413+
387414
return pid ;
388415
}
389416

SSYMOCManager.h

+17-3
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
5757
This method retains a reference to the managed object context (in any of the three MOCDics).
5858
To avoid leaks or retain cycles, send a
59-
-releaseManagedObjectContext: message whenever a managed object context returned from this
59+
+destroyManagedObjectContext: message whenever a managed object context returned from this
6060
method is no longer needed.
6161
@param type NSSQLiteStoreType or NSInMemoryStoreType.
6262
@param owner If a new managed object context must be created, an arbitrary object which
@@ -93,7 +93,7 @@
9393
for the managed objects.
9494
9595
This method retains the -document parameter until it receives a corresponding
96-
+releaseManagedObjectContext message, so be careful or you will create retain cycles.
96+
+destroyManagedObjectContext message, so be careful or you will create retain cycles.
9797
This method will, however, *replace* its record for a particular document if you later
9898
send this message again for the same document with a new or same managedObjectContext.
9999
@param document The document which owns the managed object context
@@ -133,11 +133,25 @@
133133
needed, in order to avoid memory leaks in your program. To avoid retain cycles,
134134
don't do it in -dealloc. Put it in a method which runs prior to -dealloc.
135135
It is OK to send this message more than once; further invocations will no-op.
136+
137+
However, note that SSYMOCManager does not have a retain count mechanism. That
138+
is why this method is named "destroy…" instead of "release…". If more than one
139+
of your objects could be using the subject managed object context, it is your
140+
responsibility to not send this message until all such objects no longer need
141+
it.
136142
@param managedObjectContext The managed object context to be removed.
137143
@return YES if an entry with the given managed object context was found and removed,
138144
otherwise NO.
139145
*/
140-
+ (BOOL)releaseManagedObjectContext:(NSManagedObjectContext*)managedObjectContext ;
146+
+ (BOOL)destroyManagedObjectContext:(NSManagedObjectContext*)managedObjectContext ;
147+
148+
/*@brief Removes any managed object context with a give identifier,
149+
which would be returned by -managedObjectContextType:::::, from the
150+
receiver's instance's data.
151+
152+
@details Ditto the details from +destroyManagedObjectContext:.
153+
*/
154+
+ (void)destroyManagedObjectContextWithIdentifier:(NSString*)identifier ;
141155

142156
/*!
143157
@brief Deletes the local store file on disk for an sqlite store with a given

SSYMOCManager.m

+21-42
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#import "SSYPersistentDocumentMultiMigrator.h"
99
#import "NSManagedObjectContext+Cheats.h"
1010
#import "NSError+DecodeCodes.h"
11+
#import "NSObject+MoreDescriptions.h"
12+
1113

1214
NSString* const constKeyMOC = @"moc" ;
1315
NSString* const constKeyOwner = @"owr" ;
@@ -24,40 +26,6 @@
2426
// -autorelease
2527
static SSYMOCManager* sharedMOCManager = nil ;
2628

27-
#if DEBUG
28-
29-
@interface NSCountedSet (SSYMOCManagerHelp)
30-
31-
- (NSString*)shortDescription ;
32-
33-
@end
34-
35-
@implementation NSCountedSet (SSYMOCManagerHelp)
36-
37-
- (NSString*)shortDescription {
38-
NSMutableString* desc = [NSMutableString string] ;
39-
for (id object in self) {
40-
[desc appendFormat:
41-
@"%@ [%ld],",
42-
[object shortDescription],
43-
(long)[self countForObject:object]] ;
44-
}
45-
46-
// Delete the trailing comma
47-
if ([desc length] > 0) {
48-
[desc deleteCharactersInRange:NSMakeRange([desc length] - 1, 1)] ;
49-
}
50-
else {
51-
[desc appendString:@"<Empty Set>"] ;
52-
}
53-
54-
return [[desc copy] autorelease] ;
55-
}
56-
57-
@end
58-
59-
#endif
60-
6129

6230
@interface SSYMOCManager (PrivateHeader)
6331

@@ -338,7 +306,7 @@ - (NSManagedObjectContext*)managedObjectContextType:(NSString*)type
338306
momdName:momdName
339307
error_p:error_p] ;
340308
if (coordinator) {
341-
managedObjectContext = [[NSManagedObjectContext alloc] init] ;
309+
managedObjectContext = [[NSManagedObjectContext alloc] init] ;
342310
[managedObjectContext setPersistentStoreCoordinator:coordinator] ;
343311
if (!owner_) {
344312
// A no-owner moc is a "cheap" moc.
@@ -355,6 +323,7 @@ - (NSManagedObjectContext*)managedObjectContextType:(NSString*)type
355323
forKey:identifier] ;
356324

357325
[managedObjectContext release] ; // balances +alloc, above
326+
;
358327
}
359328
}
360329

@@ -424,7 +393,13 @@ - (id)ownerOfManagedObjectContext:(NSManagedObjectContext*)managedObjectContext
424393
return answer ;
425394
}
426395

427-
- (BOOL)releaseManagedObjectContext:(NSManagedObjectContext*)managedObjectContext
396+
- (void)destroyManagedObjectContextWithIdentifier:(NSString*)identifier {
397+
[[self inMemoryMOCDics] removeObjectForKey:identifier] ;
398+
[[self sqliteMOCDics] removeObjectForKey:identifier] ;
399+
[[self docMOCDics] removeObjectForKey:identifier] ;
400+
}
401+
402+
- (BOOL)destroyManagedObjectContext:(NSManagedObjectContext*)managedObjectContext
428403
inDictionary:(NSMutableDictionary*)dictionary {
429404
NSString* removeeIdentifier = nil ;
430405
for (NSString* identifier in dictionary) {
@@ -442,17 +417,17 @@ - (BOOL)releaseManagedObjectContext:(NSManagedObjectContext*)managedObjectContex
442417
return (removeeIdentifier != nil) ;
443418
}
444419

445-
- (BOOL)releaseManagedObjectContext:(NSManagedObjectContext*)managedObjectContext {
420+
- (BOOL)destroyManagedObjectContext:(NSManagedObjectContext*)managedObjectContext {
446421
BOOL didDo = NO ;
447-
didDo = [self releaseManagedObjectContext:managedObjectContext
422+
didDo = [self destroyManagedObjectContext:managedObjectContext
448423
inDictionary:[self inMemoryMOCDics]] ;
449424
if (!didDo) {
450-
didDo = [self releaseManagedObjectContext:managedObjectContext
425+
didDo = [self destroyManagedObjectContext:managedObjectContext
451426
inDictionary:[self sqliteMOCDics]] ;
452427
}
453428

454429
if (!didDo) {
455-
didDo = [self releaseManagedObjectContext:managedObjectContext
430+
didDo = [self destroyManagedObjectContext:managedObjectContext
456431
inDictionary:[self docMOCDics]] ;
457432
}
458433

@@ -484,8 +459,12 @@ + (id)ownerOfManagedObjectContext:(NSManagedObjectContext*)managedObjectContext
484459
return [[self sharedMOCManager] ownerOfManagedObjectContext:managedObjectContext] ;
485460
}
486461

487-
+ (BOOL)releaseManagedObjectContext:(NSManagedObjectContext*)managedObjectContext {
488-
return [[self sharedMOCManager] releaseManagedObjectContext:managedObjectContext] ;
462+
+ (BOOL)destroyManagedObjectContext:(NSManagedObjectContext*)managedObjectContext {
463+
return [[self sharedMOCManager] destroyManagedObjectContext:managedObjectContext] ;
464+
}
465+
466+
+ (void)destroyManagedObjectContextWithIdentifier:(NSString*)identifier {
467+
[[self sharedMOCManager] destroyManagedObjectContextWithIdentifier:identifier] ;
489468
}
490469

491470
+ (void)removeSqliteStoreForIdentifier:(NSString*)identifier {

SSYManagedObject.m

+1-1
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ - (void)postWillSetNewValue:(id)value
311311
[(SSYDooDooUndoManager*)[[self owner] undoManager] beginAutoEndingUndoGrouping] ;
312312
}
313313

314-
NSDictionary* info = [NSDictionary dictionaryWithObjectsAndKeys:
314+
NSDictionary* info = [NSDictionary dictionaryWithObjectsAndKeys:
315315
key, constKeySSYChangedKey,
316316
value, constKeyNewValue, // May be nil, so keep this last!
317317
nil] ;

SSYOperationQueue.m

-3
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,6 @@ - (void)observeValueForKeyPath:(NSString*)keyPath
234234
id activity = [self noAppNapActivity] ;
235235
if (activity) {
236236
[[NSProcessInfo processInfo] endActivity:activity];
237-
/*SSYDBL*/ NSLog(@"Ended no-app-nap activity=%@", activity) ;
238237
}
239238
#endif
240239

@@ -259,7 +258,6 @@ - (void)observeValueForKeyPath:(NSString*)keyPath
259258
// KVO notifications are coalesced.
260259

261260
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
262-
#warning "Built for 10.9"
263261
// Being built with Mac OS X 10.9 or later SDK
264262
if ([[NSProcessInfo processInfo] respondsToSelector:@selector(beginActivityWithOptions:reason:)]) {
265263
// Running in Mac OS X 10.9 or later
@@ -280,7 +278,6 @@ - (void)observeValueForKeyPath:(NSString*)keyPath
280278
[[NSDate date] geekDateTimeString]] ;
281279
id activity = [[NSProcessInfo processInfo] beginActivityWithOptions:NSActivityAutomaticTerminationDisabled
282280
reason:reason] ;
283-
/*SSYDBL*/ NSLog(@"Suspended app nap with activity=%@ for reason: %@", activity, reason) ;
284281
[self setNoAppNapActivity:activity] ;
285282
}
286283
#endif

0 commit comments

Comments
 (0)