Pass data from a table to a webview USING SEGUES
-
04-12-2019 - |
Вопрос
I have a table based off Sam's Teach Yourself iOS Development's FlowerViewController, that, under didSelectRowAtIndesPath it goes to a website in a new nib (I tweaked part of the passing data). MY QUESTION: I would like to update this to, instead of going to a nib, to segue within a storyboard. I know that instead of using didSelectRow... I use prepareForSegue...but I can't figure out the details...
my I have ViewController.m with the following:
- (void)viewDidLoad {
[self movieData];
[super viewDidLoad];
self.title = @"Movies";
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [movieSections count];
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[movieData objectAtIndex:section] count];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier];
}
// Configure the cell.
[[cell textLabel]
setText:[[[movieData
objectAtIndex:indexPath.section]
objectAtIndex: indexPath.row]
objectForKey:@"name"]];
[[cell imageView]
setImage:[UIImage imageNamed:[[[movieData
objectAtIndex:indexPath.section]
objectAtIndex: indexPath.row]
objectForKey:@"picture"]]];
[[cell detailTextLabel]
setText:[[[movieData
objectAtIndex:indexPath.section]
objectAtIndex: indexPath.row]
objectForKey:@"detail"]];
cell.detailTextLabel.numberOfLines = 0;
cell.accessoryType=UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
// Override to support row selection in the table view.
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
WebViewController *webViewController =
[[WebViewController alloc] initWithNibName:
@"WebViewController" bundle:nil];
webViewController.detailURL=
[[NSURL alloc] initWithString:
[[[movieData objectAtIndex:indexPath.section] objectAtIndex:
indexPath.row] objectForKey:@"url"]];
webViewController.title=
[[[movieData objectAtIndex:indexPath.section] objectAtIndex:
indexPath.row] objectForKey:@"name"];
[self.navigationController pushViewController:
webViewController animated:YES];
}
#pragma mark -
#pragma mark Table view delegate
#pragma mark -
#pragma mark Memory management
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Relinquish ownership any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
// For example: self.myOutlet = nil;
}
- (void)movieData {
NSMutableArray *myMovies;
movieSections=[[NSMutableArray alloc] initWithObjects:
@"Movies",nil];
myMovies=[[NSMutableArray alloc] init];
[myMovies addObject:[[NSMutableDictionary alloc]
initWithObjectsAndKeys:@"Movie1",@"name",
@"1.png",@"picture",
@"http://www.url1.com",@"url",@"Some information",@"detail",nil]];
[myMovies addObject:[[NSMutableDictionary alloc]
initWithObjectsAndKeys:@"Movie2",@"name",
@"2.png",@"picture",
@"http://www.url2.com",@"url",@"Some information 2",@"detail",nil]];
[myMovies addObject:[[NSMutableDictionary alloc]
initWithObjectsAndKeys:@"Movie3",@"name",
@"3.png",@"picture",
@"http://www.url3.com",@"url",@"Some information 3",@"detail",nil]];
[myMovies addObject:[[NSMutableDictionary alloc]
initWithObjectsAndKeys:@"Movie4",@"name",
@"4.png",@"picture",
@"http://www.url4.com",@"url",@"Some information 4",@"detail",nil]];
movieData=[[NSMutableArray alloc] initWithObjects:
myMovies,nil];
}
I attempted to comment out the didSelectRowAtIndexPath and add the following for the segue, but the cell highlights and nothing happens (thankfully it doesn't freeze/crash, but there's nothing positive)
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:@"movieSegue"]) {
NSIndexPath *selectedRowIndex = [self.tableView indexPathForSelectedRow];
WebViewSegue *_webViewSegue = [segue destinationViewController];
_webViewSegue.detailURL =
[[NSURL alloc] initWithString:[[[movieData objectAtIndex:selectedRowIndex.section] objectAtIndex:
selectedRowIndex.row] objectForKey:@"url"]];
}
}
Then I want it to pass to WebViewSegue
WebViewSegue.h:
@interface WebViewSegue : UIViewController {
IBOutlet UIWebView *detailWebView;
NSURL *detailURL;
IBOutlet UIActivityIndicatorView *activity;
NSTimer *timer;
}
@property (nonatomic, weak) NSURL *detailURL;
@property (nonatomic, weak) UIWebView *detailWebView;
@property (nonatomic, weak) UIActivityIndicatorView *activity;
@end
WebViewSegue.m:
@synthesize detailWebView =_detailWebView;
@synthesize detailURL = _detailURL;
@synthesize activity =_activity;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
[detailWebView loadRequest:[NSURLRequest requestWithURL:detailURL]];
timer = [NSTimer scheduledTimerWithTimeInterval:(1.0/2.0)
target:self
selector:@selector(tick)
userInfo:nil
repeats:YES];
}
-(void)tick {
if (!detailWebView.loading)
[activity stopAnimating];
else
[activity startAnimating];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
-(void)wevView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Cannot connect"
message:@"Please check your connection and try again"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
}
@end
Решение
I've answered your question in another post on the site. See my answer here.
Specifically on how to pass data from a table to the next storyboard segue, first create a property for the data in the next storyboard segue (i.e. the destination view controller). Then set that property in the prepareForSegue method of the table (the source view controller).
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// needed if you have multiple segues
if ([[segue identifier] isEqualToString:@"changeNameAndDate"])
{
[[segue destinationViewController] setDataProperty:self.tableData];
// where dataProperty is the property in the designation view controller
// and tableData is the data your are passing from the source
{
}
Другие советы
This is a lot of code to digest; you should try to simplify. But if I've read it correctly, your basic approach seems correct.
First, put a breakpoint on prepareForSegue:sender:
, and make sure it's being called, and that the identifier is what you expect it to be.
Then put a breakpoint on viewDidLoad
and make sure it's called when you think it should be.
I would pull the loadRequest:
out into its own method and call it both in viewDidLoad
and in setDetailURL:
. It's likely that setDetailURL:
is being called after viewDidLoad
if all of this is in a single storyboard.
EDIT What I'm saying is that prepareForSegue:sender:
is likely correct. You're problem is in the presented view controller.
- (void)reloadWebView { // Pull the loadRequest: out...
[self.detailWebView loadRequest:[NSURLRequest requestWithURL:self.detailURL]];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self reloadWebView]; // ...and call it both in viewDidLoad...
...
}
- (void)setDetailURL:(NSURL *)URL {
[URL retain];
[detailURL release];
detailURL = URL;
[self reloadWebView]; // ...and in setDetailURL:
}
Also note that there is no reason for your timer. Just turn on your progress indicator in reloadWebView
and turn it off in webViewDidFinishLoad
and webView:didFailLoadWithError:
. Your current approach makes it impossible to deallocate this view controller because the timer retains it forever.