Re: Problem using NSTimer in privileged helper tool

2017-10-22 Thread Uli Kusterer
On 19. Oct 2017, at 18:04, Mark Allan  wrote:
> So I tried refactoring the block into a separate method and using an older 
> NSTimer method:
>   [NSTimer timerWithTimeInterval:0.2 target:self 
> selector:@selector(updateTheDelegateForRunID:) userInfo:runID repeats:YES];
> 
> 
> This causes my privileged helper tool to crash with the following message 
> printed to Console:
> 
> Terminating app due to uncaught exception 'NSInvalidArgumentException', 
> reason: '*** -[NSXPCEncoder _checkObject:]: This coder only encodes objects 
> that adopt NSSecureCoding (object is of class '__NSCFTimer').'

 What kind of class is 'self' in this case, and is the 
-updateTheDelegateForRunID: method part of your XPC protocol?

 Methods called by an NSTimer must have the form

-(void) foo: (NSTimer*)sender

So in this case, the first argument passed to -updateTheDelegateForRunID: will 
be the timer itself. If the method call is bridged over XPC, this would mean it 
would try (and fail) to secure code an NSTimer. I don't think clang knows 
enough about NSTimer to be able to tell that the SEL passed to it should take 
an NSTimer* argument, so you're not getting a type error, even though you are 
passing a method that takes the wrong type.

Also, your parameter is probably not what you think it should be. You are 
passing something named runID to your timer's userInfo. This will initialize 
the timer's userInfo property with that value. It is not the value that gets 
passed to -updateTheDelegateForRunID:.

So my guess is what you really need is an intermediate "timer fired" adapter 
method:

-(void) updateTheDelegateForRunIDTimerFired: (NSTimer*)sender
{
[self updateTheDelegateForRunID: [sender userInfo]];
}

and pass that as the timer's selector instead.

Cheers,
-- Uli Kusterer
"The Witnesses of TeachText are everywhere..."
http://www.zathras.de

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Problem using NSTimer in privileged helper tool

2017-10-21 Thread Jean-Daniel


> Le 20 oct. 2017 à 18:56, Quincey Morris  
> a écrit :
> 
> On Oct 20, 2017, at 03:23 , Mark Allan  wrote:
>> 
>> That worked with the block-based NSTimer API but not the selector-based API. 
>>  I tried changing it to 'currentRunLoop' which got rid of the crash, but the 
>> timer never fired.
> 
> This is pure guesswork, but I suspect this is what was going on:
> 
> — When you scheduled the timer on the main run loop, it was actually being 
> scheduled on the main app’s run loop. When it was block based, only the block 
> had to be passed across the XPC interface (which somehow works), but when it 
> was selector-based, the timer itself had to be passed (which doesn’t work). 
> Admittedly this is a pretty silly explanation, but it may have some relation 
> to the truth.
> 
> — When you scheduled the timer on the current run loop, everything was fine 
> either way, except the run loop *wasn’t running* in the XPC thread, so the 
> timer never fired.
> 
> This is similar to a problem that came up on the developer forums a few weeks 
> ago. A developer was using Disk Arbitration callbacks to monitor volumes 
> being mounted, and tried to move that code to an XPC process. The callback 
> was scheduled on the run loop, yet it was never called. There was more recent 
> API that was block-based instead, and that turned out to work fine in an XPC 
> process. The fact that scheduling on the run loop didn’t crash indicated that 
> there *was* a run loop, but the fact that the callbacks didn’t fire suggested 
> that it wasn’t running.

There is always a runloop as it is created lazily when accessing it. So the 
scheduling will always work. But if the current thread does not call 
-[NSRunLoop run] (or a variant), it will never be dispatched.


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Problem using NSTimer in privileged helper tool

2017-10-20 Thread Jens Alfke


