I am working on an app that receives a feed that I display in a UIWebView. The feed has embedded links that I want to open in Safari instead of thew WebView. I have looked over several other questions that are posted here. I am not sure what I am missing, but I think it is something simple. Here are my .h and .m files
#import
#class BlogRss;
#interface EnduranceDailyWorkoutViewController : UIViewController {
IBOutlet UIWebView * descriptionTextView;
BlogRss * currentlySelectedBlogItem;
}
#property (nonatomic, retain) UIWebView * descriptionTextView;
#property (readwrite, retain) BlogRss * currentlySelectedBlogItem;
#end
#import "EnduranceDailyWorkoutViewController.h"
#import "BlogRss.h"
#implementation EnduranceDailyWorkoutViewController
#synthesize descriptionTextView = descriptionTextView;
#synthesize currentlySelectedBlogItem = currentlySelectedBlogItem;
- (void)viewDidLoad {
[super viewDidLoad];
NSString *html = [NSString stringWithFormat:#"%# %#",currentlySelectedBlogItem.title, currentlySelectedBlogItem.contentEncoded];
[descriptionTextView loadHTMLString:html baseURL:[NSURL URLWithString:nil]];
}
-(BOOL)webView:(UIWebView *)descriptionTextView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if (UIWebViewNavigationTypeLinkClicked == navigationType) {
[[UIApplication sharedApplication] openURL:[request URL]];
return NO;
}
return YES;
}
Using Interface Builder I have linked the IBOutlet and the UIWebView. Please let me know what I am missing. I have put break points in the webView section but the code never hits there so it is almost like something is not linked correctly in IB.
You need to ensure that the UIWebView's delegate is set to your controller. You can do this in interface builder, or you can modify your viewDidLoad method:
- (void)viewDidLoad {
[super viewDidLoad];
// add this line to set the delegate of the UIWebView
descriptionTextView.delegate = self;
NSString *html = [NSString stringWithFormat:#"%# %#",currentlySelectedBlogItem.title, currentlySelectedBlogItem.contentEncoded];
[descriptionTextView loadHTMLString:html baseURL:[NSURL URLWithString:nil]];
}
Related
This question may seem a little odd/weird, but I have two UIWebViews, one of which is set to hidden in the .xib file, and it's delegate set to my view controller. The 2nd UIWebView is used to parse and "cleanup" the html from the hidden UIWebView and display it as a "mobilized" page to the user. There is no delegate on the non-hidden UIWebView in my .xib file.
The problem I'm having is that when the 2nd UIWebView finishes loading, the user taps on a link within the 2nd UIWebView, and it finishes loading the non parsed webpage because it didn't send this link click back to the hidden UIWebView to be loaded so that the 2nd UIWebView can parse it when it finishes loading. My two UIWebView's are properties in my .m file.
Is there any way I can solve this? I appreciate any responses offered! If i haven't stated my question clearly, please let me know!
Some code:
.h:
#import <UIKit/UIKit.h>
#interface Web : UIViewController <UIWebViewDelegate>
#property (nonatomic, strong) NSURL *url;
#end
.m:
#import "Web.h"
#interface Web()
#property (nonatomic, strong) IBOutlet UIWebView *webView2;
#property (nonatomic, strong) IBOutlet UIWebView *webView;
#property (nonatomic, strong) NSMutableString *output;
#property (nonatomic, strong) NSString *wrapper;
#end
#implementation Web
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
{
if(webView == self.webView2)
{
[self.webView loadRequest:(NSURLRequest*)request];
}
else
{
[self.webView loadRequest:(NSURLRequest*)request];
}
return NO;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.webView loadRequest:[NSURLRequest requestWithURL:self.url]];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
[self cleanUp];
[self.webView2 loadHTMLString:self.output baseURL:nil];
}
- (void)cleanUp
{
NSString *input = [self.webView stringByEvaluatingJavaScriptFromString:#"document.getElementById(\"ctl_ctl_cphBody_cphCenter_divHtml\").innerHTML;"];
NSString *breadcrumbString = [self.webView stringByEvaluatingJavaScriptFromString:#"document.getElementsByClassName('breadcrumb')[0].outerHTML;"];
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
self.wrapper = #"<html><meta http-equiv=\"Content-Type\" content=\"text/html;charset=UTF-8\"/><meta name=\"viewport\" content=\"initial-scale = 1.37,maximum-scale = 2.0\"/></html>";
}
else
{
self.wrapper = #"<html><meta http-equiv=\"Content-Type\" content=\"text/html;charset=UTF-8\"/><meta name=\"viewport\" content=\"initial-scale = 0.57,maximum-scale = 2.0\"/></html>";
}
self.output = [NSMutableString stringWithString:self.wrapper];
[self.output insertString:input atIndex:147];
[self.output replaceOccurrencesOfString:breadcrumbString withString:#"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [self.output length])];
}
You can implement the delegate method
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
This lets you intercept load requests and cancel them. You can then grab the URL from the request and hand it off to your hidden webview. The only caveat is, IIRC, this method will be called even for requests that you load yourself with -loadRequest:, so you'll want to check the navigationType argument.
You should be able to use - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType. Forward the request to the first webView and return NO to prevent the second webView from loading the page.
I know this is a common question but none of the answers fix my problem. I have a UIWebView in my app. I have everything set up correctly; the delegate is set, the webView is a property of my view controller. It is set up to load an html string upon loading the viewController. When the html string loads, in the webViewDidFinishLoad method it checks if this is the first time it loaded, and if it is it is told to load a request with a url. The string i use for the url is a property of my viewController. That string is exactly what it is supposed to be. There is just something preventing the webView from actually loading the request. Any ideas would be very much appreciated. Thank you
#interface WebViewController : UIViewController <UIWebViewDelegate, UIActionSheetDelegate, UIPrintInteractionControllerDelegate, MFMailComposeViewControllerDelegate, NSURLConnectionDelegate>
#property (nonatomic, assign) BOOL firstLoad;
#property (nonatomic, retain) UIWebView *webView;
#property (nonatomic, retain) NSString *prefixURLString;
#property (nonatomic, retain) NSString *suffixURLString;
#property (nonatomic, retain) UIActionSheet *actionSheet;
- (id)initWithTitle:(NSString *)newTitle andSuffixURL:(NSString *)suffix;
- (void)reload;
- (void)addActionButton;
- (void)showActions:(UIBarButtonItem *)sender;
- (void)dismissActionSheet;
#end
#implementation WebViewController
#synthesize webView;
#synthesize prefixURLString;
#synthesize suffixURLString;
#synthesize firstLoad;
#synthesize actionSheet;
- (id)initWithTitle:(NSString *)newTitle withPrefixURL:(NSString *)prefix andSuffixURL:(NSString *)suffix
{
self = [super initWithNibName:nil bundle:nil];
if (self) {
// Custom initialization
[self setPrefixURLString:prefix];
[self setFirstLoad:YES];
[self setTitle:newTitle];
[self setSuffixURLString:suffix];
[self setActionSheet:nil];
}
return self;
}
- (id)initWithTitle:(NSString *)newTitle andSuffixURL:(NSString *)suffix
{
return [self initWithTitle:newTitle withPrefixURL:#"https://customer.stld.com/flatroll/ios/%#" andSuffixURL:suffix];
}
- (void)reload
{
if(self.prefixURLString && self.suffixURLString)
{
NSString *fullURLString = [NSString stringWithFormat:self.prefixURLString, [self.suffixURLString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:fullURLString]]];
}
}
- (void)dealloc
{
[suffixURLString release]; suffixURLString = nil;
[prefixURLString release]; prefixURLString = nil;
[actionSheet release]; actionSheet = nil;
[super dealloc];
}
- (void):(UIWebView *)aWebView didFailLoadWithError:(NSError *)error
{
//NSLog(#"WebViewController:DidFailLoadWithError: %#", [error localizedFailureReason]);
[self setTitle:#"Loading Error"];
[self.webView loadHTMLString:[NSString stringWithFormat:#"<html><head><meta name=\"viewport\" content=\"width=device-width, user-scalable=yes\" /></head><body>Loading error:<br />%#</body></html>", [error localizedFailureReason]] baseURL:nil];
}
- (void)webViewDidFinishLoad:(UIWebView *)aWebView
{
if(self.firstLoad)
{
[self setFirstLoad:NO];
[self reload];
[self addActionButton];
}
}
#pragma mark - View lifecycle
- (void)loadView
{
UIWebView *newWebView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
[newWebView setDelegate:self];
[newWebView setScalesPageToFit:YES];
[newWebView setUserInteractionEnabled:YES];
[self setWebView:newWebView];
[self setView:newWebView];
[newWebView release];
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.webView loadHTMLString:#"<html><head><meta name=\"viewport\" content=\"width=device-width, user-scalable=yes\" /></head><body><br />Gathering data and generating report.<br />Depends on data and parameters you have requested, this could take time. Please wait...</body></html>" baseURL:nil];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
[self.webView setDelegate:nil];
[self setWebView:nil];
[self setView:nil];
}
I had the same problem, I'm not entirely sure why, but I guess it has to do something with viewControllers life cycle. Anyway try load URL in viewDidAppear method. It fixed it for me. Hope it will help
It turns out my problem had nothing to do with the UIWebView. I just had to change the credential persistence in the URLConnectionDelegate I had set up for my app. I had it set as NSURLCredentialPersistanceNone but I changed it to NSURLCredentialPersistenceSession. I hope this can help anyone else out there who had the exact problem as I did
In my app I am using Apple's KMLViewer to show annotations that I get from a KML file.In the file KMLParser.m, there is an instance variable, placemarkDescription that converts the information under Description tags from kml file to annotation subtitle.Now, in my file every annotation has the information stored under Description in this way:
<table width="280px"><tr><td></td><td></td></tr></table><table width="280px"><tr><td><b>Fitness Bulls</b>---Palester sportive. Sporti dhe koha e lire.....<a href="http://www.site.com/BIZ_DIR/810180432/Article-Fitness-Bulls.aspx" style="color:Green;" >Shikoni detajet >></a></td></tr><tr><td><a href="http://www.site.com/HartaV2/AddReview.aspx?gisDataId=8123855e-b798-40bc-ad2e-00346a931211" style="color:Green;" >Shkruani pershtypjen tuaj >> </a> <p style="float:right;">Postuar nga:<i>Import</i></p></td></tr></table>
In KMLParser.m i have transformed the placemarkDescription from that to this:
<html><body>
<table width="280px"><tr><td></td><td></td></tr></table><table width="280px"><tr><td>
<b>Fitness Bulls</b>---Palester sportive. Sporti dhe koha e lire.....
<a href="http://www.site.com/BIZ_DIR/810180432/Article-Fitness-Bulls.aspx" style="color:Green;" >Shikoni detajet >></a></td></tr><tr><td>
<a href="http://www.site.com/HartaV2/AddReview.aspx?gisDataId=8123855e-b798-40bc-ad2e-00346a931211" style="color:Green;" >Shkruani pershtypjen tuaj >> </a> <p
style="float:right;">Postuar nga:<i>Import</i></p></td></tr></table>
</body></html>
I've done this because I want to pas this string to a webView and visualize this in it.
The problem is that when the kml loads, the methods get the description information, get called severe times.Exactly as times as placemarks stored in the kml.So passing the string directly has no effect.If i choose to set active the subtitle option (annotation.subtitle = placemarkDescription in KMLParser), maybe I gen get the subtitle info of the annotation the user tapped, but I don't want to show this information because it shows like this
<table width="280px"><tr><td></td><td></td></tr></table><table width="280px"><tr......
By the way, I don't have any idea of how to get the subtitle info of the selected annotation.
So far, I have managed only to store the description information in an array (done this in the KMLParser.m).But what should I do with that array?How to know to which array entry corresponds the annotation the user tapped (the annotation that has the callout bubble opened).
So I don't know what to do.
Maybe I have not been too clear: What I want to do is get the Description information of a placemark (annotation), when the user taps an annotation in the map, tapping the disclosureButton should redirect him to a webView that shows the description Information.
EDIT code Added:
DetailViewController.h
#import <UIKit/UIKit.h>
#interface DetailViewController : UIViewController<UIWebViewDelegate> {
UIWebView *webView;
UITextField *addressBar;
UIActivityIndicatorView *activityIndicator;
NSString *placemarkDescription;
}
#property (nonatomic, retain) IBOutlet UIWebView *webView;
#property (nonatomic, retain) IBOutlet UITextField *addressBar;
#property (nonatomic, retain) IBOutlet UIActivityIndicatorView *activityIndicator;
#property (nonatomic, retain) NSString *placemarkDescription;
-(IBAction) gotoAddress:(id)sender;
-(IBAction) goBack:(id)sender;
-(IBAction) goForward:(id)sender;
#end
DetailViewController.m
#import "DetailViewController.h"
#implementation DetailViewController
#synthesize webView, addressBar, activityIndicator, placemarkDescription;
- (void)viewDidLoad {
[super viewDidLoad];
[webView loadHTMLString:placemarkDescription baseURL:nil];
}
-(IBAction)gotoAddress:(id) sender {
NSURL *url = [NSURL URLWithString:[addressBar text]];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
[webView loadRequest:requestObj];
[addressBar resignFirstResponder];
}
-(IBAction) goBack:(id)sender {
[webView goBack];
}
-(IBAction) goForward:(id)sender {
[webView goForward];
}
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
if (navigationType == UIWebViewNavigationTypeLinkClicked) {
NSURL *URL = [request URL];
if ([[URL scheme] isEqualToString:#"http"]) {
[addressBar setText:[URL absoluteString]];
[self gotoAddress:nil];
}
return NO;
}
return YES;
}
- (void)webViewDidStartLoad:(UIWebView *)webView {
[activityIndicator startAnimating];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[activityIndicator stopAnimating];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)dealloc {
[super dealloc];
}
#end
PlacemarkAnnotation2.h
#import <Foundation/Foundation.h>
#import <MapKit/Mapkit.h>
#interface PlacemarkAnnotation2 : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString * title;
NSString * subtitle;
NSString * placemarkDescription;
}
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, retain) NSString * title;
#property (nonatomic, retain) NSString * subtitle;
#property (nonatomic, retain) NSString * placemarkDescription;
#end
PlacemarkAnnotation2.m
#import "PlacemarkAnnotation2.h"
#implementation PlacemarkAnnotation2
#synthesize coordinate, title, subtitle, placemarkDescription;
- (id) initWithCoordinate:(CLLocationCoordinate2D)coord andTitle:(NSString *)maintitle andSubtitle:(NSString *)subTitle {
self.coordinate = coord;
self.title = maintitle;
self.subtitle = subTitle;
return self;
}
-(NSString *) placemarkDescription
{
return placemarkDescription;
}
- (void) setPlacemarkDescription: (NSString *) pd
{
placemarkDescription = pd;
}
- (void) dealloc {
[title dealloc];
[subtitle dealloc];
[placemarkDescription dealloc];
[super dealloc];
}
#end
Changes in KMLParser.M
//KMLPoint class
- (MKShape *)mapkitShape
{
PlacemarkAnnotation2 *annotation = [[PlacemarkAnnotation2 alloc] init];
annotation.coordinate = point;
return [annotation autorelease];
}
//KMLPlacemark class
- (void)_createShape
{
if (!mkShape) {
mkShape = [[geometry mapkitShape] retain];
mkShape.title = name;
// Skip setting the subtitle for now because they're frequently
// too verbose for viewing on in a callout in most kml files.
NSString *lessThan = #"<";
NSString *greaterThan = #">";
placemarkDescription = [placemarkDescription stringByReplacingOccurrencesOfString:lessThan
withString:#"<"];
placemarkDescription = [placemarkDescription stringByReplacingOccurrencesOfString:greaterThan
withString:#">"];
NSString *beforeBody = #"<html><body>";
NSString *afterBody = #"</body></html>";
NSString *finalContent = [[beforeBody stringByAppendingString:placemarkDescription]
stringByAppendingString:afterBody];
placemarkDescription = finalContent;
mkShape.placemarkDescription = placemarkDescription;
}
}
Error found in this lines of code (No cause of crash description):
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view
calloutAccessoryControlTapped:(UIControl *)control
{
NSLog(#">>> Entering %s <<<", __PRETTY_FUNCTION__);
DetailViewController *dvc = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:[NSBundle mainBundle]];
PlacemarkAnnotation2 *pa = (PlacemarkAnnotation2 *)view.annotation;
dvc.placemarkDescription = pa.placemarkDescription;
[self presentModalViewController:dvc animated:YES];
[dvc release];
NSLog(#"<<< Leaving %s >>>", __PRETTY_FUNCTION__);
}
It's not clear how much of the KMLViewer sample app code you're using but one way to do this is to create your own annotation class instead of using the MKPointAnnotation class like the sample app does.
The custom class (eg. "PlacemarkAnnotation"), should implement the MKAnnotation protocol or be a sub-class of MKShape (if you are using the KMLViewer code). In the custom class, add a placemarkDescription property.
Where the KMLViewer code currently creates an MKPointAnnotation object, create a PlacemarkAnnotation instead and set its placemarkDescription property instead of the subtitle property.
Then in the viewForAnnotation delegate method, set the rightCalloutAccessoryView to a detail disclosure button.
Next, add to the project a detail view controller with a UIWebView in it. Add a placemarkDescription property to the view controller. In the viewDidLoad method, call loadHTMLString on the web view and pass it placemarkDescription (I think you can pass nil for the baseURL).
In the map view's calloutAccessoryControlTapped delegate method, create the detail view controller, set its placemarkDescription property and present it:
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view
calloutAccessoryControlTapped:(UIControl *)control
{
DetailViewController *dvc = [[DetailViewController alloc] init...
PlacemarkAnnotation *pa = (PlacemarkAnnotation *)view.annotation;
dvc.placemarkDescription = pa.placemarkDescription;
[self presentModalViewController:dvc animated:YES];
[dvc release];
}
Edit:
First, it looks like it will be best to subclass MKShape for your custom class instead of implementing the MKAnnotation protocol. The rest of the KMLViewer code is based on this assumption. So change #interface PlacemarkAnnotation2 : NSObject <MKAnnotation> to #interface PlacemarkAnnotation2 : MKShape. (By the way, for the NSString properties, copy is more appropriate than retain and it'll get rid of warnings.)
It also looks like you may have changed the type of the mkShape ivar in KMLPlacemark (and other places) from MKShape to something else. Change these types back to MKShape.
Next, _createShape might not be the best place to set the placemarkDescription since that method is called for both overlays and annotations. Remove your changes from that method and put them in the point method (also in KMLPlacemark). Note there are a couple of potential memory-related issues with your changes. Here's my suggestion:
- (void)_createShape
{
if (!mkShape) {
mkShape = [[geometry mapkitShape] retain];
mkShape.title = name;
// Skip setting the subtitle for now because they're frequently
// too verbose for viewing on in a callout in most kml files.
}
}
- (id <MKAnnotation>)point
{
[self _createShape];
if ([mkShape isKindOfClass:[PlacemarkAnnotation2 class]])
{
if (placemarkDescription != nil)
//check for nil, otherwise will crash when
//passing to stringByAppendingString below
{
NSString *lessThan = #"<";
NSString *greaterThan = #">";
placemarkDescription = [placemarkDescription stringByReplacingOccurrencesOfString:lessThan
withString:#"<"];
placemarkDescription = [placemarkDescription stringByReplacingOccurrencesOfString:greaterThan
withString:#">"];
NSString *beforeBody = #"<html><body>";
NSString *afterBody = #"</body></html>";
NSString *finalContent = [[beforeBody stringByAppendingString:placemarkDescription]
stringByAppendingString:afterBody];
placemarkDescription = [finalContent retain];
//added retain above since finalContent is autoreleased
//and we are setting the ivar manually. otherwise,
//can result in EXC_BAD_ACCESS later.
}
PlacemarkAnnotation2 *pa2 = (PlacemarkAnnotation2 *)mkShape;
pa2.placemarkDescription = placemarkDescription;
return (id <MKAnnotation>)mkShape;
}
return nil;
}
I'm trying to implement a UIWebViewDelegate in my application and I cannot for the life of me get it to work. I would really appreciate a second set of eyes on this.
I know the name MapViewController is confusing, but the WebView is controlling a map (not UIMapView).
Here's the bulk of the code:
MapViewController.h
#import <UIKit/UIKit.h>
#import <UIKit/UIWebView.h>
#interface MapViewController : UIViewController<UIWebViewDelegate> {
IBOutlet UIWebView *webView;
}
#property (nonatomic, retain) IBOutlet UIWebView *webView;
#end
MapViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
webView.delegate = self;
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"map" ofType:#"html"]isDirectory:NO]];
[webView loadRequest:request];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView{
NSLog(#"Done loading.");
}
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
NSLog(#"hi");
return NO;
}
- (void)dealloc {
webView.delegate = nil;
[webView release]
[super dealloc];
}
Thanks for any help!
Does the initial page you're loading actually display? Are you sure you connected your webview in Interface Builder?
go interface builder , connect the delegate to the file's owner , then it should work.
Open Interface Builder
Right click on the Web View object
Drag the delegate onto files owner.
Things to check:
if map.html is in the bundle. Put it on the root of the bundle, not on resources.
if it is, right click on it, and choose get info. Verify on TARGETS if the target is checked for the file.
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
NSLog(#"hi");
return YES; // for all supported oreintation.
}
Scenario: Need to execute CustomWebview delegate on view controller.
Please help me with this code. Instead of using callback, I need to use "Protocol". Can it be done or we can only use callback in this scenario.
On ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
//MyWebView *webView = [[MyWebView alloc] initWithDelegate:self callback:#selector(finishLoading)];
MyWebView *webView= [[MyWebView alloc] initWithFrame:CGRectMake(0,0,320, 460)];
[webView LoadURL:#"http://192.168.5.165/"];
[webView setDelegate:self];
[webView setCallback:#selector(finishLoading)];
[self.view addSubview:webView] ;
}
- (void) finishLoading
{
NSLog(#"Finish");
}
On MyWebView.h
#interface MyWebView : UIView<UIWebViewDelegate> {
NSString *strURL;
}
#property(nonatomic, retain) NSString *strURL;
#property (nonatomic, assign) id delegate;
#property (nonatomic, assign) SEL callback;
-(void) LoadURL:(NSString*)url;
#end
On MyWebView.m
#import "MyWebView.h"
#implementation MyWebView
#synthesize strURL,delegate,callback;
UIWebView *webView;
-(id) initWithFrame:(CGRect)frame
{
if(self =[super initWithFrame:frame])
{
webView = [[UIWebView alloc] initWithFrame:frame];
webView.delegate = self;
[self addSubview:webView];
}
return self;
}
-(void) LoadURL:(NSString*)url
{
NSURL *u = [NSURL URLWithString:url];
NSURLRequest *req= [NSURLRequest requestWithURL:u];
[webView loadRequest:req];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
[delegate performSelector:callback];
}
Your question is a bit unclear. A protocol and a delegate are two entirely separate, though related, things--apples and oranges. A protocol defines a list of methods an object may or must respond to:
#protocol Document
+ (id)documentWithContentsOfURL: (NSURL *)aURL;
- (void)writeToURL: (NSURL *)aURL error: (NSError **)outError;
#end
A delegate is an object, usually an instance of a custom class, that is handed to another object for custom processing or feedback--that latter object delegates work to the delegate object.
Are you asking how to convert a delegate category on NSObject to a delegate protocol? (The former used to be Apple's pattern for defining the obligations and abilities of a delegate; the latter is the newer way to do the same thing.) If so, it generally looks something like this:
Delegate Category on NSObject
#interface NSObject (WidgetDelegate)
- (void)doSomethingWithWidget: (Widget *)w;
#end
#interface Widget : NSObject
#property (readwrite, assign) id delegate;
#end
Delegate Protocol
#protocol WidgetDelegate <NSObject>
- (void)doSomethingWithWidget: (Widget *)w;
#end
#interface Widget : NSObject
#property (readwrite, assign) id <WidgetDelegate> delegate;
#end
Is that what you're looking for? If not, can you clarify exactly what you're trying to do?
Also see Apple's Communicating with Objects, which discusses delegates, protocols, and selectors. Though its listed under Mac OS X, most (if not all) appears to apply to iOS also.
On ViewController.m
#interface MyViewController : UIViewController<MyFinishLoadingDelegate> {
//your own definition
}
- (void)viewDidLoad
{
[super viewDidLoad];
//MyWebView *webView = [[MyWebView alloc] initWithDelegate:self callback:#selector(finishLoading)];
MyWebView *webView= [[MyWebView alloc] initWithFrame:CGRectMake(0,0,320, 460)];
[webView LoadURL:#"http://192.168.5.165/"];
[webView setDelegate:self];
[self.view addSubview:webView] ;
}
- (void)finishLoading //this is your implementation for MyFinishLoadingDelegate
{
NSLog(#"Finish");
}
On MyWebView.h
//you declare the protocol here to tell anyone who'd like to act like your delegate that they need to implement "finishLoading"
#protocol MyFinishLoadingDelegate <NSObject>
- (void)finishLoading;
#end
#interface MyWebView : UIView<UIWebViewDelegate> {
NSString *strURL;
}
#property(nonatomic, retain) NSString *strURL;
#property (nonatomic, assign) id<MyFinishLoadingDelegate> delegate;
-(void) LoadURL:(NSString*)url;
#end
On MyWebView.m
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
[delegate finishLoading];
}