How to call webviewdidfinishload delegate method of web view in cocoa? - cocoa-touch

I am using the WebViewDidFinishLoad delegate Method of WebView, but it is not getting called. Whenever I run the application and load request in a WebView.
Please tell me, how to call the method and which delegate I need to connect with the file owner.
Any help will be appreciated.
Thanks in advance.

You said in a comment on another answer:
- (void)webViewDidFinishLoad:(WebView *)webView{ NSLog(#"hello");}
This method is not getting called.
That's because there is no such method.
WebView and UIWebView are not the same thing. The former is in the WebKit framework on the Mac; the latter is in the UIKit framework on iOS. WebView is not available on iOS and UIWebView is not available on the Mac.
UIWebView is a very stripped-down version of WebView. In particular, UIWebView has only one delegate protocol, of which webViewDidFinishLoad: is one of its methods, whereas WebView has no fewer than six delegate protocols.
webViewDidFinishLoad: only exists in the UIWebViewDelegate protocol, in the UIKit framework for iOS apps. Implementing it in a Mac application will achieve nothing, because nothing will call it.
Please tell me how to call the method …
That will do you no good, because the whole point of implementing it is to find out when a load has finished. For you to call it yourself, you would need to know when to call it—i.e., when a load has finished. To know that, you would need to be told that a load has finished by WebKit. This is, as they say in logic, begging the question.
The correct solution is to set the correct delegate to an object that conforms to the correct delegate protocol and implements the correct method. The correct delegate is the WebView's frame load delegate. Accordingly, the correct protocol is the WebViewFrameLoadDelegate protocol. The correct method within that protocol that your frame load delegate must implement is the webView:didFinishLoadForFrame: method.
Cocoa Touch programmers with the same problem (webViewDidFinishLoad: not getting called) should make sure that their UIWebView's delegate is set to the correct object. If you're setting it in code, make sure you're talking to the correct web view—i.e., that your outlet to the web view is connected (if it's in a nib or storyboard), that you're loading the nib or storyboard (if it's in one), and that you're not clobbering the value of the outlet with a different web view (one from the nib, then one created in code, or vice versa).

Try to add (And replace the myUIWebView with your UIWebView outlet name):
[myUIWebView setDelegate:self];
And in the header file, add <UIWebViewDelegate>, so you can use this methods:
-(void)webViewDidStartLoad:(UIWebView *)webView {
}
-(void)webViewDidFinishLoad:(UIWebView *)webView{
}

First Bound ResourceDelegate of webview with file Owner
(void)webView:(WebView *)sender resource:(id)identifier didFinishLoadingFromDataSource:(WebDataSource *)dataSource
This will work for me perfectly.

Related

AppDelegate instantiated last on launch

