Replacement for core service's MPRemoteCall? - macos

I have a legacy carbon app that used MPRemoteCall to show an assert dialog when something bad happens on the main thread of the app. Sometimes an assert happens in a worker thread that shouldn't be doing UI stuff. However it's deprecated a long time ago and I was wondering what the replacement API is?

I think - [NSObject performSelectorOnMainThread:withObject:waitUntilDone:] is probably the closest analog to MPRemoteCall().
GCD/blocks should also work:
dispatch_sync(dispatch_get_main_queue(), ^{
// do work here
});
Hopefully these will work correctly if your app is still using a Carbon event loop--I have had problems in the past with Cocoa timer functions in Carbon apps.

Related

Xcode 8 UI Testing Taking Very Long

I'm writing UI tests in XCode 8 for a very complicated app. I'm discovering several issues, one of them being that each test I run takes several minutes.
The flow for the particular test I'm running isn't even that complicated.
I get many "Wait for app to idle" messages.
Does anyone know why the tests take so long to run, or do you have any suggestions on how I can speed them up? The WWDC demo was basically instant, but that was a very simple app.
Here's an example of what I see, and how long it takes. (The test is also still running!)
t = 504.16s Wait for app to idle
t = 625.29s App animations complete notification not received, will attempt to continue.
t = 625.30s Synthesize event
t = 625.67s Wait for app to idle
Thanks!
Update: When I slightly interact with the app, while keeping the elements I need visible, like by pulling on a tableview, the tests continue.
Thanks #Oletha - I found the issue, which may be specific to this app:
After deleting large amounts of code at a time to see where the issue was, we found that we were calling beginRefreshing and endRefreshing on a subclass of UIRefreshControl, on consecutive lines.
Something about that stalled the UI, enough to hold the app in "Wait for app to idle" for minutes.
We replaced those two lines with a custom method, and now tests are running normally.
The framework will wait for the app to become static, so if any views are animating or any activity indicators are shown, possibly including the network activity indicator in the status bar, the framework will hang until the app is still. This is to prevent race conditions with animations and components loading while the UI tests run.
If you think it's OK to override some of this behaviour to speed up your UI tests, you can try experimenting with removing activity indicators.
I encountered the same issue. The solution was to move the call to endRefreshing from the handler to the end of a network method triggered in the handler. In other words, if you refresh a table view, make sure to endRefreshing after all data has been loaded.
In my case was because I had some animations (UIView.animate...) so I had to UIView.setAnimationsEnabled(false) when running the app from the UI tests (you can send launchArguments or something).
Set launchArguments just before calling app.launch():
app.launchArguments = ["enable-testing"]
app.launch()
Then in the AppDelegate, check launch arguments:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
#if DEBUG
if CommandLine.arguments.contains("enable-testing") {
UIView.setAnimationsEnabled(false)
}
#endif
// ...
}
Thats all!
I had the same issue - on an actual device I would continually see "Wait for app to idle"
2 simple solutions:
1) If you're running on a device, make sure it's kept still (i.e not moving). Running tests while holding the device it would always be waiting for the app to idle. Placed flat on a desk, tests ran fine.
2) Alternatively, run your tests on the simulator if possible

Closing an application and saving data when using ARC Welder

When closing an application using ARC Welder, does the application get any message about this?
There are methods like OnPause / OnStop / OnDestroy. They are called by Android OS, but in our opinion they are not called by ARC Welder when we close an application. So the data can't be saved this way and the user would have to save all data manually before closing the application.
Sorry, it looks like we do currently not forward the signal we receive from the chrome.app.window.onClosed event.
Feel free to star this bug to vote it up.

How to integrate WinRT asynchronous tasks into existing synchronous libraries?

We have a long established, greatly multiplatform codebase that is currently being ported to WinRT. One of the challenges we're facing is how to handle WinRT's asynchronous style.
For example, we are unsure how to handle WinRT's async file operations. Unsurprisingly, our codebase's API is synchronous. A typical example is our File::Open function which attempts to open a file and return with success or failure. How can we call WinRT functions and yet keep the behavior of our functions the same?
Note that we are unfortunately constrained by legacy: we cannot simply go and change the API to become asynchronous.
Thanks!
I assume you wish to reimplement the library to support WinRT apps while not changin the definitions of the APIs so that existing applications remain compatible.
I think that if you don't include the await keyword when calling an async method you will not do an async operation, it should execute in a synchronous way. But it really doesn't work if the method returns a value (in my experience).
I've been using this code to make a file operation synchronous:
IAsyncOperation<string> contentAsync = FileIO.ReadTextAsync(file);
contentAsync.AsTask().Wait();
string content = contentAsync.GetResults();
If you want to share your code with a platform that does not support async/await - you are probably better off having a different API for the old platform and the new one with switches like
#if SILVERLIGHT
#elif NETFX_CORE
#elif WPF
#endif
Eventually the async APIs are likely to show up in older platforms and you could actually wrap the non-async calls into Tasks to make them async if they don't. Forcing async method to work synchronously is bound to bite you back rather quickly. Your WinRT app might become unresponsive for a few seconds for example and get killed by the OS. Or you could get deadlocks waiting for tasks to complete and blocking the thread they try to complete on.

