Post

Replies

Boosts

Views

Activity

Reply to How to find WHY my app triggers LNP popoup on MacOS 15
Once I remember there was some tool that you would run your binary through, and it would tell you which MacOS APIs you have used... This was decades ago, maybe on the move from Carbon to Cocoa, or from 32 to 64 bit, or maybe even from MacOS to iOS... can't recall now. Does such tool exist ? In my case, anything beyond very basic "Foundation" should be really minimal - so just looking at the list may be useful, This app does almost nothing when launched (merely makes XPC connections to other components of the product, and receives some "configuration" data via these connections. Then - when required by other components, it emits Notifications (via Notification Center) and updates a small popover window "data model". That's all. What could be this thing?
Sep ’24
Reply to How to find WHY my app triggers LNP popoup on MacOS 15
Playing hide and seek with my code to catch the API that indirectly needs "Local Network" permission is not only tedious - it's almost impossible Once the Dialog is up - a TCC entry is created in the TCC database records - no matter if the user answers yes or no, or doesn't even answer at all. It is created even if you cut the electricity to the Mac. From then on, no dialog will ever pop. The app gets a "NO" for Local network access, and works with that. I have NOT found a reasonable way to reset this TCC entry, and as far as I understand - there isn't any. The best I could till now - is to erase the user account and recreate it. But then --- reinstalling all the stuff there, and debugging with another subset of the code - this becomes insanely cumbersome. This is really annoying!!! how can any API require permission, without having at least a name, or some footprint in the OS logs? This is Mac and not IOS, and the available APIs are quite extensive. I'd like to know at least WHY my app wants this? I can't think of anything "network" in my app to start with! isn't this something that should be mentioned in the documentation somewhere?
Sep ’24
Reply to What is the recommended way to count files recursively in a specific folder
Thank you very much. I'll try your suggested approach as well. Seems interesting. I think the inefficiency comes from the basic functionality of the APIs I found so far ( in MacOS Cocoa). They all assume that I'm interested in the actual items, and they fetch/pre-fetch meta-data for each file/item whereas all I need to do is COUNT. Furthermore - all existing APIs that support recursive scan of directory hierarchies - are AGGREGATING the results along the scan, and won't return until they have the full list of items. This of course both burdens CPU work and Memory consumption. I never thought to go to Posix APIs until now, because I dislike them (A True Mac programmer since 1987) because they're all synchronous and plain dumb - they do NOT cover the rich and strange behaviors and attributes of modern file-system. At least in the past, apple had its low-level FileSystem APIs exposed, and I could work magic with them. Since then the FileSystem has changed, but I don't know which APIs exist today. By example, I wrote the following naive code: static NSUInteger totalCount = 0; NSDirectoryEnumerator *dirPathEnumenumerator = [fm enumeratorAtPath:@"/Users/me/Documents"]; NSString *currRelativePath = nil; // local path while ( (currRelativePath = [dirPathEnumenumerator nextObject]) != nil) { NSDictionary *fileAttributes = [dirPathEnumenumerator fileAttributes]; if (![fileAttributes[NSFileType] isEqualToString:NSFileTypeDirectory]) totalCount++; And for my ~100,000 files Documents folder, it took about 6 seconds to run. I then wrote it differently - using SHALLOW directory enumeration, and instead of recursing, I dispatched "need to scan" code-blocks onto concurrent NSOperationQueue, thus removing recursion (and stacks) and also spreading the task over several cores -- like this: static NSUInteger totalCount = 0; static NSFileManager *fmm = nil; static NSArray *requiredProperties = nil; -(void)countFilesInDocumentsFolder { NSOperationQueue *q = [[NSOperationQueue alloc] init]; q.maxConcurrentOperationCount = 5; q.qualityOfService = NSQualityOfServiceUtility; q.name = @"file counting queue"; dirFullPath = @"/Users/me/Documents"; NSURL *topURL = [NSURL fileURLWithPath:dirFullPath]; if (fmm == nil) fmm = [NSFileManager defaultManager]; if (requiredProperties == nil) requiredProperties = @[NSURLNameKey, NSURLIsRegularFileKey ,NSURLIsDirectoryKey, NSURLIsSymbolicLinkKey, NSURLIsVolumeKey, NSURLIsPackageKey]; [self countFilesInDirectory:topURL usingQueue:q]; [q waitUntilAllOperationsAreFinished]; NSLog (@"Total File count in directory: %@ is: %lu", dirFullPath, totalCount); } -(void)countFilesInDirectory:(NSURL *)directoryURL usingQueue:(NSOperationQueue *)queue { [queue addOperationWithBlock:^{ NSError *error = nil; NSArray<NSURL *> *itemURLs = [fmm contentsOfDirectoryAtURL:directoryURL includingPropertiesForKeys:requiredProperties options:NSDirectoryEnumerationSkipsHiddenFiles error:&error]; if (error) { NSLog(@"Failed to get contents of: %@, Error:%@", directoryURL, error); return; }; for (NSURL *url in itemURLs) { NSDictionary<NSURLResourceKey, id> *fileAttributes = [url resourceValuesForKeys:requiredProperties error:&error]; if (error!=nil || fileAttributes == nil) { NSLog(@"Failed to retrieve attributes for:%@ Error:%@",url, error); continue; } if ([fileAttributes[NSURLIsDirectoryKey] boolValue]) { [queue addOperationWithBlock:^{ [self countFilesInDirectory:url usingQueue:queue]; }]; } else { if ( [fileAttributes[NSURLIsRegularFileKey] boolValue]) totalCount++; } } } }]; } And this one - although lengthy - took about 0.45 sec to do the same job (even a little better). So... with my ***** of a Mac and a fast-as-hell SSD, I am still very far from satisfied. I'll go down the POSIX rabbit hole and see what goes. Thanks! If I find the POSIX faster than my current thing, I'll accept your answer as the best :)
Jul ’24
Reply to XPC, Swift, ObjC, and arrays
Thanks for the info so far -- it is really valuable. However - few questions remained un-answered for me (in similar but not identical scenario) Should the set of allowed classes be applied to the "exported interface" on both Client and Server side of the XPC connection? only Server side? only Client side? Your question involves your own custom class. But what Cocoa classes are acceptable by default (without calling the "exportedInterface.setClasses", and what should be manually added ? Where is the list documented? B.T.W an ObjC version of the same snippet would be nice. 3, In my experience both server and client are Obj-C and I don't have any custom classes - only Cocoa classes), the behavior of XPC is very unclear. I experienced exceptions that claim exactly that - "unsupported classes" but only sometimes it fails, and sometimes it passes OK, and I can't understand when and what and why. For example, I removed NSError NSAttributedString classes from my XPC protocol, and that removed the intermittent exceptions. Why? Last, you asked about logs have you found relevant log messages related to this? Where to look for them? In my case, the only "logs" were .ips crash-logs...
Jun ’24
Reply to Faulty, hard-to-understand XPC behavior with remote methods that have a reply-block
Thanks again. Indeed I missed the sentence "A method can have only one reply block." in the old archived documentation - but that same sentence also says: A method can have only one reply block. However, because connections are bidirectional, the XPC service helper can also reply by calling methods in the interface provided by the main application, if desired. Which brings me to the original question -- HOW do I do that? My "players" aren't an App and its helper-service, but rather independent, resilient system daemons and global agents that need communicate, in all directions. The dual XPC connection I'm maintaining now, is just cumbersome. Each "product shutdown" flow is an ugly nightmare, and recovering from one-side-crash looks different on either sides - which is ugly too. Bidirectional XPC connections look like the right thing to me. I found and downloaded the recommended 2012 WWDC session from here: https://archive.org/download/wwdc-2012-sessions and watched it carefully twice - but there too - it is only HINTED for a split second, that the connection is bidirectional and both sides can send messages - and immediately the hint is removed from screen, and replaced by that single reply-block technique. There is a tiny gap here I need to bridge. I already have a live NSXPCConnection, both sides agree on the same protocol, the "client side" obtains a "remote proxy" and the "server side" exports an object and assigns them to accepted incoming connection. Then client sends messages to the service. How can the client-side create an "exported object"? can it also assign an NSXPCInterface and exported-object to its NSXPCConnection when it connects to the service? and how would the service get the proxy if it wants to call-back to the client? If the docs say NSXPCConnection is bi-directional, SOMETHING must be said somewhere regarding the use of this feature. As in your hinted novel - I think I'll just go on and open the "disused lavatory" carrying that "Beware of the Leopard" sign, to find the demolition order for my house :( One things keeps me uneasy. In the full decade of NSXPCConnection, hasn't anyone need bi-directional IPC? Why is it only I'm looking for ways to do it? Design-wise, Is it something wrong with my ideas?
Sep ’23
Reply to Is Quinn “The Eskimo!” actually a franchise?
To whoever collects evidence - I admit to have met Quinn face-to-face SEVERAL times, in 4 or 5 different WWDC occasions, from about 1995 to (I'm not sure here) 2010. I also know his name from header files of the late OpenTransport technology and even the larger-scale "Power" set of communications/networking technologies that Apple brewed in the last 5 years of MacOS classic (7,8,9). This means, I can remember his face, with no direct connection to any developer support incident. Rather a beer (or was it white-wine?) in one of the WWDC receptions in San Jose, CA. I even owe him my life and happiness - as one of his indispensable comments in one of Apple's old header files, said "Don't do XXXXX or you will never have a happy life". Fortunately I read this note in time to see my code contained exactly XXXXX - so I found another way of doing what I needed, and my life was saved.
Sep ’23
Reply to How to properly implement delay gap between operations for NSOperationQueue?
Hi, I read the code - not thoroughly, and I think this can be done much simpler. First, I agree with Eskimo that messing with NSOperationQueue isn't the right thing. Your task is better achieved by constructing a proper NSOperation instead. Second, and this is "high level" remark" you almost re-implemented NSOperation in your subclass, instead of modifying its behavior, and I think there's a much much simpler way to do this. As you're already aware, the isCancelled and isFinished properties of an NSOperation are observable - and are also observed by the NSOperationQueue. But you forgot the one property that BY DESIGN gives you what you want -- @property (readonly, getter=isReady) BOOL ready; Now when you want to delay the execution of an NSOperation, all you need to do is to keep its ready property at NO until such time you want it to execute, and then - change it to YES. NSOperationQueue observes the ready property, and will schedule pulling it from the queue when it becomes ready. You'll need to wisely override the ready property, so that you don't break other behavior of it, and you will need to have a timer somewhere that will trigger its change to YES. I don't have time to implement a sample now... maybe I'll do it and add to this answer. Hope this helps.
May ’23
Reply to Determine if Active Directory user is admin or not
I fail to fully understand this code. Why attempt to retrieve records for ALL users? (kODMatchAny for kODRecordTypeUsers without limitations?) This WILL fail in large environments (most corporates) after few thousands of users. Why do this on the first place, if you want to "see whether a specific AD user is admin" ?? This code only receives records from the LOCAL search-scope, not AD at all. Have you tested? Why the textual manipulation of group results? use OD objects..
Mar ’23
Reply to Need help resolving a nasty crash
I found the problem to be this: My NSMutableDictionary (actionInfo) sometimes contained values that were of the class NSSet. Sadly, the Cocoa/ObjC implementation of NSXPCConnection does not allow passing just any type of object "on the wire" to the remote process. I DO NOT completely understand the issue - because SOMETIMES it does work, and sometimes it crashes, but the moment I restrict the objects passed on the wire to those basic Foundation classes one finds in Plists (The sacred NSArray, NSDicationary, NSString, NSDate, NSNumber and (maybe - haven't verified - NSData) The sporadic crashes disappeared completely. I verified also that all the objects in the NSSet I was passing were from this list of "standard" objects - so - the cause is definitely the NSSet. What I do now, is pass [mySet allObjects] (yielding an NSArray) to the other side, where I convert it back to [NSSet setWithArray:] and live like that. Maybe I missed it in the documentation - but I think the only "no no" I have seen in the docs is about classes that can't be securely encoded - and as far as I know NSSet is a honorable and securely-encodable object... So... I don't understand, but at least I resolved my crash. Hope this helps anyone.
Dec ’22
Reply to Need help resolving a nasty crash
Thanks for the reply. Maybe I wasn't clear. In my attempt to resolve the crash, I changed my code so that ALL modifications to the actionInfo mutable dictionary are enclosed in operations added to the serial monitorUpdateQueue queue. You can look at the example - I just have about a dozen "snippets" like that, adding/modifying some info on the actionInfo, then calling the XPC. All on the serial queue. The other concurrent queues and threads, are now ALL dispatching anything related to the actionInfo onto the serial queue. The whole code related to this mutable dictionary is placed in 2 methods (actionInfo is a heap object, not an object member, allocated in the beginning of one method, and deleted as it exits. I is never passed to other objects -- except, of course, the failing XPC call which "reports" this data to another process.
Sep ’22