I'm very comfortable with writing iOS apps, but OS X unexpectedly seems somewhat alien.
Here's the question upfront (read on for context):
When my application launches using the .xib set in the Main Interface field under the deployment info of my apps target, why does the AppDelegate get instantiated after the ViewControllers?
Context (no pun intended):
The reason I ask is because I'm using Core Data (spare me any heckling for this decision), and typically you keep a pointer to the MOC (Managed Object Context) in AppDelegate. One of my controllers is trying to get this MOC instance variable but the AppDelegate instance isn't around yet and therefore my app doesn't present data just after launch.
The AppDelegate and the two ViewControllers are in the .xib. The VCs are hooked to views inside a split view. They're trying to use the MOC in viewDidLoad to make queries. They are accessing the AppDelegate like this:
let delegate = NSApplication.sharedApplication().delegate as AppDelegate
let moc = delegate.managedObjectContext
This will crash as the .delegate property of the sharedApplication() returns nil.
I tried making an NSWindowController from the .xib in applicationDidFinishLaunching and removing the .xib from the Main Interface field, but then applicationDidFinishLaunching doesn't get called at all.
I've ensured that all the connections in IB for from the Application and the Files Owner (NSApplcation) delegate IBOutlets to the AppDelegate have been made.
UPDATE - 31/03/15
Stephen Darlington's answer below offers a good solution for my/this case. And as I understand it's actually better to setup the MOC in the way he's suggested.
If a correct answer arrives that explains why the AppDelegate is being instantiated at some later time in the launch process, I'll mark it correct instead of Stephen's. Thanks Stephen!
The "easy" solution would be to have managedObjectContext create a MOC if one doesn't exist (i.e., change it from a property to a method). That way which ever code gets there first the stack will be available.
(I'll spare the lectures about both creating the Core Data stack in the app delegate and accessing the app delegate like that!)
Here's another option without having to subclass NSApplication:
Don't put your view controllers in the .xib that you set as the Main Interface, just have the Main Menu (menu bar), AppDelegate and Font Manager in there.
Then make your view controllers in other .xibs.
Then in the applicationDidFinishLaunching method init your view controllers from their .xib files.
I also faced this issue with setting up Parse. To get around it, I simply subclassed NSApplication and set it as the Principle class in the Info.plist. In your NSApplication subclass, override the init methods and initialise Parse or anything else you need to, there.

How to use methods in a informal protocol in Objective C

I am learning to program a simple Web Browser Mac App in Objective C. I have a simple textfield as an address bar and a Webview. As such, I wish to update the address the website in the textfield whenever the page changes when I click a link.
After googling, I realise I could use a method
didStartProvisionalLoadForFrame
in the WebFrameLoadDelegate Protocol. I then proceed to type
#interface AppDelegate : NSObject <NSApplicationDelegate,WebFrameLoadDelegate>
which resulted in an error. After further search I found out that is due to WebFrameLoadDelegate being an informal Protocol.
My question is then this: What is the syntax for using the method below specified by the informal Protocol?
- (void)webView:(WebView *)webView didFinishLoadForFrame:(WebFrame*)frame;
With an informal protocol, you implement the methods without declaring conformation to a protocol. WebFrameLoadDelegate is not a type, just the name of an NSObjectcategory.
They exist because, previously, there was no way to specify that a method in a protocol was optional (the #optional and #required keywords did not exist.) When the requisite keywords were added to Objective-C, Apple started moving to formal protocols with optional methods, which makes for better type safety and self-documenting code.
If you're manually creating a webview, then just set your own class as the delegate as following [webview setDelegate:self]. But if you made the webview in IB instead, you can link the delegate there instead.
Once you set your class as the delegate of the webview, you can just implement that method without any extra code.
- (void)webView:(WebView *)webView didFinishLoadForFrame:(WebFrame*)frame
{
//Do stuff here.
}
And the WebView will simply call your method whenever it finishes loading a frame.
If you want to know how this works, it all goes back to the construction of a delegate. WebView will check if delegate is nil or not. If it's not, then it will call respondsToSelector: to check if the delegate has implemented the delegate method. An informal delegate is just an old way of allowing optional protocol method, which shouldn't be used anymore as stated by #JonathanGrynspan
And if you didn't know, you don't have to explicitly declare that your class confirms to a protocol (even if it's not informal) if you connect it in IB.
By the way, if you're working on a webview, check out Apple's development guide on it. It gives you a step-by-step tutorial on creating the basics of a webview including when to change the webview's URL address.

Communication between UIViewControllers

I am new with Objective-C so apologies for a dumb question.
I am opening an "options" view controller from my main view controller. Both are built in the storyboard. Before and after presenting the options controller I need to stop and start a timer on my main view controller. After the options controller is closed (a button calls dismiss) I need to send some info back to my main controller or at least let my main controller know that it needs to refresh some values.
MAIN QUESTION
What's the best way of presenting a view controller and executing some presenter's methods before and after opening?
WHAT I'VE TRIED
I found a few ways to do it, but they are all cumbersome and I assume that there must be some plausible way of doing it.
Ideally I'd like to use the segue I set up in the storyboard between the two controllers.
I managed to call the options controller programmatically by accessing the storyboard and calling instantiateViewControllerWithIdentifier. It worked but looks a bit complex.
I was not able to find a delegate method on the UIViewController to handle the dismiss event
When I was trying to access the main controller in the options controller via presentingViewController and downcasting it, I got a linkage error by including my .h file twice (not sure what are the Obj-C standards of using #define).
Appreciate your help...
For communication between ViewControllers that are weakly linked, you could use the NSNotificationCenter:
https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/Reference/Reference.html
Here you can send a message to all ViewControllers listening, which need to process some changes (for example an option to change the font size).
It's really easy to implement and it keeps certain ViewControllers less dependent on each other.
All of this can be done quite easily with storyboard and NSNotificationCenter, and NSCoding. In the viewDidLoad method of your main controller, put this code:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveNotification:)
name:#"Update"
object:nil];
Then create this method in the same controller:
(void)receiveNotification:(NSNotification*)notification
{
//...
}
When you want to make the main controller update from the options controller:
[[NSNotificationCenter defaultCenter] postNotificationName:#"Update" object:self];
Also, I would suggest using NSArchiving for Basic Data Persistence. Just found this tutorial, looks pretty good.
http://samsoff.es/posts/archiving-objective-c-objects-with-nscoding
Basically, create an object that can store information, code it using nscoding, and then uncode it whenever you need it. It has worked great for me.
Hope that helps!
MAIN QUESTION What's the best way of presenting a view controller and executing some presenter's methods before and after opening?
Just in case the answers above are a bit more involved than you'd like, I'll suggest that the easiest way to execute a presenter's methods before opening is to do so in the presenter's prepareForSegue method. If you need to send data to the destination view controller, you can access its properties this way:
ViewController *destinationVC = [segue destinationViewController];
An easy way to execute the presenter's methods after opening would be:
ViewControllerSubclass *previousVC = [self presentingViewController];
And then use the class or instance to execute your class or instance methods. You could do this in the destination's viewWillAppear.
Sorry if you already knew all this; it's often difficult to surmise what level of complexity is needed.
I have run into this with almost every app I have on the market. Difference is I have never decided to go down the storyboard path.
The way I have always been able to accomplish this is to provide accessor functions between the controllers. You get past the linker issue by defining the cross defined controller as simply a UIViewController type within your options view header, then including the main view controller' header only in the .m file. Now when you call a main view controller routine from your options view, you will have to cast it to the type of your main view controller!
You will also have to provide a routine in your options view that will allow you to set the variable that will hold a pointer to your main view controller to self.
Example for your optionsView
#interface optionsViewController : UIViewController{
UIViewController * myReactiveMainViewController;
}
-(void)setMyReactiveMainViewController:(UIViewController *)controller;
No in the .m file for the optionsView
#import "myMainViewController.h"
-(void)setMyReactiveMainViewController:(UIViewController *)controller{
myReactiveMainViewController = controller;
}
In any other call back to the main view controller you will have to do this:
-(void)returnToMain{
[(myMainViewController *)myReactiveMainViewController someCall:variable];
}
This example would of course assume that your myMainViewController implements a method called "someCall" that take on input parameter.
Thanks for replies.
I ended up with
Calling prepareForSegue to execute pre-transition code
Calling performSelector on presentingViewController when releasing presented view controller.
I am sure other suggestions would work too.

how to handle “sendDidFinish” in sharekit

I use sharekit with mail/twitter/facebook and I am really new to objective-c. sharekit works well and sends my images like it should.
in my app I have a screenshot function. I want the app to 'freeze' when a screenshot is taken, stopping to send any shake- or touch-event to the scene behind the sharekit-action.
in my screenshot-layer I have three buttons which call the shareItem-methods of their specified service, like
[SHKTwitter shareItem:item];
vereything works fine 'till here. but now when the sending is finished (or canceled or errored) I need the app to 'unfreeze', sharekit should tell my app that it is allowed to listen to any touch- or shake-action again.
I am sorry but I think I don't understand the concept of using the delegate here. I mean, is 'sendDidFinish' meant to be inside a delegate? and if so, how could I tell sharekit who is its delegate? or do I have to edit the send-service classes (like SHKItem or SHKFacebook) itself?
please don't downrate me for this question. I really want to get behind this mystery...
SHKTwitter inherit from SHKOAuthSharer, who inherit from SHKSharer. SHKSharer has a delegate protocol called "SharerDelegate".
So you can use an instance of SHKTwitter, then set it's delegate as :
shkTwitterInstance.shareDelegate = yourDelegateObject.
And implement the delegate method
- (void)sharerFinishedSending:(SHKSharer *)sharer;.
Try that.
EDIT (OTHER, AND MORE POPULAR, SOLUTION)
Also, you can suscribe your object to "SHKSendDidFinish" notification from SHKTwitter object.
[[NSNotificationCenter defaultCenter] addObserver:yourObject selector:#selector(theMethodthatYouWantToExecuteWhenTheNotificationIsRaised:) name:#"SHKSendDidFinish" object:shkTwitterObject];

How can I initialize a custom GUI class?

I'm developing an iPad app.
Now I ran into the following problem. I created a "Custom Class" for a UIScrollView. So in my nib file I have added a default UIScrollView and set the Custom Class to MultiSelectView (which is the custom class I created). Screenshot here.
So in my MultiSelectView I have added some methods that I want to use. This works!
The issue is that I'm wondering how I can initialize certain objects that I need in these methods. It seems like - (id)initWithFrame:(CGRect)frame {} is not called, and neither is - (void) viewDidLoad {}.
Thus, is there a way to initialize a custom (GUI) class?
When you unarchive a view from a .xib file, it is not sent -initWithFrame:, as you've noticed. Instead, it's sent -initWithCoder:.
So, if you've got any UIView subclass in a .xib file that needs custom initialization, you'll need to override -initWithCoder: as well as (or instead of) -initWithFrame:.
Looks like you need initWithCoder, it is called when object is loaded from NIB
Or, better, awakeFromNib. The difference is that awakeFromNib is called when all outlets are connected.