Re: Running an NSApplication from a test case
Re: Running an NSApplication from a test case
- Subject: Re: Running an NSApplication from a test case
- From: "email@hidden" <email@hidden>
- Date: Wed, 05 Mar 2014 09:50:57 +0000
On 4 Mar 2014, at 21:27, Daniel Luis dos Santos <email@hidden> wrote:
> Hello all,
>
> I have a test case where I would like to launch a UI. I have a NIB with a window that I load through code in the test case. Here goes the code :
>
> - (void)testExample
> {
> NSArray* topLevelWidgets = nil;
>
> NSBundle* theBundle = [NSBundle bundleForClass:[self class]];
> [NSApplication sharedApplication];
>
> Boolean nibLoaded = [theBundle loadNibNamed: @"TestSetOne" owner: [NSApplication sharedApplication] topLevelObjects: &topLevelWidgets];
>
> if (!nibLoaded)
> XCTFail(@"NIB file was not loaded");
>
> [[NSApplication sharedApplication] runModalForWindow:[topLevelWidgets objectAtIndex:2]];
I would use an outlet here rattan indexing the top level objects.
> }
>
> Problem is that the last line does not cause the window in the NIB to appear. If I run the code through the debugger I can see the NSWindow instance that I am passing to the “runModalForWindow”.
>
> What am I doing wrong ?
Is the test case running as a part of a foundation tool?
If this is the case then application runloop isn’t established.
The overview section in the NSPPlication docs has something to say on this:
https://developer.apple.com/library/mac/documentation/cocoa/reference/applicationkit/classes/nsapplication_class/reference/reference.html
The main() function Xcode creates begins by calling a function named NSApplicationMain(), which is functionally similar to the following:
void NSApplicationMain(int argc, char *argv[]) {
[NSApplication sharedApplication];
[NSBundle loadNibNamed:@"myMain" owner:NSApp];
[NSApp run];
}
So try using NSApp as the nib owner and remember to call -run.
I would not try and run the window modally. If you do then calling -stop will only exit the modal run loop, not the application one.
NSApp run will block until -stop is sent. I found the following method did the trick.
/*
- stopApp:
*/
- (void)stopApp:(id)sender
{
#pragma unused(sender)
// will stop run loop after next actual event object dispatched.
// a timer doesn't count here
[NSApp stop:self];
// send a dummy event to trigger stopping
NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined
location:NSMakePoint(0,0)
modifierFlags:0
timestamp:0
windowNumber:0
context:nil
subtype:1
data1:1
data2:1];
[NSApp postEvent:event atStart:YES];
}
.
It may also be necessary to transform the process type to a foreground application in some cases - I don’t quite remember all the detail of this however so you may need to experiment.
/*
transform to foreground application
*/
+ (BOOL)transformToForegroundApplication
{
//
// check if already transformed
//
if ([self isForegroundApplication]) {
return YES;
}
OSStatus osStatus;
ProcessSerialNumber ourPSN;
// get our current process
if ((osStatus = GetCurrentProcess(&ourPSN)) != noErr) {
OSStatusLog(osStatus);
return NO;
}
// transform it into a foreground app
if ((osStatus = TransformProcessType(&ourPSN, kProcessTransformToForegroundApplication)) != noErr) {
OSStatusLog(osStatus);
return NO;
}
// bring it to the front
if ((osStatus = SetFrontProcess(&ourPSN)) != noErr) {
OSStatusLog(osStatus);
return NO;
}
// set system UI mode to limit interaction for this process
SetSystemUIMode(kUIModeNormal, 0);
// sharedApplication will make a connection to the window server
[NSApplication sharedApplication];
isForegroundApplication = YES;
return YES;
}
Jonathan
_______________________________________________
Cocoa-dev mailing list (email@hidden)
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:
This email sent to email@hidden