> On Oct 20, 2017, at 9:56 AM, Quincey Morris 
>  wrote:
> 
> — When you scheduled the timer on the main run loop, it was actually being 
> scheduled on the main app’s run loop. When it was block based, only the block 
> had to be passed across the XPC interface (which somehow works), but when it 
> was selector-based, the timer itself had to be passed (which doesn’t work). 
> Admittedly this is a pretty silly explanation, but it may have some relation 
> to the truth.

That sounds plausible. One of the dangers of super-transparent inter-process 
messaging like XPC is that you can lose track of which objects are local and 
which remote, and end up using an object you thought was local but is just a 
proxy. Then you get either errors (as here) or terrible performance.

True story from the early days of iChat: We were using Distributed Objects (the 
ancestor of XPC) to communicate between the iChatAgent process, which actually 
logs into the IM service, and the iChat app. One particular GUI operation was 
noticeably slow (I don’t recall which), and when we profiled it, we saw that it 
was making zillions of IPC calls. The reason turned out to be that we had 
assumed that NSURL objects got copied when sent between processes (the way 
NSStrings do), but actually they didn’t; they were proxied. So the iChat app 
ended up with a bunch of NSURL objects received from IPC calls, that it thought 
were local but were actually proxies. They behaved the same way as ‘real’ 
NSURLs, except that calling them was thousands(?) of times slower.

—Jens
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Problem using NSTimer in privileged helper tool

2017-10-20 Thread Quincey Morris
On Oct 20, 2017, at 03:23 , Mark Allan  wrote:
> 
> That worked with the block-based NSTimer API but not the selector-based API.  
> I tried changing it to 'currentRunLoop' which got rid of the crash, but the 
> timer never fired.

This is pure guesswork, but I suspect this is what was going on:

— When you scheduled the timer on the main run loop, it was actually being 
scheduled on the main app’s run loop. When it was block based, only the block 
had to be passed across the XPC interface (which somehow works), but when it 
was selector-based, the timer itself had to be passed (which doesn’t work). 
Admittedly this is a pretty silly explanation, but it may have some relation to 
the truth.

— When you scheduled the timer on the current run loop, everything was fine 
either way, except the run loop *wasn’t running* in the XPC thread, so the 
timer never fired.

This is similar to a problem that came up on the developer forums a few weeks 
ago. A developer was using Disk Arbitration callbacks to monitor volumes being 
mounted, and tried to move that code to an XPC process. The callback was 
scheduled on the run loop, yet it was never called. There was more recent API 
that was block-based instead, and that turned out to work fine in an XPC 
process. The fact that scheduling on the run loop didn’t crash indicated that 
there *was* a run loop, but the fact that the callbacks didn’t fire suggested 
that it wasn’t running.

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Problem using NSTimer in privileged helper tool

2017-10-20 Thread Mark Allan
(sending again - the list was missed off the 'cc' in my reply)

> On 19 Oct 2017, at 6:19 pm, Jens Alfke  > wrote:
> 
>> On Oct 19, 2017, at 9:04 AM, Mark Allan > > wrote:
>> 
>> Initially, I thought this meant my own class needed to conform to 
>> NSSecureCoding, but after some failed attempts, it think it's trying to tell 
>> me that it can't do it because *NSTimer* doesn't conform to NSSecureCoding.  
>> Is that correct, and if so does anyone know of a way around this issue?
> 
> You’re probably not intentionally trying to send the NSTimer object across 
> the XPC connection, but it seems to be happening by accident. The backtrace 
> of the exception should indicate what remote method you’re calling that 
> includes the timer in a parameter.

Thanks for the suggestion. Even though I've now got a working solution, this 
intrigued me enough to try and find out where I might be inadvertently sending 
an NSTimer across the XPC connection.  Console in macOS 10.12 only shows a 
handful of lines of the backtrace so I had to implement my own logging to catch 
this!

I've checked the backtrace and there's only two methods listed - the one which 
the timer fires and the one in the delegate which communicates back to the main 
app. The only parameters involved are NSNumber and NSString, and the delegate 
method has a single line which simply passes those parameters back to the main 
app via the remote object proxy.

