I have a table view controller in my app. Each cell is the name of a website. When a cell is hit a web view controller is created, passed a url and pushed to the view.
Pretty standard right?
If I go in and out of a web view enough times I begin to get memory warnings until the app crashes.
I can't see anywhere in my implementation where I'm not releasing anything properly. Is there some webview specific best practices or important delegate methods I might have left out?
This is driving me crazy because there is very little code involved and yet I still can't seem to find the problem.
Could somebody help me discover what is causing this memory problem or prehaps refer me to an article or tutorial so I can see how to do this properly?
Table View Controller
#implementation LinkListViewController
#synthesize linksArray;
#synthesize wvcontroller;
#pragma mark -
#pragma mark Initialization
- (void)loadView {
[super loadView];
table = [[UITableViewController alloc] initWithStyle:UITableViewStylePlain];
[self pushViewController:table animated:YES];
table.tableView.delegate = self;
table.tableView.dataSource = self;
table.title = #"Links"; // Tab Bar Title
[self.view addSubview:table.view];
}
-(id) initWithTabBar {
if ([self init]) {
self.tabBarItem.image = [UIImage imageNamed:#"events.png"];
}
return self;
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [linksArray count];;
}
#define LABEL_TAG 7777
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
LinkData *ld;
ld=[linksArray objectAtIndex:indexPath.row];
static NSString *CellIdentifier = #"Cell";
UILabel *label = nil;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
CGRect frame;
frame.origin.x = 0;
frame.origin.y = 10;
frame.size.width = 100;
frame.size.height = 30;
frame.origin.x = 0;
frame.size.width =290;
label = [[[UILabel alloc] initWithFrame:frame] autorelease];
label.tag = LABEL_TAG;
[cell.contentView addSubview:label];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
} else {
label = (UILabel *) [cell.contentView viewWithTag:LABEL_TAG];
}
label.text = [ld.linkname copy];
label.textColor=[UIColor blackColor];
return cell;
}
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
LinkData *ld=[linksArray objectAtIndex:indexPath.row];
if ([ld.linktype isEqualToString:#"webpage"]) {
if (wvcontroller) {
[wvcontroller release];
wvcontroller=nil;
}
wvcontroller= [[WebViewController alloc]initWithPath:ld.linkurl];
wvcontroller.title=ld.linkname;
[table.navigationController pushViewController:wvcontroller animated:YES];
}
}
Web View Controller
#import "WebViewController.h"
#implementation WebViewController
#synthesize webView;
#synthesize path;
#synthesize showsync;
#synthesize activity;
-(id)initWithPath:(NSString *)thepath
{
if ( [self init]) {
self.path= [thepath copy];
self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
[self.view setBackgroundColor:[UIColor blackColor]];
[self loadView];
}
return self;
}
- (void)loadView {
//Create a URL object.
webView = [[UIWebView alloc] initWithFrame:self.view.frame];
webView.autoresizesSubviews = YES;
webView.autoresizingMask=(UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth);
//set the web view delegates for the web view to be itself
self.webView.scalesPageToFit = YES;
self.webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
self.webView.delegate = self;
//Create a URL object.
NSURL *url = [NSURL URLWithString:path];
//URL Requst Object
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
//add the web view to the content view
[self.view addSubview:webView];
//load the URL into the web view.
[webView loadRequest:requestObj];
//[webView release], webView = nil;
activity = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activity.frame = CGRectMake(0.0, 0.0, 40.0, 40.0);
activity.center = self.view.center;
[self.view addSubview: activity];
}
/*
If you need to do additional setup after loading the view, override viewDidLoad. */
- (void)viewDidLoad {
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.webView;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)dealloc {
[webView release];
[activity release];
webView=nil;
[path release];
[super dealloc];
}
- (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.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)webViewDidStartLoad:(UIWebView *)webView {
[activity startAnimating];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[activity stopAnimating];
}
You still hold an extra reference to self.view at the end of initWithPath which should be released.
A bit more explanation: [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] gives you a UIView with a retain count of 1 (since you have just allocated it). Assigning it to self.view bumps its retain count by 1, so it is 2 at the moment. When your controller is deallocated, it takes care of decreasing the retain count of the object in self.view, but the count is still 1, so it never gets deallocated. You should do this:
UIView* myView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
self.view = myView;
[myView release];
One way to avoid UIWebView memory problems is to create only one webview one time, and reuse it for the whole life of the application. That is, not release it but reuse it.
Related
Sounds like a question that has been answered... maybe but i have checked all of the possible solutions i believe and nothing will work for me.
My .h file looks like this
#import <UIKit/UIKit.h>
#interface epsMenuPage : UIViewController<UITableViewDelegate,UITableViewDataSource>{
NSArray *listData;
...
UITableView *menuList;
...
}
#property (nonatomic,retain) NSArray *listData;
...
#property (nonatomic, retain) IBOutlet UITableView *menuList;
...
#end
My .m file looks like this
#implementation epsMenuPage
#synthesize listData;
...
#synthesize menuList;
- (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
{
//Arrays credit,debit and both
creditListData = [[NSArray alloc]initWithObjects:#"Return",#"Force Sale",#"Authorize Only",#"Total Sales",#"Items Sold",#"Reciept's", nil];
debitListData = [[NSArray alloc]initWithObjects:#"Return",#"Force Sale",#"Authorize Only",#"Total Sales",#"Items Sold",#"Reciept's", nil];
bothListData = [[NSArray alloc]initWithObjects:#"Batch History",#"Settle Batch", nil];
self.listData = creditListData;
[menuList reloadData];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.view.backgroundColor =[UIColor colorWithRed:255/255.0 green:95/255.0 blue:95/255.0 alpha:1.0];
[colorChange setBackgroundColor:[UIColor colorWithRed:255/255.0 green:95/255.0 blue:95/255.0 alpha:1.0]];
[self.view addSubview:creditTabButton];
[self.view addSubview:debitTabButton];
[self.view addSubview:bothTabButton];
[self.view addSubview:creditButtonText];
[self.view addSubview:debitButtonText];
[self.view addSubview:bothBottonText];
[self.view addSubview:colorChange];
}
- (void)viewDidUnload
{
[self setTitleBAckButton:nil];
[self setTitleSettingsButton:nil];
[self setCreditTabButton:nil];
[self setDebitTabButton:nil];
[self setBothTabButton:nil];
[self setMenuList:nil];
[self setColorChange:nil];
[self setCreditButtonText:nil];
[self setDebitButtonText:nil];
[self setBothBottonText:nil];
[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);
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.listData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *SimpleTableIdentifier = #"tableID";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:SimpleTableIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:SimpleTableIdentifier] autorelease];
}
NSUInteger row = [indexPath row];
cell.textLabel.text = [self.listData objectAtIndex:row];
return cell;
}
- (void)dealloc {
[titleBAckButton release];
[titleSettingsButton release];
[creditTabButton release];
[debitTabButton release];
[bothTabButton release];
[menuList release];
[colorChange release];
[creditButtonText release];
[debitButtonText release];
[bothBottonText release];
[listData release];
[super dealloc];
}
- (IBAction)titleBackClick:(id)sender {
[self.parentViewController dismissModalViewControllerAnimated:YES];
}
- (IBAction)titleSettingsClick:(id)sender {
}
- (IBAction)creditTabClick:(id)sender {
self.listData = creditListData;
[menuList reloadData];
[colorChange setBackgroundColor:[UIColor colorWithRed:255/255.0 green:95/255.0 blue:95/255.0 alpha:1.0]];
[self.view addSubview:creditTabButton];
[self.view addSubview:creditButtonText];
[self.view addSubview:colorChange];
self.view.backgroundColor = [UIColor colorWithRed:255/255.0 green:95/255.0 blue:95/255.0 alpha:1.0];
}
- (IBAction)debitTabClick:(id)sender {
self.listData = debitListData;
[menuList reloadData];
[colorChange setBackgroundColor:[UIColor colorWithRed:244/255.0 green:133/255.0 blue:33/255.0 alpha:1.0]];
[self.view addSubview:debitTabButton];
[self.view addSubview:debitButtonText];
[self.view addSubview:colorChange];
self.view.backgroundColor = [UIColor colorWithRed:244/255.0 green:133/255.0 blue:33/255.0 alpha:1.0];
}
- (IBAction)bothTabClick:(id)sender {
self.listData = bothListData;
[menuList reloadData];
[colorChange setBackgroundColor:[UIColor colorWithRed:72/255.0 green:72/255.0 blue:255/255.0 alpha:1.0]];
[self.view addSubview:bothTabButton];
[self.view addSubview:bothBottonText];
[self.view addSubview:colorChange];
self.view.backgroundColor = [UIColor colorWithRed:72/255.0 green:72/255.0 blue:255/255.0 alpha:1.0];
}
#end
I really for the life of me can not figure out why it wont display to my TableView, i have tried so many different tutorials.
any help is greatly appreciated.
You're never adding the menuList table view to your view. Add it and see if that does the trick:
// In -viewDidLoad
[self.view addSubview:menuList];
EDIT 1: Did you declare properties in your .h? These aren't visible, so it appears as if you're not creating or adding your table view to the view controller's view. However, if you are using IBOutlets, then this probably isn't the issue.
EDIT 2: From the comments below, your dataSource is nil, which is exactly why nothing is being displayed. Make sure your table view in Interface Builder has its dataSource outlet pointing to your view controller. To be double sure, delete the table view from Interface Builder and add it back again. Make sure your connections are exactly right. Also try cleaning the project and rebuilding, as well as restarting Xcode.
It looks like you are missing the required datasource method:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; {
return 1;
}
Also, it looks like you are not actually initializing your UIButton's, or anything you are adding as a subview. Are you using a nib?
I'm trying to acheive a dual-tabBar app for the iPhone and using the following code for a base class view controller to add several navigation controllers inside the view controller (see code below). But the problem is: No subviews are added to self.view, despite them being initialized earlier. Any ideas?
- (IBAction)ViewButtonPressed:(id)sender
{
UIButton *b = (UIButton *)sender;
int index = b.tag - 1000;
[self SelectNavigationController:index];
}
- (void)SelectNavigationController:(int)index
{
// Set index to top-most view ->
UINavigationController *nc = (UINavigationController *)[navigationControllers objectAtIndex:index];
[self.view bringSubviewToFront:nc.view];
}
#pragma mark -
#pragma mark display
- (void)Display
{
CGRect frame = CGRectMake(0, 44, 320, 367);
// Create buttons above frame and show navigation controller inside frame ->
UIView *v = [[UIView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.origin.y)];
for (int i=0; i<[navigationControllers count]; ++i)
{
UINavigationController *nc = (UINavigationController *)[navigationControllers objectAtIndex:i];
UIViewController *vc = [nc.viewControllers objectAtIndex:0];
NSString *titel = vc.navigationItem.title;
UIButton *b = [UIButton buttonWithType:UIButtonTypeCustom];
[b setBackgroundColor:[UIColor lightGrayColor]]; // TODO: Replace with image <-
[b setTitle:titel forState:UIControlStateNormal];
b.tag = i + 1000;
[b setFrame:CGRectMake(i * frame.size.width / 3, 0, frame.size.width / 3, frame.origin.y - 1)];
[v addSubview:b];
}
for (int j=0; j<[navigationControllers count]; ++j)
{
UINavigationController *nc = (UINavigationController *)[navigationControllers objectAtIndex:j];
[nc.navigationBar addSubview:v];
[self.view addSubview:nc.view]; // Add view to view <-
nc.view.frame = frame;
}
[v release];
if (VIEW_DEBUG)
NSLog(#"BaseTabViewController.m: self.view.subviews: %d", [self.view.subviews count]);
}
#pragma mark -
#pragma mark addviewcontroller
- (void)AddViewControllerForNavigationController:(UIViewController *)viewController
{
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
navController.view.backgroundColor = [UIColor greenColor];
[navigationControllers addObject:navController];
[navController release];
}
#pragma mark -
#pragma mark init, loadView, viewDidLoad and dealloc
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder])
{
navigationControllers = [[NSMutableArray alloc] init];
}
return self;
}
- (void)loadView
{
//
}
- (void)viewDidLoad
{
if (!viewDidLoadAlready)
{
[self Display];
viewDidLoadAlready = YES;
[super viewDidLoad];
}
}
And the code in the subclass:
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder])
{
PistKartaViewController *pistKarta = [[PistKartaViewController alloc] init];
pistKarta.navigationItem.title = #"Pistkarta";
LiftRapportViewController *liftRapport = [[LiftRapportViewController alloc] init];
liftRapport.navigationItem.title = #"Liftrapport";
SkipassViewController *skiPass = [[SkipassViewController alloc] init];
skiPass.navigationItem.title = #"Skipass";
[self AddViewControllerForNavigationController:pistKarta];
[self AddViewControllerForNavigationController:liftRapport];
[self AddViewControllerForNavigationController:skiPass];
[pistKarta release];
[liftRapport release];
[skiPass release];
}
return self;
}
I figured it out. I had the following in a view controller I was adding...
- (void)loadView
{
}
, which of course means that the superclass won't be loaded at all. Stupid. Otherwise, this method works quite well. :)
The iOS app I'm currently working on is tabbar-based, and one of the tab is a UITableViewController.
The thing is, when I open this tab with an empty datasource (for whatever reason), I'd like to bring another view, with some kind of message/image, instead of the blank view I get with the tableviewcontroller.
I tried something like that :
- (void)viewWillAppear:(BOOL)animated {
if ([myData count] == 0) {
if (!emptyView) {
emptyView = [[UIView alloc] initWithFrame:self.view.frame];
UILabel *emptyMsg = [[UILabel alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height / 2, self.view.frame.size.width, 20)];
emptyMsg.text = #"This is Empty !";
emptyMsg.textAlignment = UITextAlignmentCenter;
[emptyView addSubview:emptyMsg];
}
[self.view insertSubview:emptyView atIndex:0];
}
else {
if (emptyView != nil) { [emptyView removeFromSuperview]; emptyView = nil; }
[self.tableView reloadData];
[super viewWillAppear:animated];
}
}
With emptyView defined as an iVar in the view controller.
But It doesn't work as expected, and I can't find the reason :/
Could any of you give it a look and give me the proper way to do this kind of behavior ?
Thanks,
I solved this problem by adding a UIView in the tableview header with a frame size equal to tableview size and disallowing user interaction on the tableview:
UIView *emptyView = [[UIView alloc] initWithFrame:self.tableView.frame];
/* Customize your view here or load it from a NIB */
self.tableView.tableHeaderView = emptyView;
self.tableView.userInteractionEnabled = NO;
When you have data you just remove the header and reenable user interaction:
self.tableView.tableHeaderView = nil;
self.tableView.userInteractionEnabled = YES;
UITableViewController doesn't allow you to add subviews to it's view (the tableView).
You should make a UIViewController and add the UITableView yourself with your optional emptyView.
Don't forget to set the dataSource and the delegate!
Update : I've made a subclass of UIViewController to avoid mimics UITableViewController every time.
.h
//
// GCTableViewController.h
// GCLibrary
//
// Created by Guillaume Campagna on 10-06-17.
// Copyright 2010 LittleKiwi. All rights reserved.
//
#import <UIKit/UIKit.h>
//Subclass of UIViewController that mimicks the UITableViewController except that the tableView is a subview of self.view and allow change of the frame of the tableView
#interface GCTableViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
#property (nonatomic, readonly) UITableView *tableView;
- (id) initWithStyle:(UITableViewStyle)style;
//Subclass if you want to change the type of tableView. The tableView will be automatically placed later
- (UITableView*) tableViewWithStyle:(UITableViewStyle) style;
#end
.m
//
// GCTableViewController.m
// GCLibrary
//
// Created by Guillaume Campagna on 10-06-17.
// Copyright 2010 LittleKiwi. All rights reserved.
//
#import "GCTableViewController.h"
#implementation GCTableViewController
#synthesize tableView;
- (id) initWithStyle:(UITableViewStyle) style {
if (self = [super initWithNibName:nil bundle:nil]) {
tableView = [[self tableViewWithStyle:style] retain];
self.tableView.delegate = self;
self.tableView.dataSource = self;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.tableView];
self.tableView.frame = self.view.bounds;
self.tableView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
}
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
}
#pragma mark TableView methods
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger) tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section {
return 0;
}
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
return nil;
}
#pragma mark Getter
- (UITableView *) tableViewWithStyle:(UITableViewStyle)style {
return [[[UITableView alloc] initWithFrame:CGRectZero style:style] autorelease];
}
- (void)dealloc {
[tableView release];
tableView = nil;
[super dealloc];
}
#end
You could perhaps try setting the number of rows to zero. Then inserting the no results view as the header view.
I'm completely new to iPhone development. I have a query regarding how to implement scroll view in table view. I'm using following code
#import <UIKit/UIKit.h>
#class ScrollViewViewController;
#interface ScrollViewAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
ScrollViewViewController *viewController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet ScrollViewViewController *viewController;
#end
////////////////////////////////////////////
#import "ScrollViewAppDelegate.h"
#import "ScrollViewViewController.h"
#implementation ScrollViewAppDelegate
#synthesize window;
#synthesize viewController;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Override point for customization after app launch
[window addSubview:viewController.view];
[window makeKeyAndVisible];
}
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
#end
///////////////////////////
#import <UIKit/UIKit.h>
#interface MyTableCell : UITableViewCell {
NSMutableArray *columns;
}
- (void)addColumn:(CGFloat)position;
#end
//////////////////////////
#import "MyTableCell.h"
#implementation MyTableCell
- (id)initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithFrame:frame reuseIdentifier:reuseIdentifier]) {
// Initialization code
columns = [NSMutableArray arrayWithCapacity:5];
[columns retain];
}
return self;
}
- (void)addColumn:(CGFloat)position {
[columns addObject:[NSNumber numberWithFloat:position]];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (void)drawRect:(CGRect)rect {
CGContextRef ctx = UIGraphicsGetCurrentContext();
// just match the color and size of the horizontal line
CGContextSetRGBStrokeColor(ctx, 0.5, 0.5, 0.5, 1.0);
CGContextSetLineWidth(ctx, 0.25);
for (int i = 0; i < [columns count]; i++) {
// get the position for the vertical line
CGFloat f = [((NSNumber*) [columns objectAtIndex:i]) floatValue];
CGContextMoveToPoint(ctx, f, 0);
CGContextAddLineToPoint(ctx, f, self.bounds.size.height);
}
CGContextStrokePath(ctx);
[super drawRect:rect];
}
- (void)dealloc {
[super dealloc];
[columns dealloc];
}
#end
//////////////////////
#import <UIKit/UIKit.h>
#interface RootViewController : UITableViewController {
}
#end
/////////////////
#import "RootViewController.h"
#import "MyTableCell.h"
#implementation RootViewController
#define LABEL_TAG 1
#define VALUE_TAG 2
#define FIRST_CELL_IDENTIFIER #"TrailItemCell"
#define SECOND_CELL_IDENTIFIER #"RegularCell"
- (void)viewDidLoad {
// Add the following line if you want the list to be editable
// self.navigationItem.leftBarButtonItem = self.editButtonItem;
self.title = #"Grids!";
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
return 19;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *MyIdentifier = [NSString stringWithFormat:#"MyIdentifier %i", indexPath.row];
MyTableCell *cell = (MyTableCell *)[tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[MyTableCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease];
UILabel *label = [[[UILabel alloc] initWithFrame:CGRectMake(0.0, 0, 30.0,
tableView.rowHeight)] autorelease];
[cell addColumn:40];
label.tag = LABEL_TAG;
label.font = [UIFont systemFontOfSize:12.0];
label.text =#"S.NO";// [NSString stringWithFormat:#"%d", indexPath.row];
label.textAlignment = UITextAlignmentRight;
label.textColor = [UIColor redColor];
label.autoresizingMask = UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleHeight;
[cell.contentView addSubview:label];
label = [[[UILabel alloc] initWithFrame:CGRectMake(40.0, 0, 70.0,
tableView.rowHeight)] autorelease];
[cell addColumn:120];
label.tag = VALUE_TAG;
label.font = [UIFont systemFontOfSize:12.0];
// add some silly value
label.text =#"Product ID";// [NSString stringWithFormat:#"%d", indexPath.row * 4];
label.textAlignment = UITextAlignmentRight;
label.textColor = [UIColor blueColor];
label.autoresizingMask = UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleHeight;
[cell.contentView addSubview:label];
label = [[[UILabel alloc] initWithFrame:CGRectMake(134.0, 0, 70.0,
tableView.rowHeight)] autorelease];
[cell addColumn:220];
label.tag = VALUE_TAG;
label.font = [UIFont systemFontOfSize:12.0];
// add some silly value
label.text =#"Product Name";// [NSString stringWithFormat:#"%d", indexPath.row * 4];
label.textAlignment = UITextAlignmentRight;
label.textColor = [UIColor greenColor];
label.autoresizingMask = UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleHeight;
[cell.contentView addSubview:label];
label = [[[UILabel alloc] initWithFrame:CGRectMake(230.0, 0, 70.0,
tableView.rowHeight)] autorelease];
[cell addColumn:310];
label.tag = VALUE_TAG;
label.font = [UIFont systemFontOfSize:12.0];
// add some silly value
label.text =#"Customer Name";// [NSString stringWithFormat:#"%d", indexPath.row * 4];
label.textAlignment = UITextAlignmentRight;
label.textColor = [UIColor greenColor];
label.autoresizingMask = UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleHeight;
[cell.contentView addSubview:label];
label = [[[UILabel alloc] initWithFrame:CGRectMake(320.0, 0, 70.0,
tableView.rowHeight)] autorelease];
[cell addColumn:400];
label.tag = VALUE_TAG;
label.font = [UIFont systemFontOfSize:12.0];
// add some silly value
label.text =#"Customer Product";// [NSString stringWithFormat:#"%d", indexPath.row * 4];
label.textAlignment = UITextAlignmentRight;
label.textColor = [UIColor greenColor];
label.autoresizingMask = UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleHeight;
[cell.contentView addSubview:label];
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated {
}
- (void)viewDidDisappear:(BOOL)animated {
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
- (void)dealloc {
[super dealloc];
}
#end
////////////
#import <UIKit/UIKit.h>
#interface ScrollViewViewController : UIViewController<UIScrollViewDelegate> {
}
#end
/////////////
#import "ScrollViewViewController.h"
#import "RootViewController.h"
#implementation ScrollViewViewController
/*
// The designated initializer. Override to perform setup that is required before the view is loaded.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Custom initialization
}
return self;
}
*/
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
RootViewController *RootViewControllerLink = [[RootViewController alloc]initWithNibName:#"RootViewController" bundle:nil];
RootViewControllerLink.view.tag = 100;
/* UIImageView *imgView = [[[UIImageView alloc] initWithImage:
[UIImage imageNamed:#"winkler-gnu-blue.png"]] autorelease];
imgView.tag = 100;
*/
UIScrollView *scrollView = [[[UIScrollView alloc]
initWithFrame:CGRectMake(0,0,320,480)] autorelease];
scrollView.delegate = self;
scrollView.minimumZoomScale = 0.25;
scrollView.maximumZoomScale = 2;
scrollView.bounces = NO;
scrollView.showsHorizontalScrollIndicator = NO;
scrollView.showsVerticalScrollIndicator = NO;
scrollView.contentSize = RootViewControllerLink.view.frame.size;
scrollView.contentOffset =
CGPointMake((RootViewControllerLink.view.frame.size.width-320)/2,
(RootViewControllerLink.view.frame.size.height-480)/2);
[scrollView addSubview:RootViewControllerLink.view];
self.view = scrollView;
}
/*- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return [self.view viewWithTag:100];
}
- (BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view
{
return YES;
}// default returns YES
- (BOOL)touchesShouldCancelInContentView:(UIView *)view
{
return YES;
}
*/
// not called if canCancelContentTouches is NO. default returns YES if view isn't UIControl
/*
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
}
*/
/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/
- (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.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
#end
In above code if I set scroll for UIIMage then it works but if I set scroll view for RootViewController then it doesn't work.
I didn't read your code, please reformat it so others can read it easily.
What do you mean by a UIScrollView in an UITableView? Inside the cells? Still I don't get it.
FYI UITableView inherits from UIScrollView ...
What functionality do you exactly want to achieve?
I will recommend to read some of the samples given by Apple. There are very good and extensive examples specially regarding UIKit.
I have an application which contains a scrollview with two subviews (to scroll left and right between them)
Both views appear correctly and scrolling between the views worked fine. Now I want to change the first view to be a TTTableView (courtesy of Three20) but when I use the class 'TableControlsTestController' from the TTCatalog application all I see is an empty tableView
Note that this class contains all the data to display 6 cells
To add the new TTTableView I use the following
[scrollView addSubview:detailView.view];
where detailView is the instance of TableControlsTestController
To try and narrow down where the problem is I also tried calling
[self presentModalViewController:detailView animated:YES];
This correctly displays the tableview with the 6 cells.
Why when I try to add the view to the scrollView does this not work as I expect?
For reference if you do not have access to the TTCatalog
#import "TableControlsTestController.h"
///////////////////////////////////////////////////////////////////////////////////////////////////
#implementation TableControlsTestController
///////////////////////////////////////////////////////////////////////////////////////////////////
// NSObject
- (id)init {
if (self = [super init]) {
self.tableViewStyle = UITableViewStyleGrouped;
self.autoresizesForKeyboard = YES;
self.variableHeightRows = YES;
UITextField* textField = [[[UITextField alloc] init] autorelease];
textField.placeholder = #"UITextField";
textField.font = TTSTYLEVAR(font);
UITextField* textField2 = [[[UITextField alloc] init] autorelease];
textField2.font = TTSTYLEVAR(font);
textField2.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
TTTableControlItem* textFieldItem = [TTTableControlItem itemWithCaption:#"TTTableControlItem"
control:textField2];
UITextView* textView = [[[UITextView alloc] init] autorelease];
textView.text = #"UITextView";
textView.font = TTSTYLEVAR(font);
TTTextEditor* editor = [[[TTTextEditor alloc] init] autorelease];
editor.font = TTSTYLEVAR(font);
editor.backgroundColor = TTSTYLEVAR(backgroundColor);
editor.autoresizesToText = NO;
editor.minNumberOfLines = 3;
editor.placeholder = #"TTTextEditor";
UISwitch* switchy = [[[UISwitch alloc] init] autorelease];
TTTableControlItem* switchItem = [TTTableControlItem itemWithCaption:#"UISwitch" control:switchy];
UISlider* slider = [[[UISlider alloc] init] autorelease];
TTTableControlItem* sliderItem = [TTTableControlItem itemWithCaption:#"UISlider" control:slider];
self.dataSource = [TTListDataSource dataSourceWithObjects:
textField,
editor,
textView,
textFieldItem,
switchItem,
sliderItem,
nil];
}
return self;
}
#end
It turns out that some of the events were not being propagated through the scrollView and therefore not handled in the TTTableViewController. To fix this I had to do the following in my scrollView
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[myNewTTViewController viewWillAppear:NO];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[myNewTTViewController viewDidAppear:NO];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[myNewTTViewController viewWillDisappear:NO];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[myNewTTViewController viewDidDisappear:NO];
}
As soon as I did this the table popped into life