Handling CGEventTaps in an NPAPI plugin

I'm trying to create an NPAPI plugin to listen to the Media Keys on a macbook and pass that to javascript to control things like pandora or soundcloud. I'm using Spotify's SPMediaKeyTap library, which just wraps CGEventTap running on a separate thread.
My problem is that I use npn_invoke to call back to javascript. This works normally, but when it's triggered from the CGEventTap callback, it crashes the plugin. I realize this needs to be run from the plugin thread, and I've tried to pass it back to the main thread both by using [NSObject performSelectorOnMainThread] and [NSObject performSelector:onThread] with the thread i've stored away in the main plugin threads create method. Both of these solutions still crash on any npn call. Is there anything else that goes on when handling a CGEventTap event that causes state to be invalid for NPN browser interaction calls?
Don't try to second guess the threading model by saving the thread like you are; just use performSelectorOnMainThread to call NPN methods. I do this all the time and it works fine, so I'm guessing that something with your method of cross-thread marshalling isn't working the way it needs to.

NSNotificationCenter Observer stops receiving events when app is out of focus on Lion

I have an app that subscribes to a specific kind of notifications from the default NSNotificationCenter.
On OSX Lion, it works fine, except that when the app loses the focus (another app becomes active), it stops receiving the events. When the app gains the focus, it starts receiving events again.
The app did not have this behavior on previous versions of OSX, it always received notifications, even when it was out of focus.
What can I do to change this behavior?
Thanks!
Nathan
I know its a bit late to answer this, still for my records and if some one still searching.
My OS X Menu bar app had the same problem. I wanted the app to observe all states.
Reason:
When the app looses focus,the observer is suspended.
ie. When the application becomes in-active it calls the method
-(void)applicationDidResignActive:(NSNotification *)notification
and by default the NSDistributedNotificationCenter object gets suspended.
Solution:
I created an object for NSDistributedNotificationCenter
NSDistributedNotificationCenter *center=[NSDistributedNotificationCenter defaultCenter];
and then when the app looses focus its call the applicationDidResignActive method and inside
that the NSDistributedNotificationCenter object is made to regain from suspended state by sending NO to setSuspended method.
-(void)applicationDidResignActive:(NSNotification *)notification
{
[center setSuspended:NO];
}
and then app starts observing even when it looses focus.
According to NSDistributionNotificationCenter reference
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSDistributedNotificationCenter_Class/Reference/Reference.html#//apple_ref/doc/uid/20000396-BCICEHHB
The NSApplication class automatically suspends distributed notification delivery when the application is not active. Applications based on the Application Kit framework should let AppKit manage the suspension of notification delivery. Foundation-only programs may have occasional need to use this method.
You can either
set the observer's behavior when suspended to NSNotificationSuspensionBehaviorDeliverImmediately using
- (void)addObserver:(id)notificationObserver selector:(SEL)notificationSelector name:(NSString *)notificationName object:(NSString *)notificationSender suspensionBehavior:(NSNotificationSuspensionBehavior)suspendedDeliveryBehavior
or set deliverImmediately to YES when posting
- (void)postNotificationName:(NSString *)notificationName object:(NSString *)notificationSender userInfo:(NSDictionary *)userInfo deliverImmediately:(BOOL)deliverImmediately
to send notifications immediately under suspended state.
And make sure you're not periodically killing distnoted.
I forgot I had an old launch agent script to killall distnoted to avoid memory leaks.
It looks like the default behavior when adding an observer to a NSDistributedNotificationsCenter has changed to NSNotificationSuspensionBehaviorCoalesce, that does not deliver notifications when the app is inactive.
Described here:
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSDistributedNotificationCenter_Class/Reference/Reference.html#//apple_ref/doc/uid/20000396-5567

Resources