Thinking about it some more, if the NSTimer were being sent across the XPC 
connection, surely that would also have been happening with the newer 
block-based NSTimer API I was using originally?

I think that means it *must* be something related to the run-loop, as Quincey 
suggests, but I'm still not sure what the issue is.

I've got a working solution now, so unless anyone wants me to do a bit more 
digging or testing anything, I'll leave it at that.


Thanks for all the help.
Mark

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Problem using NSTimer in privileged helper tool

2017-10-20 Thread Mark Allan

> On 19 Oct 2017, at 6:05 pm, Quincey Morris 
>  wrote:
> 
> On Oct 19, 2017, at 09:04 , Mark Allan  > wrote:
>> 
>> Terminating app due to uncaught exception 'NSInvalidArgumentException', 
>> reason: '*** -[NSXPCEncoder _checkObject:]: This coder only encodes objects 
>> that adopt NSSecureCoding (object is of class '__NSCFTimer').'
> 
> It’s very suspicious that the timer itself would be encoded, since that would 
> suggest that the timer itself is being passed back across the interface to 
> the main app. What does the backtrace look like? Ideally there would be 
> something there that tells you what it’s trying to do at that time.
> 
> I don’t know, but I suspect that the block-based NSTimer methods might differ 
> from the selector-based ones in that they use GCD rather than the run loop. 
> If you look at the documentation, the old methods say "schedules it on the 
> current run loop”. The new methods do not.
> 
> That suggests the possibility of using dispatch_source_create and 
> dispatch_source_set_timer directly to create a GCD-based time. It’s not quite 
> as convenient to code, but not hard to get right.


Bingo...I think!

After creating the NSTimer, I was scheduling it on the main run loop with the 
following:
[[NSRunLoop mainRunLoop] addTimer:self.delegateUpdateTimer 
forMode:NSDefaultRunLoopMode];

That worked with the block-based NSTimer API but not the selector-based API.  I 
tried changing it to 'currentRunLoop' which got rid of the crash, but the timer 
never fired.

Removing NSTimer altogether and replacing it with your suggestion of a 
GCD-based timer works a treat.  Timer fires, no crashing, and the main app sees 
the expected output.


Many thanks
Mark
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Problem using NSTimer in privileged helper tool

2017-10-19 Thread Quincey Morris
On Oct 19, 2017, at 09:04 , Mark Allan  wrote:
> 
> Terminating app due to uncaught exception 'NSInvalidArgumentException', 
> reason: '*** -[NSXPCEncoder _checkObject:]: This coder only encodes objects 
> that adopt NSSecureCoding (object is of class '__NSCFTimer').'

It’s very suspicious that the timer itself would be encoded, since that would 
suggest that the timer itself is being passed back across the interface to the 
main app. What does the backtrace look like? Ideally there would be something 
there that tells you what it’s trying to do at that time.

I don’t know, but I suspect that the block-based NSTimer methods might differ 
from the selector-based ones in that they use GCD rather than the run loop. If 
you look at the documentation, the old methods say "schedules it on the current 
run loop”. The new methods do not.

That suggests the possibility of using dispatch_source_create and 
dispatch_source_set_timer directly to create a GCD-based time. It’s not quite 
as convenient to code, but not hard to get right.

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Problem using NSTimer in privileged helper tool

2017-10-19 Thread Alex Zavatone
A granular timer shouldn’t be that hard to write.  Can you use 
CFAbsoluteTimeGetCurrent() ?  It’s in MacOS since 10.0.

https://developer.apple.com/documentation/corefoundation/1543542-cfabsolutetimegetcurrent



