Grand Central Dispatch: App crashes on instance member assignment - objective-c

To start with it all works without using the the GCD but I want this happening in a separate thread so trying GCD. I've got a login screen where on pressing the login button i've got the following action:
- (void)login
{
dispatch_queue_t buckyballLoginFetcherQ = dispatch_queue_create("Login Queue", NULL);
dispatch_async(buckyballLoginFetcherQ, ^
{
NSDictionary *resultDictionary = [MyService login:self.name.text password:self.password.text];
self.userDetails = [resultDictionary valueForKey:USER_DETAILS_ATTRIBUTE];
[self performSegueWithIdentifier:#"Login" sender:self];
});
}
In MyService method being called above:
+ (NSDictionary *)executeRequest:(NSDictionary *)requestDictionary
{
// Prepare the URL request and do the following
NSData *results = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&urlRequestError];
// Process results
...
}
NOW the bit that crashes:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"Login"])
{
MyDestinationTableViewController *myDestinationTableViewController = nil;
UITabBarController *tbc = (UITabBarController *)[segue destinationViewController];
for (UIViewController *vc in [tbc viewControllers])
{
if ([vc isKindOfClass:[UINavigationController class]])
{ // in our case all view controlers are navigation controllers :-)
UINavigationController *nc = (UINavigationController *)vc;
if ([[[nc viewControllers] lastObject] isKindOfClass:[BuckyballsTableViewController class]])
{
myDestinationTableViewController = [[nc viewControllers] lastObject];
/**************CRASH LINE************/
buckyballsTableViewController.userDetails = self.userDetails;
}
}
}
}
Again without GCD it works, but it holds up screen so i'd want to do it asynchronously. Is it the instance member causing a problem? OR do i need to use it differently or do more with it? Thank you...

Only the main thread may manipulate the UI, so use this code fragment to call those bits on the main thread:
dispatch_async(dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:#"Login" sender:self];
});

Related

watch os 2 not waking parent app and changing UITableView of parent

