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.
Related
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.
i have been working on moving one of my apps away from the "shared appdelegate" process which seems to be frowned up, despite its over whelming use. i have been attempting to setup protocol methods for what i want to do but am having zero luck. my question is, can you even have lets say a single viewcontroller send delegate requests to multiple classes? from what im finding out it doesn't seem like you can. which doesn't make sense because i thought that was the whole point of delegates and protocols with mvc. now just to clarify, i know you can have a single viewcontroller act as the delegate for multiple other viewcontrollers. but that's not what i am asking. for a simple example, lets say you have apples flip-utility template. the "done" button just calls a delegate method to the mainvc to dismiss it. now lets say we added a new class called...
#interface NewClass : NSObject <TheOtherDelegate>
and it had a delegate method...
- (void)doSomething
{
NSLog(#"The Delegate did something...");
}
can we have a button on the flipsideviewcontroller, that we wanted to call that delegate method, but still keep the "done" button call to the delegate method on the mainviewcontroller that dismisses it?
that being said, i put together a quicky project just to see if it would work and it doesn't. i came across an "answer" that says you have to instantiate the class first you want to be the delegate...
NewClass *myDelegate = [NewClass alloc] init]
[fillInMethodHere setDelegate:myDelegate];
not sure why it got a correct answer check, because needless to say it doesn't work. is there something i am missing? i scoured ib to see if there is some "delegate" connection somewhere but i couldn't find anything.
on a side note, as i was working in my working project, i read a suggestion about removing the #import and adding #class. again, that broke all kinds of things. the strange thing is before doing that, what i had so far was working and building fine. when i removed the new #class and un-commented the #import. xcode all of a sudden gave me an error "cannot find protocol deceleration for..." but yet, it worked seconds earlier. i would up having to remove the protocol code and re-add it for it to work again. very starge.
any help would be appreciated. everything iv read in docs, google, stack, etc that say something should work, don't in an actual project.
A "delegate" isn't some fancy object. It's simply a synthesized property of type id called delegate. If you wanted to, you could have an arbitrary number of properties that all conformed to the same protocol. Then when you wanted to issue a callback, you would just address all of them:
[self.mydelegateA doSomething];
[self.mydelegateB doSomething];
etc.
You could also have an NSMutableArray property that you could add objects to, and then use [self.myMutableArrayOfDelegates makeObjectsPerformSelector:#selector(doSomething)].
Finally, there's always the route of NSNotificationCenter (not to be confused with push notifications) is a class that provides an inter-object messaging system. Many objects can register for a message that any other object can send.
Please see the Apple's documentation for more information. Click Here.
Regardless of the fact that this is OS X documentation, it's still quite good at explaining things visually: click here.
Here's an example of simply changing the name of the delegate property: click here
And here's an example of adding another protocol and a second delegate: click here
Finally, here's an example that builds on the previous two and has a third delegate that also conforms to the same protocol: click here
Trying to get my head around protocols and delegates when extending it further into the UIKit framework's implementation.
From my understanding of this stackoverflow post a delegate method will usually have Did, Should & Will in it's name.
Based on this, I would assume that - (void)viewDidLoad; declared in UIViewController.h is a delegate method, but of what and from where?
I've looked at UIViewController's header file and it only adhere's to the NSCoding protocol which is a dead end. UIViewController's superclass UIResponder is also a dead end as far as I can see.
I've used viewDidLoad as an example here but this could apply to any of the Did, Should & Will methods in UIViewController.
Is this simply one of those cases that is an exception to the guidelines or am I missing something?
"did", "should", and "will" are words usually used to describe when a method is called, whether it is asking if it "should" do something", giving you a hook to run code before something "will" happen, or as a callback when something "did" happen. these words are usually used in delegate and callback methods.
viewDidLoad is called when your .nib file has been loaded into memory, and your IBOutlets have been instantiated and hooked up, and are ready for configuration. you don't need to worry about calling it yourself if you intend to subclass UIViewController, if that's what you're wondering.
I was checking some video at Lynda.com about iphone development.
The guy was adding custom data to a picker, but to add the data he was not declaring the methods in the header file. He was checking which nethods he needed on the documentation and copying pasting those methods declarations in his controller class.
For exampe this method
-(int) numberOfComponentsInPickerView: (UIPickerView *) pickerView
Why doesn't we need to declare those methods on the header file?
If those methods pertain to the picker class, why do we declare them in the controller class instead of simply calling them in the picker IBOutlet instance?
TIA
When you declare in your header that you follow a certain protocol, you are essentially saying that you agree to implement the methods defined in the protocol.
I'll bet he added something like this to the header:
<UIPickerViewDataSource>
That means that he is implementing the UIPickerViewDataSource protocol.
So, by implementing the UIPickerViewDataSource protocol, you are implying those methods, therefore, they do not need to be prototyped.
If those methods pertain to the picker class, why do we declare them in the controller class instead of simply calling them in the picker IBOutlet instance?
The method you quoted does not belong to the UIPickerView class, but rather to the UIPickerViewDataSource protocol. Your controller acts as a "helper" for the picker, so the picker is calling your controller if it needs to figure out how many components it should display. You are usually not calling this method yourself.
As another answer pointed out, by declaring that you implement the protocol, the methods of that protocol are implicitly declared. By adding <UIPickerViewDataSource> to your interface, you're basically saying "I can act as a data source for a picker view and I'm ready for any picker that wants to call the methods that are declared in the protocol".
I've created my own Delegate for a ObjC class. The class itself deals with Core Data operations. Delegate methods are used to inform other classes about changes that happened to the datastore. The class that deals with the datastore is called Datastore and it's delegate is called DatastoreDelegate. A UIViewController of mine (ContactsViewController) implements the delegate.
My DatastoreDelegate is declared as followed:
#class Datastore;
#protocol DatastoreDelegate <NSObject>;
#optional
- (void)didAddMessage:(Message *)message;
- (void)didUpdateContact:(Contact *)contact;
- (void)didAddContact:(Contact *)contact;
- (void)didUpdateContact:(Contact *)contact;
- (void)didDeleteContacts;
#end
The weird thing is, my code all worked fine with these methods except for the [didAddMessage:] method. Whenever I try to call this delegate from within the Datastore class I get an error from the ContactsViewController. The error tells me the [didAddMessage:] selector is missing in the ContactsViewController instance (Unrecognized selector sent to instance). How can the selector be missing if it's optional?
I should note that my Datastore class is a Singleton. I'm not sure if this is somehow related to this issue I'm having.
"Optional" means the caller is responsible for checking that a target responds to a given selector. E.g.:
if ([_myDelegate respondsToSelector:#selector(didAddMessage:)])
{
[_myDelegate didAddMessage:theMessage];
}
Did you implement didAddMessage: in your ContactsViewController? It's optional so you aren't forced to implement it, but if you send the didAddMessage: message to ContactsViewController but haven't actually implemented it in ContactsViewController, you'll still get a compiler warning. In other words, #optional just means you don't have to implement it, but the compiler may still give a warning if you haven't implemented it but try to use it.
What you might want to do in Datastore is this:
if ([delegate respondsToSelector:#selector(didAddMessage:)]) {
[delegate didAddMessage:theMessage];
}
rather than just:
[delegate didAddMessage:theMessage];
(You'll still get a compiler warning in the first example, but it's safe to ignore since you're checking at runtime to see if the appropriate method is implemented in the delegate.)