> On Oct 19, 2017, at 11:04 AM, Mark Allan  wrote:
> 
> Hi all,
> 
> I'm currently writing a Mac app which performs some lengthy process on some 
> data, and for a variety of reasons it needs to do this via privileged helper 
> tool.
> 
> The class which does the work sends progress updates periodically to its 
> delegate, which then communicates these back to the main app.
> 
> The main app communicates with the helper tool via NSXPCConnection.
> 
> I'm using an NSTimer to send the update messages to the delegate with the 
> following incantation:
> 
>[NSTimer timerWithTimeInterval:0.2 repeats:YES block:^(NSTimer * _Nonnull 
> timer) { ... }];
> 
> 
> This works fine, but I've just realised NSTimer's 
> timerWithTimeInterval:repeats:block: is only available with macOS 10.12 and I 
> still need to support 10.8.
> 
> So I tried refactoring the block into a separate method and using an older 
> NSTimer method:
>   [NSTimer timerWithTimeInterval:0.2 target:self 
> selector:@selector(updateTheDelegateForRunID:) userInfo:runID repeats:YES];
> 
> 
> This causes my privileged helper tool to crash with the following message 
> printed to Console:
> 
> Terminating app due to uncaught exception 'NSInvalidArgumentException', 
> reason: '*** -[NSXPCEncoder _checkObject:]: This coder only encodes objects 
> that adopt NSSecureCoding (object is of class '__NSCFTimer').'
> 
> 
> Initially, I thought this meant my own class needed to conform to 
> NSSecureCoding, but after some failed attempts, it think it's trying to tell 
> me that it can't do it because *NSTimer* doesn't conform to NSSecureCoding.  
> Is that correct, and if so does anyone know of a way around this issue?
> 
> I guess, if push comes to shove, I could put the timer in the main app and 
> have it request updates from the helper tool, but that sounds awfully like 
> polling, and feels like it would be the wrong way round!
> 
> Grateful for any suggestions.
> 
> Many thanks
> Mark
> 
> ___
> 
> Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)
> 
> Please do not post admin requests or moderator comments to the list.
> Contact the moderators at cocoa-dev-admins(at)lists.apple.com
> 
> Help/Unsubscribe/Update your Subscription:
> https://lists.apple.com/mailman/options/cocoa-dev/zav%40mac.com
> 
> This email sent to z...@mac.com

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Problem using NSTimer in privileged helper tool

2017-10-19 Thread Mark Allan
Hi all,

I'm currently writing a Mac app which performs some lengthy process on some 
data, and for a variety of reasons it needs to do this via privileged helper 
tool.

The class which does the work sends progress updates periodically to its 
delegate, which then communicates these back to the main app.

The main app communicates with the helper tool via NSXPCConnection.

I'm using an NSTimer to send the update messages to the delegate with the 
following incantation:

[NSTimer timerWithTimeInterval:0.2 repeats:YES block:^(NSTimer * _Nonnull 
timer) { ... }];


This works fine, but I've just realised NSTimer's 
timerWithTimeInterval:repeats:block: is only available with macOS 10.12 and I 
still need to support 10.8.

So I tried refactoring the block into a separate method and using an older 
NSTimer method:
[NSTimer timerWithTimeInterval:0.2 target:self 
selector:@selector(updateTheDelegateForRunID:) userInfo:runID repeats:YES];


This causes my privileged helper tool to crash with the following message 
printed to Console:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 
'*** -[NSXPCEncoder _checkObject:]: This coder only encodes objects that adopt 
NSSecureCoding (object is of class '__NSCFTimer').'


Initially, I thought this meant my own class needed to conform to 
NSSecureCoding, but after some failed attempts, it think it's trying to tell me 
that it can't do it because *NSTimer* doesn't conform to NSSecureCoding.  Is 
that correct, and if so does anyone know of a way around this issue?

I guess, if push comes to shove, I could put the timer in the main app and have 
it request updates from the helper tool, but that sounds awfully like polling, 
and feels like it would be the wrong way round!

Grateful for any suggestions.

Many thanks
Mark

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com