I have a watch app that is being updated for watch os 2. The sendmessage does not wake the parent app. According to the transition documentation is this how you would wake a parent in the background.
"The iOS app is always considered reachable, and calling this method from your Watch app wakes up the iOS app in the background as needed."
Has anyone had this problem? The only way to get data is to have the parent app already open.
Another weird thing is the watch app changes the uitableview for the parent app. When the -(IBAction)yesterdaySales:(id)sender is called on the watch, it changes the parent app UITableView instead of the watch tableview.
InterfaceController.m
#import "InterfaceController.h"
#import "MyRowController.h"
#import "ftDateParser.h"
#import WatchKit;
#import <WatchConnectivity/WatchConnectivity.h>
#interface InterfaceController() <WCSessionDelegate>
{
IBOutlet WKInterfaceDevice *it;
BOOL tday;
IBOutlet WKInterfaceLabel *lblCompany;
}
#end
#implementation InterfaceController
#synthesize myTable = _myTable;
- (void)awakeWithContext:(id)context {
[super awakeWithContext:context];
// Configure interface objects here.
if([WCSession isSupported]){
WCSession *session = [WCSession defaultSession];
session.delegate = self;
[session activateSession];
}
//[self requestInfoPhone];
[self getToday];
}
- (void)willActivate {
// This method is called when watch view controller is about to be visible to user
[super willActivate];
}
- (void)didDeactivate {
// This method is called when watch view controller is no longer visible
[super didDeactivate];
}
-(void)requestInfoPhone{
NSDictionary *dic = #{#"request":#"ySales"};
[[WCSession defaultSession] sendMessage:dic
replyHandler:^(NSDictionary *replyInfo){
NSLog(#"The Reply: %#", replyInfo);
NSDictionary *location = replyInfo;
NSString *name = location[#"label"];
NSString *totalSales = location[#"totalSales"];
// NSString *test2 = location[#"rowText"];
NSMutableArray *sales = [[NSMutableArray alloc]init];
NSMutableArray *storeNames = [[NSMutableArray alloc]init];
sales = location[#"rowText"];
storeNames = location[#"storeNames"];
[self loadTable:sales names:storeNames company:name];
[_labelName setText:name];
[_labelTotalSales setText:totalSales];
tday = YES;
}
errorHandler:^(NSError *error){
NSLog(#"%#", error);
}
];
}
-(void)loadTable:(NSMutableArray*)tester names:(NSMutableArray*)names company:(NSString *)company{
[_myTable setNumberOfRows:[tester count] withRowType:#"row"];
[_labelName setText:company];
for (int i = 0; i < [tester count]; i++) {
MyRowController *vc = [_myTable rowControllerAtIndex:i];
[vc.testLabel setText:[ftDateParser currencyFormat: tester[i]]];
[vc.nameLabel setText:[ftDateParser parseName:names[i]]];
}
[_myTable scrollToRowAtIndex:(0)];
}
-(IBAction)yesterdaySales:(id)sender{
if (tday) {
[_ydaySales setTitle:#"Today Sales"];
[self requestInfoPhone];
}
else{
[_ydaySales setTitle:#"Yesterday Sales"];
[self getToday];
}
}
-(void)getToday{
NSDictionary *dic = #{#"request":#"todaySales"};
[[WCSession defaultSession] sendMessage:dic
replyHandler:^(NSDictionary *replyInfo){
NSDictionary *location = replyInfo;
NSString *name = location[#"label"];
NSString *totalSales = location[#"totalSales"];
// NSString *test2 = location[#"rowText"];
NSMutableArray *sales = [[NSMutableArray alloc]init];
NSMutableArray *storeNames = [[NSMutableArray alloc]init];
sales = location[#"rowText"];
storeNames = location[#"storeNames"];
[self loadTable:sales names:storeNames company:name];
[_labelName setText:name];
[_labelTotalSales setText:totalSales];
tday = YES;
}
errorHandler:^(NSError *error){
NSLog(#"%#", error);
}
];
}
#end
Parent.m
-(void)setUpAppForWatch{
done = NO;
if([WCSession isSupported]){
WCSession *session = [WCSession defaultSession];
session.delegate = self;
[session activateSession];
}
}
-(void)session:(WCSession *)session didReceiveMessage:(NSDictionary<NSString *,id> *)message replyHandler:(void (^)(NSDictionary<NSString *,id> * _Nonnull))replyHandler{
/*UIApplication *application = [UIApplication sharedApplication];
__block UIBackgroundTaskIdentifier identifier = UIBackgroundTaskInvalid;
dispatch_block_t endBlock = ^ {
if (identifier != UIBackgroundTaskInvalid) {
[application endBackgroundTask:identifier];
}
identifier = UIBackgroundTaskInvalid;
};
identifier = [application beginBackgroundTaskWithExpirationHandler:endBlock];*/
[self setUpAppForWatch];
[self getTheDate];
startDate = todayDay;
endDate = tomorrow;
//[self getTodaySalesforWatch];
NSString *currency = [ftDateParser currencyFormat:totalSales];
NSDictionary *dic = #{#"label": [NSString stringWithFormat:#"%#", #"Town Crier, Inc."],
#"totalSales": currency,
#"rowText": storeSalesData,//[NSString stringWithFormat:#"%#", currency]
#"storeNames":storeNames
};
NSString *request = [message objectForKey:#"request"];
if ([request isEqualToString:#"todaySales"]) {
[self getTodaySalesforWatch];
}
else if ([request isEqualToString:#"ySales"]){
[self connectToWebService];
}
if (done) {
replyHandler(dic);
}
}
Edit:
Maybe the changes to the parent app were happening before, but I didn't know cause the app was running in the background. Still can't get it to wake the parent app.
You don't link to the source of the quote at the top of your question but it must be referring to the openParentApplication method of WatchKit 1. Devices running WatchOS 2.0 cannot call openParentApplication.
The method you're implementing in the code in your question is for a WCSession, which only works for immediate communication between a WatchKit app extension and an iOS app that are both running at the same time. This method does not cause your iOS app to launch, neither in the background nor in the foreground. Other asynchronous communication methods must be used if both apps are not running at the time.

Data Doesn't Load Unless UIButton Clicked

This might be a strange case so I apologize in advance if my problem or solution is unclear:
I have a LoginViewController that fetches a users Facebook profile picture, username, email, etc. I then have it segue to a HomeViewController that displays some objects, other items, and a UIView that shows the users profile picture.
The strange part is that the UIImage that i create only gets transferred when I use a UIButton. I can not seem to get the image to be sent to the HomeViewController any other way. I even set up a GCP to have it try and wait in order for Facebook to deliver the information - still nothing. Below is the code that I have for the LoginViewController.m. If anyone has any idea on why this is happening I would be extremely grateful. thank you!
#import "LoginViewController.h"
#import <QuartzCore/QuartzCore.h>
#interface LoginViewController ()
- (void)toggleHiddenState:(BOOL)shouldHide;
#end
#implementation LoginViewController
#synthesize profPicture;
- (void)viewDidLoad {
[super viewDidLoad];
[self toggleHiddenState:YES];
self.lblLoginStatus.text = #"";
self.loginButton.readPermissions = #[#"public_profile", #"email"];
self.loginButton.delegate = self;
// Do any additional setup after loading the view.
}
-(void)toggleHiddenState:(BOOL)shouldHide{
self.lblUsername.hidden = shouldHide;
self.lblEmail.hidden = shouldHide;
self.profilePicture.hidden = shouldHide;
self.loggedinwallpaper.hidden = shouldHide;
self.FBlogout.hidden = shouldHide;
}
-(void)loginViewShowingLoggedInUser:(FBLoginView *)loginView{
self.lblLoginStatus.text = #"";
[self toggleHiddenState:NO];
}
-(void)loginViewShowingLoggedOutUser:(FBLoginView *)loginView{
self.lblLoginStatus.text = #"";
[self toggleHiddenState:YES];
}
-(void)loginViewFetchedUserInfo:(FBLoginView *)loginView user:(id<FBGraphUser>)user{
NSLog(#"%#", user);
self.profilePicture.profileID = user.objectID;
self.lblUsername.text = user.name;
self.lblEmail.text = [user objectForKey:#"email"];
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(void){
// Create Facebook Profile Picture from User ID url
NSString *pic_link = [NSString stringWithFormat:#"http://graph.facebook.com/%#/picture?width=300&height=300", user.objectID];
NSURL *pic_url = [NSURL URLWithString:pic_link];
profPicture = [UIImage imageWithData: [NSData dataWithContentsOfURL:pic_url]];
dispatch_async(dispatch_get_main_queue(), ^(void){
//Main Thread : UI Updates
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *homeViewController = (UIViewController *)[storyboard instantiateViewControllerWithIdentifier:#"HomeViewController"];
[self performSelector:#selector(prepareForSegue:sender:) withObject:nil afterDelay:1.0 ];
[self presentViewController:homeViewController animated:YES completion:nil];
});
});
}
-(void)loginView:(FBLoginView *)loginView handleError:(NSError *)error{
NSLog(#"%#", [error localizedDescription]);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
HomeViewController *homeviewController = segue.destinationViewController;
homeviewController.homepic = profPicture;
}
#end
From the code you shared I'd assume that the button you mentioned worked because you wired that up in the Storyboard with a segue, right? (Dragged an arrow to the next VC?)
The issue with your code is that here
[self performSelector:#selector(prepareForSegue:sender:) withObject:nil afterDelay:1.0 ];
you are triggering prepareForSegue:sender: on your own without the necessary parameters - you don't have a segue to prepare for as you aren't even segueing to the other view controller. So when HomeViewController *homeviewController = segue.destinationViewController; is executed segue is nil so the image can't be set.
You should be able to fix this by replacing your code which runs on the main thread with this:
dispatch_async(dispatch_get_main_queue(), ^(void){
// Main Thread : UI Updates
[self performSegueWithIdentifier:#"<insert segue identifier here>" sender:self];
});
Make sure to set a name in your Storyboard for the segue between the view controllers and use that identifier here. (See the Apple Docs)
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
HomeViewController *homeviewController = segue.destinationViewController;
homeviewController.homepic = [UIImage alloc] init];
homeviewController.homepic = profPicture;
}

Unable to "pop" view controller using "Show" segue in XCode 6

I have an app that allows you to scan a QR code for meta data. The root view controller has two text fields, and allows you to fill one of those fields with the scanner. The button to access the scanner uses the "Show" segue to push the Scanning view onto the navigation stack.
My intention is that once a valid scan has been completed, the view controller will pass data back to the parent controller, and then be removed.
Being that the view has been pushed, I should be able to implement popViewControllerAnimated, but this does not work. I have also tried iterating through the view controllers in the navigation stack, matching the class I'm trying to pop to and using popToViewController, but am still stuck with the view that I'm trying to pop off the stack.
My viewcontroller.m
#interface ScanQRViewController ()
#end
#implementation ScanQRViewController
#synthesize scanPreview, scanPreviewLayer, scanSession, addyString, delegate;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
scanSession = nil;
[self startScanning];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark QR code scanning
-(void)startScanning {
addyString = nil;
NSError *error;
// create capture device and input
AVCaptureDevice *capDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:capDevice error:&error];
// error checking
if(!input) {
NSLog(#"%#", [error localizedDescription]);
}
// init the capture session
scanSession = [[AVCaptureSession alloc] init];
[scanSession addInput:input];
AVCaptureMetadataOutput *metaOutput = [[AVCaptureMetadataOutput alloc] init];
[scanSession addOutput:metaOutput];
// assign to dispatch queue
dispatch_queue_t dispatchQueue;
dispatchQueue = dispatch_queue_create("qrQueue", NULL);
[metaOutput setMetadataObjectsDelegate:self queue:dispatchQueue];
[metaOutput setMetadataObjectTypes:[NSArray arrayWithObject:AVMetadataObjectTypeQRCode]];
// create camera view for user
scanPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:scanSession];
[scanPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
[scanPreviewLayer setFrame:scanPreview.layer.bounds];
[scanPreview.layer addSublayer:scanPreviewLayer];
// start running sesssion
[scanSession startRunning];
}
- (void)stopScanning {
[scanSession stopRunning];
scanSession = nil;
[scanPreviewLayer removeFromSuperlayer];
}
#pragma mark AV Delegate Methods
-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
// check for objects
if (metadataObjects != nil && [metadataObjects count] > 0) {
//get the last object
AVMetadataMachineReadableCodeObject *metaObj = [metadataObjects objectAtIndex:0];
if([[metaObj type] isEqualToString:AVMetadataObjectTypeQRCode]) {
// remove url string if exists
if ([[[metaObj stringValue] substringToIndex:9] isEqualToString:#"zetacoin:"]) {
addyString = [[metaObj stringValue] substringFromIndex:9];
} else {
addyString = [metaObj stringValue];
}
}
[self stopScanning];
[self dismissView];
}
}
#pragma mark - Navigation
- (void)dismissView {
[delegate ScanQRCodeDidFinish:self];
[self.navigationController popViewControllerAnimated:YES];
}
#end
So I figured out the issue to this problem. Essentially when passing the data back to the parent controller to the delegate, I wasn't on the main thread. Therefore it would eventually timeout and return to the view, but very slowly. My two views:
QRScanner.m < The scanning view
#interface ScanQRViewController ()
#end
#implementation ScanQRViewController
#synthesize scanPreview, scanPreviewLayer, scanSession, addyString, delegate;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
scanSession = nil;
[self startScanning];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark QR code scanning
-(void)startScanning {
addyString = nil;
NSError *error;
// create capture device and input
AVCaptureDevice *capDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:capDevice error:&error];
// error checking
if(!input) {
NSLog(#"%#", [error localizedDescription]);
}
// init the capture session
scanSession = [[AVCaptureSession alloc] init];
[scanSession addInput:input];
AVCaptureMetadataOutput *metaOutput = [[AVCaptureMetadataOutput alloc] init];
[scanSession addOutput:metaOutput];
// assign to dispatch queue
dispatch_queue_t dispatchQueue;
dispatchQueue = dispatch_queue_create("qrQueue", NULL);
[metaOutput setMetadataObjectsDelegate:self queue:dispatchQueue];
[metaOutput setMetadataObjectTypes:[NSArray arrayWithObject:AVMetadataObjectTypeQRCode]];
// create camera view for user
scanPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:scanSession];
[scanPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
[scanPreviewLayer setFrame:scanPreview.layer.bounds];
[scanPreview.layer addSublayer:scanPreviewLayer];
// start running sesssion
[scanSession startRunning];
}
- (void)stopScanning {
[scanSession stopRunning];
scanSession = nil;
[scanPreviewLayer removeFromSuperlayer];
}
#pragma mark AV Delegate Methods
-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
// check for objects
if (metadataObjects != nil && [metadataObjects count] > 0) {
//get the last object
AVMetadataMachineReadableCodeObject *metaObj = [metadataObjects objectAtIndex:0];
if([[metaObj type] isEqualToString:AVMetadataObjectTypeQRCode]) {
// remove url string if exists
if ([[[metaObj stringValue] substringToIndex:9] isEqualToString:#"zetacoin:"]) {
addyString = [[metaObj stringValue] substringFromIndex:9];
} else {
addyString = [metaObj stringValue];
}
}
[self stopScanning];
[self dismissView];
}
}
#pragma mark - Navigation
- (void)dismissView {
NSLog(#"%#", self.navigationController);
[delegate ScanQRCodeDidFinish:self];
}
#end
AddAddress.m < The view I was trying to return to
#import "AddAddressViewController.h"
#import "ScanQRViewController.h"
#interface AddAddressViewController ()
#end
#implementation AddAddressViewController
#synthesize nameField, addressField, addressText;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.navigationController.navigationItem.backBarButtonItem.title = #"Back";
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)viewWillAppear:(BOOL)animated {
// check to see if there's an address (QR) add to text field
if (addressText != nil) {
addressField.text = addressText;
NSLog(#"Address: %#", addressText); // debugging
}
}
#pragma mark delegate methods
- (void)ScanQRCodeDidFinish:(ScanQRViewController *)sqrvc {
if (![NSThread isMainThread]) {
dispatch_sync(dispatch_get_main_queue(), ^{
addressField.text = sqrvc.addyString;
[self.navigationController popViewControllerAnimated:YES];
});
} else {
addressField.text = sqrvc.addyString;
[self.navigationController popViewControllerAnimated:YES];
}
}
#pragma mark - Navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
ScanQRViewController *sqvc = [segue destinationViewController];
sqvc.delegate = self;
}
#end
By adding the dispatch_sync(dispatch_get_main_queue(), ^{ it executed on the main thread and returned back the view as expected.

UIWebView display PDF and hide gray shadow in iOS7

I'm trying to remove/hide the shadow from an UIWebView that displays a PDF in iOS7.
I've tried all solutions on stackoverflow and also others from the Internet, but it doesn't work.
Maybe it's because I'm using NSURLSession to load a PDF from a server and then display it.
Right now it looks like this:
My first guess was that it doesn't work because the NSURLSession delegates are not on the main thread but even if I remove the subviews (that contain the shadow) on the main thread and call setNeedsDisplay it doesn't change.
I'm starting a DownloadTask and when the task is finished and the delegate gets called I remove the layers.
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location {
NSData *data = [NSData dataWithContentsOfURL:location];
[self.webView loadData:data MIMEType:#"application/pdf" textEncodingName:#"utf-8" baseURL:nil];
// remove shadow layers from scrollview
dispatch_async(dispatch_get_main_queue(), ^{
self.webView.scalesPageToFit = YES;
for (UIView* subView in [self.webView subviews])
{
if ([subView isKindOfClass:[UIScrollView class]]) {
for (UIView* shadowView in [subView subviews])
{
if ([shadowView isKindOfClass:[UIImageView class]]) {
[shadowView setHidden:YES];
}
}
}
}
[self.webView.layer setNeedsDisplay];
});
}
Even if a remove the GCD async block and it's executed in the same thread it doesn't change anything. I've also tried to call it in viewDidLoad and viewDidAppear.
Any tips are highly appreciated!
- (void)webViewDidFinishLoad:(UIWebView *)webView {
for (UIView *object in webView.scrollView.subviews) {
if ([NSStringFromClass([object class]) isEqualToString:#"UIWebPDFView"]) {
UIView *pdfView = object;
for (UIView *pdfObjectSubview in pdfView.subviews) {
if ([NSStringFromClass([pdfObjectSubview class]) isEqualToString:#"UIPDFPageView"]) {
UIView *uiPDFPageView = pdfObjectSubview;
uiPDFPageView.layer.shadowOpacity = 0.0f;
}
}
}
}
}

Receiving Drag events on an NSWindow when the window contains a single WebView view

I am new to objective-c and cocoa so please break things down for me. I'm working on a project started by another developer and have only been working in objective-c for 3 days.
I have an NSWindow subclass that contains a WebView view. The WebView content that is loaded is a Silverlight plugin. I registered the NSWindow to receive Drag events. The drag events are being generated but only when the drag occurs within the NSWindow Title Bar. I register for the drag events in the load method.
AdminWindow.mm
#import "AdminWindow.h"
#import "NativeMessageReceiver.h"
extern AdminWindow* adminRiaWindow;
#implementation AdminWindow
#synthesize adminWebView;
BOOL isAdminContentLoaded;
-(void) load
{
if (!isAdminContentLoaded)
{
NSLog(#"loading Admin window");
NSString *curDir = [[NSBundle mainBundle] bundlePath];
NSString* url = [NSString stringWithFormat: #"file://%#/Contents/Resources/RIA/AdminContentMac.html",curDir];
[[adminWebView mainFrame] loadRequest: [NSURLRequest requestWithURL: [NSURL URLWithString: url]]];
[adminWebView setDrawsBackground:NO];
id win = [adminWebView windowScriptObject];
NativeMessageReceiver* receiver = [NativeMessageReceiver getInstance];
[win setValue:receiver forKey:#"NativeMessageReceiver"];
receiver.adminWebView = adminWebView;
isAdminContentLoaded = YES;
}
}
-(void) show
{
[self load];
[self setIsVisible: YES];
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
[self makeKeyAndOrderFront: self];
[self makeMainWindow];
[self center];
}
-(void) hide
{
[self setIsVisible: NO];
}
- ( BOOL ) windowShouldClose : ( id ) sender
{
[self setIsVisible: NO];
return NO;
}
- (BOOL) canBecomeKeyWindow
{
return YES;
}
- (BOOL) canBecomeMainWindow
{
return YES;
}
#end
extern "C" void ShowAdminWindow()
{
NSLog(#"showing Admin window");
if (![NSThread isMainThread])
[adminRiaWindow performSelectorOnMainThread:#selector(show) withObject:nil waitUntilDone:YES];
else
{
[adminRiaWindow show];
}
}
extern "C" void HideAdminWindow()
{
if (![NSThread isMainThread])
{
[adminRiaWindow performSelectorOnMainThread:#selector(hide) withObject:nil waitUntilDone:YES];
}
else
{
[adminRiaWindow hide];
}
}
CustomeWebView
#implementation SteamPunkWebView
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
[self registerForDraggedTypes:[NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
NSLog(#"In Custom View Init");
}
return self;
}
I think you're only getting drag events in the title bar because you registered the window to receive the events, not the web view.
Try this instead:
[self.adminWebView registerForDraggedTypes:[NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
WebViews are one of the most complex views in Cocoa and are a special case when it comes to dragging. Instead of implementing the standard NSView dragging behaviour, you need instead to set an object as the web view's WebUIDelegate and implement the following delegate method:
‑webView:dragDestinationActionMaskForDraggingInfo:
You can then control how you want the web view to respond to the drag action. The WebUIDelegate protocol has several other methods to control dragging, so you should read the documentation for more detail.
To actually receive the dragged objects and process them, you will need to subclass WebView and implement ‑draggingEnded:.
You definitely do not need to add any dragging methods to the window itself.