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];
}
Related
I have a function that returns a NSUrl, and i want to use it in another class. But when i tried to retrieve it in my other class, it gives me null.
This is my First Class
#interface UOEventDetailController : UIViewController {
NSURL *imgData;
}
#property(nonatomic, retain)NSURL *imgData;
-(NSURL *)imgData;
#implementation UOEventDetailController
#synthesize imgData;
The .m File
-(NSURL *)imgData{
UOEventPost *post = (UOEventPost *)self.event;
NSURL *url = [NSURL URLWithString:post.postImageURL];
return url;
}
I want to retrieve the URL in this class
#class UOEventDetailController;
#interface UOEnlargeImageViewController : UIViewController {
IBOutlet UIImageView *enlargedImage;
}
#property (nonatomic, retain) UOEventDetailController *controller;
#property (nonatomic, retain) IBOutlet UIImageView *enlargedImage;
the .m file
#implementation UOEnlargeImageViewController
#synthesize controller;
#synthesize enlargedImage;
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"Enlarged Image";
controller = [[UOEventDetailController alloc]init];
NSURL *url = [controller imgData];
NSLog(#"%#",url);
}
#end
I can retrieve objects other than post.postImageUrl.
For Example
instead of post.postImageUrl, i put in string like #"omg", #"god"
it gets retrieved in my other class...
EDIT
-(IBAction)enlargeImg{
UOEventPost *post = (UOEventPost *)self.event;
UOEnlargeImageViewController *enlarge = [[UOEnlargeImageViewController alloc]initWithNibName:nil bundle:nil];
enlarge.temp = post.postImageURL;
[self.navigationController pushViewController:enlarge animated:YES];
[suggestPopupView removeFromSuperview];
[enlarge release];
}
this is because you are making a new object. and that of new object, relevent attributes are empty and hence url is also null.
The Object will be null as a new object is being created and it's not in same state as you want it , you must use protocol & delegate to pass the object to another class if flow is backward else ensure that you work on the same object.
I have started working more with delegate as suggested in another question I made. Now, I have made a UIViewController called ProfileViewController in which I would like to load the News Feed from Facebook. I also have subclass of NSObject called FBFeed. This subclass loads the Facebook News Feed and should pass it back to the view controller. All my requests to Facebook are sent through a singleton named FBRequestWrapper which (in this case) should pass the result to FBFeed.
I call getFBRequestWithGraphPath:andDelegate: in FBRequestWrapper which will call a method in the Facebook iOS SDK which takes a delegate as a parameter. If I put in self (which will be the FBRequestWrapper) it works just fine. If I put in _delegate (which is an instance of FBFeed) the application crashes with EXC_BAD_ACCESS.
I have a theory why it might crash. I have read that
#property (nonatomic, retain) id <FBFeedDelegate> delegate;
should be
#property (nonatomic, assign) id <FBFeedDelegate> delegate;
But when doing so I get the following error:
Existing ivar 'delegate' for unsafe_unretained property 'delegate'
must be __unsafe_unretained
Also, I don't know if that enough to make the application crash.
Here is my code.
ProfileViewController.h
#import <UIKit/UIKit.h>
#import "FeedTableView.h"
#import "FBFeed.h"
#interface ProfileViewController : UIViewController <FBFeedDelegate>
{
FeedTableView *tableView;
}
- (void)loadFeed;
#end
ProfileViewController.m
#implementation ProfileViewController
- (void)loadFeed
{
FBFeed *feed = [[FBFeed alloc] init];
[feed loadNewsFeedWithDelegate:self];
}
#pragma mark -
#pragma FBFeedDelegate
- (void)finishedLoadingFeed:(FBFeed *)_feed
{
NSLog(#"ProfileViewController: FBFeed Finished.");
}
- (void)failedToLoadFeed:(FBFeed *)_feed
{
NSLog(#"ProfileViewController: FBFeed Failed.");
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Load feed
[self loadFeed];
}
#end
FBFeed.h
#import <Foundation/Foundation.h>
#import "FBRequestWrapper.h"
#protocol FBFeedDelegate;
#interface FBFeed : NSObject <FBRequestDelegate>
{
id <FBFeedDelegate> delegate;
}
#property (nonatomic, retain) id <FBFeedDelegate> delegate;
- (void)loadNewsFeedWithDelegate:(id)_delegate;
#end
#protocol FBFeedDelegate <NSObject>
#required
- (void)finishedLoadingFeed:(FBFeed *)_feed;
- (void)failedToLoadFeed:(FBFeed *)_feed;
#end
FBFeed.m
#import "FBFeed.h"
#implementation FBFeed
#synthesize delegate;
- (void)loadNewsFeedWithDelegate:(id)_delegate
{
self.delegate = _delegate;
[[FBRequestWrapper defaultManager] getFBRequestWithGraphPath:#"me" andDelegate:self];
}
#pragma mark -
#pragma mark FBRequest Delegate
- (void)request:(FBRequest *)request didLoad:(id)result
{
NSLog(#"FBFeed: FBRequest Did Load.");
NSLog(#"%#", result);
}
- (void)request:(FBRequest *)request didFailWithError:(NSError *)error
{
NSLog(#"FBFeed: FBRequest Failed.");
NSLog(#"%#", error);
}
#end
FBRequestWrapper.h
#import <Foundation/Foundation.h>
#import "FBConnect.h"
#interface FBRequestWrapper : NSObject <FBRequestDelegate, FBSessionDelegate>
{
Facebook *facebook;
BOOL isLoggedIn;
}
#property (nonatomic, assign) BOOL isLoggedIn;
+ (id)defaultManager;
- (void)setIsLoggedIn:(BOOL)_loggedIn;
- (void)FBSessionBegin:(id<FBSessionDelegate>)_delegate;
- (void)FBLogout;
- (void)getFBRequestWithGraphPath:(NSString *)_path andDelegate:(id)_delegate;
- (void)getFBRequestWithMethodName:(NSString *)_methodName andParams:(NSMutableDictionary *)_params andDelegate:(id)_delegate;
#end
FBRequestWrapper.m
#import "FBRequestWrapper.h"
static FBRequestWrapper *defaultWrapper = nil;
#implementation FBRequestWrapper
#synthesize isLoggedIn;
+ (id)defaultManager
{
if(!defaultWrapper)
{
defaultWrapper = [[FBRequestWrapper alloc] init];
}
return defaultWrapper;
}
- (void)getFBRequestWithGraphPath:(NSString *)_path andDelegate:(id)_delegate
{
if (_path != nil)
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
if (_delegate == nil)
{
_delegate = self;
}
[facebook requestWithGraphPath:_path andDelegate:_delegate];
}
}
#pragma mark -
#pragma mark FBRequestDelegate
- (void)request:(FBRequest *)request didLoad:(id)result
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSLog(#"%#", result);
}
- (void)request:(FBRequest *)request didFailWithError:(NSError *)error
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSLog(#"FBRequest Failed: %#", error);
}
#end
I guess you are using ARC and the new iOS5 SDK which is still under NDA. Instead of using retain, use the Keyword 'strong'. Using strong will have the same behaviour intended as using retain. Set up your property like this:
#property (nonatomic, strong) id <FBFeedDelegate> delegate;
I think there are two ways for you:
Don't use ARC and leave your code as it was
If you want to use ARC, be aware that delegates normally shouldn't be retained. But when using ARC, an ivar declaration like this:
id <FBFeedDelegate> delegate
defaults to
id <FBFeedDelegate> __strong delegate
So when you declare a property like this:
#property (readwrite, unsafe_unretained) id <FBFeedDelegate> delegate
The ivar should look like this:
id <FBFeedDelegate> __unsafe_unretained delegate
I had the same problem but then I was able to make it work correctly under iOS 5.1 on XCode 4.3.2
Use this code in your .h file
#protocol AnimationManagerCountdownTimerDelegate <NSObject>
#required
-(void)countdownCompleted;
#end
#interface AnimationManager : NSObject{
....
}
#property (nonatomic, strong) id <AnimationManagerCountdownTimerDelegate> countdownTimerDelegate;
#end
Then in the .m file you simply synthesize:
#synthesize countdownTimerDelegate;
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]];
}
I'm new to Objective C and I'm having trouble getting delegates to work in my code.
I have a class called cViewController and in this class has a UIWebView to fetch webpages and a button above it that calls a popover class called prodMenu. What I'm having trouble with is that the function to call webpages from the prodMenu class and display it on the parent UIWebView isn't working.
cViewController.h
#import <UIKit/UIKit.h>
#import "prodMenu.h"
#interface cViewController : UIViewController <prodMenuDelegate>{
UIPopoverController *cpopover;
IBOutlet UIWebView *webImageDisplay;
}
#property (nonatomic, retain) UIWebView *webImageDisplay;
#property (nonatomic, retain) UIPopoverController *cpopover;
- (IBAction)cPopoverTapped:(id)sender;
- (void) fetchWebsite:(NSString *)website; //This is the delegate method I'm trying to call in the popover class.
#end
cViewController.m
- (IBAction)cPopoverTapped:(id)sender {
prodMenu *tp = [[prodMenu alloc] init];
cpopover = [[UIPopoverController alloc] initWithContentViewController:tp];
[tp release];
CGRect rect = CGRectMake(40, 0, 50, 50);
cpopover.popoverContentSize = CGSizeMake(250, 225);
[cpopover presentPopoverFromRect:rect inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}
- (void)fetchWebsite:(NSString*)website{ //This function is called by prodMenu class
NSLog(#"address: %#", website);
NSString *urlAddress = website;
NSURL *url = [NSURL URLWithString:urlAddress];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
[webImageDisplay loadRequest:requestObj];
[webImageDisplay release];
}
- (void)viewDidLoad {
[self fetchWebsite:#"http://www.yahoo.com"];
[super viewDidLoad];
}
prodMenu.h
#import <UIKit/UIKit.h>
#protocol prodMenuDelegate;
#interface prodMenu : UIViewController{
<prodMenuDelegate> delegate;
}
- (IBAction)radBtn:(id)sender; //This is the IBAction that calls the fetchWebsite function
#property (nonatomic, assign) id <prodMenuDelegate> delegate;
#end
#protocol prodMenuDelegate
- (void)fetchWebsite:(NSString *)website;
#end
prodMenu.m
#import "prodMenu.h"
#import "cViewController.h"
#implementation prodMenu
#synthesize delegate;
- (IBAction)radBtn:(id)sender{
[delegate fetchWebsite:#"http://www.google.com"]; //Here is the call to the method
}
Am I missing something here to call the delegate method? There aren't any errors or warnings. All I want to do is when the user presses a button on the popover view, the parent class underneath changes the webpage. Thanks in advance.
Just a quick idea. Have you tried declaring the delegate protocol like this
#protocol prodMenuDelegate <NSObject>
...
#end
? I often ran into troubles when omitting the < NSObject >. Also I think there is an 'id' missing in
#interface prodMenu : UIViewController{
<prodMenuDelegate> delegate;
}
Edit: Also, in the code you posted I do not see where you actually assign the prodMenu's delegate.
I have an UIViewController named MainViewController
I have another UIViewController named LeftSharingViewController;
I would like to get and use the NSString from MainViewController in my LeftSharingViewController
I have a problem, I always get (null) instead of the NSString wanted value.
Here's my code and how does the NSString get it's value
MainViewController:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
leftWebViewString = [NSString stringWithString:leftWebView.request.URL.absoluteString];
}
LeftSharingViewController.h:
#import <UIKit/UIKit.h>
#import "MainViewController.h"
#import <MessageUI/MessageUI.h>
#import <MessageUI/MFMailComposeViewController.h>
#class MainViewController;
#interface LeftSharingViewController : UIViewController <MFMailComposeViewControllerDelegate> {
MainViewController *mainViewController;
NSString *leftWebViewUrl;
}
#property (nonatomic, retain) MainViewController *mainViewController;
#property (nonatomic, retain) NSString *leftWebViewUrl;
#end
LeftSharingViewController.m:
#import "LeftSharingViewController.h"
#import "MainViewController.h"
#implementation LeftSharingViewController
#synthesize mainViewController;
#synthesize leftWebViewUrl;
- (void)viewWillAppear:(BOOL)animated {
self.leftWebViewUrl = self.mainViewController.leftWebViewString;
}
#pragma mark -
#pragma mark Compose Mail
-(void)displayComposerSheet
{
MFMailComposeViewController *mailPicker = [[MFMailComposeViewController alloc] init];
mailPicker.mailComposeDelegate = self;
[mailPicker setSubject:#"Check Out This Website!"];
[mailPicker setMessageBody:[NSString stringWithFormat:#"Take a look at this site:%#", leftWebViewUrl] isHTML:YES];
mailPicker.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentModalViewController:mailPicker animated:YES];
[mailPicker release];
}
Thanks!
On your MainViewController, you are never retaining the NSString you create. You are using stringWithString:, which returns an autoreleased object.
You should either retain it, or (easier) change your code to use your accessor, which already retains, like this:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
self.leftWebViewString = [NSString stringWithString:leftWebView.request.URL.absoluteString];
}
As a side note, if you are navigating from MainViewController to LeftSharingViewController, instead of "pulling" the data in LeftSharingViewController from MainViewController, I would do it the other way around:
In MainViewController, before displaying the view of LeftSharingViewController, I'd set the required properties.