Stuck with tableview - ios

I am making an app with dynamic tables inside of it. I had managed to let it work with the table inside the MainviewController, but now i am stuck. I tried to put the table code in its own class.
strange thing is that it gives no errors.
This is what i do:
MainviewController.m:
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * 0;//0 will later be i
frame.origin.y = 0;
frame.size.width = self.scrollView.frame.size.width;
TellerTable *tellerTable = [[TellerTable alloc] initWithFrame:frame style:UITableViewStyleGrouped];
[tellerTable loadWithJsonData:JSONArray];
[tellerTable setDataSource:tellerTable];
[self.view addSubview:tellerTable];
[tellerTable reloadData];
TableTeller.m:
-(void)loadWithJsonData:(NSArray *)JA
{
self.JSONArray = JA;
tableview = self;
self.delegate = self;
self.dataSource = self;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSMutableArray *TellerItems = [JSONArray objectAtIndex:section];
return TellerItems.count;
}
(the rest to make the table cellForRowAtIndexPath etc..)
TellerTable.h
#interface TellerTable : UITableView <UITableViewDataSource, UITableViewDelegate>
{
UITableView *tableview;
}
#property (nonatomic, retain) IBOutlet UITableView *tableview;
#property (nonatomic, retain) IBOutlet NSArray *JSONArray;
-(void)loadWithJsonData:(NSArray *)JA;
#end
Strange thing is, it goes to loadwithJSON, then it calls numberOfRowsInSection but after that it stops. It doesn't add the table to the scrollview. What am i doeing wrong/forget?

I think you should change your approach .. you have created a subclass of UITableView and then another tableView property on the same then you are assigning it to self all feels wrong even if it works. I dont see any use of subclassing here you are not customising the table so why are you subclassing it?. Add a tableView(drag and drop) to xib or storyboard then connect outlet to mainviewcontroller. You may be able to make it work somehow using this method but its errorprone,less readable etc etc

Related

All UITableCells disappear when tapping on UITableView in iOS 7

I am having a problem with my UITableView in iOS7. Initially, the data loads in just fine, and I get output in my console that proves that the cells are speaking to the data source correctly, but as soon as I tap anywhere on the table, the cells disappear and the table goes blank. The height of the cells in the empty UITableView seem to be honoring the height my custom prototype cell (410px), but all the data in the cells vanish, and the empty table view acts like it only has one cell in it (like its default state before it gets hooked up to the delegate).
I am using Storyboards for this app.
To get a little context, this app is similar to the iphone Instagram app, and I am using this application as way to learn iOS 7 development. I have been banging my head up against a wall trying to solve this issue, and I can't find any online resources that can help me solve this, so I wanted to ask all the smart peeps on Stack Overflow.
I have prepared a graphic that helps you see the problem
higher resolution version here
Here is my TableViewController code:
#interface PA_PhotoTableViewController ()
#property (nonatomic, copy) NSArray *photos;
#end
#implementation PA_PhotoTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.photos = [[PA_PhotoStore sharedPhotoStore] allPhotos];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[[PA_PhotoStore sharedPhotoStore] allPhotos] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
PA_PhotoCell *cell = [tableView dequeueReusableCellWithIdentifier:#"PhotoCell" forIndexPath:indexPath];
PA_Photo *photo = (self.photos)[indexPath.row];
cell.photoTitle.text = photo.title;
cell.photoOwnerName.text = [NSString stringWithFormat:#"%#", photo.owner];
cell.photoLikes.text = #"99";
// Photo Image URL
NSURL *photoImageURL = [NSURL URLWithString:photo.image_full_url];
[cell.photoImage sd_setImageWithURL:photoImageURL placeholderImage:[UIImage imageNamed:#"lightGraySpinningLoader.gif"]];
// Photo Owner Image
[cell.photoOwnerImage sd_setImageWithURL:photoImageURL placeholderImage:[UIImage imageNamed:#"lightGraySpinningLoader.gif"]];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// This code never gets called when I try to tap on a cell
NSLog(#"A row was selected");
}
- (void)dealloc {
NSLog(#"dealloc called in PA_PhotoTableViewController");
}
and here is the custom cell code PA_PhotoCell (consolidated .h & .m files):
#interface PA_PhotoCell : UITableViewCell
#property (nonatomic, weak) IBOutlet UIImageView *photoImage;
#property (nonatomic, weak) IBOutlet UILabel *photoTitle;
#property (nonatomic, weak) IBOutlet UILabel *photoOwnerName;
#property (nonatomic, weak) IBOutlet UIImageView *photoOwnerImage;
#property (nonatomic, weak) IBOutlet UILabel *photoLikes;
#property (nonatomic, weak) IBOutlet UILabel *photoTimestamp;
#property (nonatomic, weak) IBOutlet UILabel *photoComments;
#end
#implementation PA_PhotoCell
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
NSLog(#"in set selected");
}
-(void)setHighlighted:(BOOL)highlighted {
NSLog(#"in set highlighted");
}
You can see a few NSLog() calls to help me see if anything is getting called.
Where am I going wrong? The end goal is to click on one of the TableViewCell instances and launch a UINavigationController, I know how to do that, but I can't move on to that step until I figure out why my UITableView won't scroll, and why it disappears when I click on it!
EDIT: After much testing, debugging and experimentation, I have been able to conclude that the problem is actually not with the UITableView at all, and it is, in fact, a problem with how the UITableView is being loaded into its parent view. I still haven't found a solution to my problem, but I am getting closer to finding the cause. Here is what I have discovered:
First, when any of the UIButtons at the bottom of the screen are tapped (see photo reference), it loads the relevant instance of UIViewController into a UIView called placeholderView. When I run my problematic UITableView OUTSIDE of this UIView (where the UITableViewController is acting on its own, not embedded within another UIView) then the table works perfectly, it scrolls, it revives click events, and so on. So as soon as I load the UITableView into the UIView, the UITableView becomes unresponsive (it doesn't scroll or receive tap events) and any attempt to interact with it, the UITableView goes completely blank. My debugging session concludes that the NSArray *photos never gets reset to nil, or manipulated in anyway, the table just goes blank.
So does anyone have any ideas on what would cause a UITableView to do this when being loaded into a generic UIView? All the other views that get loaded into this generic UIView are responsive, and behave as expected. Its just this UITableView that is giving me problems.
If you review the graphic I attached to this post (above), you will see that I am using what appears to be a UITabBarView, but it is, in fact, just a generic view with UIButtons inside. The reason I decided to craft my own "UITabBarView look-alike" instead of using the ready-made UITAbBarView class was because I wanted to give custom functionality to the "menu" button on the bottom left (I want a nice UIView to slide in from the left, and stop about 60 pixels from the right of the screen when the "menu" button is tapped, and I can't figure out how to customize the behavior of the UITabBarView, so I opted for this approach.
Here is the code that is actually loading the UITableViewController into the subview (via a CustomStoryboardSegway):
// PA_HomeViewCustomStoryboardSegue.m
#import "PA_HomeViewCustomStoryboardSegue.h"
#import "PA_HomeViewController.h"
#implementation PA_HomeViewCustomStoryboardSegue
// to create a custom segue, you have to override the perform method
-(void)perform {
// get the source and destination view controllers
PA_HomeViewController *segueSourceController = (PA_HomeViewController *)[self sourceViewController];
UIViewController *destinationController = (UIViewController *)[self destinationViewController];
for (UIView *view in segueSourceController.placeholderView.subviews){
[view removeFromSuperview];
}
segueSourceController.currentViewController = destinationController;
[segueSourceController.placeholderView addSubview:destinationController.view];
}
#end
and here is the header file for my PA_HomeViewController (the view the contains the "placeholderView" which is the target view that loads the various UIViewControllers after the user has tapped the UIButtons at the bottom of the view (similar to a TabBarView) :
#interface PA_HomeViewController : UIViewController
#property (weak, nonatomic) IBOutlet UIView *placeholderView;
#property (weak, nonatomic) UIViewController *currentViewController;
#end
I am hoping that I am just missing something obvious in the way that I am loading the UITableView into the placeholderView, and something in there is causing the UITableView to go completely blank.
When you display the UITableView in a different view, you must always make sure that the view controller which "hosts" the UITableView has a strong reference to its controller. In your case, the data source for the UITableView seems to be deallocated after adding the UITableView as subview.
Changing the currentViewController property from weak to strong should fix your problem.
In swift you need to declare viewcontroller object globally that would result in Strong, in case if you declare locally it results in keep disappearing the cells.
e.g.
var refineViewController : RefineViewController?
then you can access that controller using below code that would not result in disappearing cells.
func showRefineView(isFindHomeTab isFindHomeTab : Bool){
refineViewController = RefineViewController(nibName: String(BaseGroupedTableVC),bundle : nil)
refineViewController!.refineSearchDelegate = self
refineViewController!.view.frame = CGRectMake(0, -490, self.view.frame.size.width, self.view.frame.size.height)
UIView.animateWithDuration(0.3, delay: 0.0, options: .CurveEaseOut, animations:
{
self.refineViewController!.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)
self.refineViewController!.isFindHomeTab = isFindHomeTab
}, completion: nil)
self.view.addSubview(refineViewController!.view)
}
I experienced the exact same problem. The issue was that I was using a custom datasource class (called tableVCDataSource), and was setting the tableView's dataSource incorrectly in the ViewController class. I was doing:
override func viewDidLoad() {
mainTableView.dataSource = TableVCDataSource()
}
when I should have been doing:
fileprivate var tableVCDataSource: TableVCDataSource?
override func viewDidLoad() {
tableVCDataSource = TableVCDataSource()
mainTableView.dataSource = tableVCDataSource
}
This solved my issue.

UITableView not displaying when embedded in another view

I am trying to create a view with three big subviews side-by-side. The three subviews should all be UITableViews packaged in UINAvigationControllers. I am using a subclass for UITableViewController named "TOGViewController" here.
When I do set this up, the UITableViews are not updating. The header (from the UINAvigationController) appears, but the space below stays white. When I debug it, I can see that cellForRowAtIndexPath is NEVER called. numberOfSectionsInTableView, numberOfRowsInSection and even heightForRowAtIndexPath are all called. But cellForRowAtIndexPath never!
CODE (only for the first, leftmost subview)
// Create a big scrollview 3 times as wide as the screen and paginate it
CGRect screenRect = self.view.bounds;
CGRect wholeViewRect =screenRect;
wholeViewRect.size.height= screenRect.size.height;
wholeViewRect.size.width= screenRect.size.width * 3.0;
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame: wholeViewRect];
scrollView.contentSize = wholeViewRect.size;
scrollView.contentOffset = CGPointMake(screenRect.size.width, 0);
scrollView.pagingEnabled = TRUE;
self.view = scrollView;
// Add a view to the left
CGRect firstRect = screenRect;
firstRect.size.width -= 1;
TOGViewController *insightsViewController = [[TOGViewController alloc] init];
insightsViewController.view.frame = firstRect;
[self addChildViewController:insightsViewController];
[scrollView addSubview: insightsViewController.view];
When I am using exactly the same TOGViewController (subclass of UITableViewController) and place this directly on the screen it works fine. But as soon as I embed this into a scrollview with two other UITableViews, none of the table views displays anything.
EDIT: I pasted the wrong code in the question from an older version. There are no UINavigationController around each UITableViewController. There is only one UINavigationController for the whole triple view consisting of 3 table views.
If you want multiple UITableViews in one view, each with their own Navigation Controller, you'll want to put each TableView in its own Container View.
Check Apple's documentation and various tutorials available online.
There are various other questions that deal with this topic. The key is to make each UITableView a property of your View:
#property (nonatomic, strong) IBOutlet UITableView* firstTableView;
#property (nonatomic, strong) IBOutlet UITableView* secondTableView;
#property (nonatomic, strong) IBOutlet UITableView* thirdTableView;
You would only keep one delegate and datasource for all of them. Then in your UITableView delegate and datasource methods you would include if statements to check which UITableView you are in.
For example:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
if (tableView == self.firstTableView) {
...
} else if (tableView == self.secondTableView) {
...
} else {
//thirdTableView code
}
}
It sounds like something is messed up with UITableViewDataSource Protocol delegate property on your TableViews. tableView:cellForRowAtIndexPath: is called on the tableView.datasource object. Although I am kinda confused as how tableView:numberOfRowsInSection: is getting called but NOT tableView:cellForRowAtIndexPath:.

IBOutlets in subview are nil

I have a UIViewController,which is associated with custom class MAViewControllerMenu and loads right after the splash screen. In that UIViewController, I have an UIScrollView, which belongs to another class, MASlideShowView, in which the IBOutlet of the UIScrollView is defined and is connected to.
The class for the UIViewController has, among others, the field:
#property MASlideShowView* slideShow;
as a private property for the class that holds the UIScrollView inside it.
Also in the UIViewController,
- (void)viewDidLoad
{
[super viewDidLoad];
//TODO [_slideShow initializeImages];
_slideShow = [[MASlideShowView alloc] initWithModel];
_slideShow.delegate = imageViewController;
}
- (void)viewDidAppear{
[super viewDidAppear:(YES)];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// Set up the content size of the scroll view
//HERE, self.slideShow is allocated, but all the fields it has, including the IBOutlet to the UIScrollView is still nil
CGSize pagesScrollViewSize = self.slideShow.frame.size;
_slideShow.contentSize = CGSizeMake(pagesScrollViewSize.width * self.pageViews.count, pagesScrollViewSize.height);
//Delegate
_slideShow.scrollView.delegate = self;
// Load the initial set of pages that are on screen
[_slideShow loadVisiblePages:YES page_index:0 image:_last_image_taken];
}
Note the error I saw in the comments in the above class
The MASlideShowView file looks like:
h:
#class MASlideShowView;
#protocol slideShowDelegate <NSObject>
-(void)imageViewSelected:(MASlideShowView*)slideShow image:(UIImage*)image;
#end
#interface MASlideShowView : UIScrollView
#property (nonatomic,weak) id<slideShowDelegate> delegate;//delegate to next controller to notify upon picture centered
#property (nonatomic, strong) IBOutlet UIScrollView *scrollView;
#property (nonatomic, strong) IBOutlet UIPageControl *pageControl;
#property (weak, nonatomic) IBOutlet UIButton *rotateImageButton;
#property UIImageView* centered_image_view;
- (IBAction)PageThroughPageControl;
- (IBAction)rotateImageButtonClicked;
- (id)initWithModel;
- (void)pageThroughPageControl;
- (void)addImageToSlideshow:(UIImage*)toAdd;
- (void)loadVisiblePages:(BOOL)use_page_number page_index:(NSInteger)page image:(UIImage*)image;
#end
m:
- (id)initWithModel{
[self initializeImages];
return self;
}
-(void)initializeImages{
// Set up the image you want to scroll & zoom and add it to the scroll view
self.pageViews = [NSMutableArray arrayWithObjects:nil];
NSInteger pageCount = 0;
_imageViewCount = 0;
// Set up the page control
self.pageControl.currentPage = 0;
self.pageControl.numberOfPages = pageCount;
// Set up the array to hold the views for each page
self.pageViews = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < pageCount; ++i) {
[self.pageViews addObject:[NSNull null]];
}
}
My question is simple:
How can I make the UIScrollView initialize?
I know that there's no viewDidAppear as it inherits from UIScrollView.
Thanks
As you are using Interface Builder, I would recommend calling initializeImages inside awakeFromNib:
An awakeFromNib message is sent to each object loaded from the
archive, but only if it can respond to the message, and only after all
the objects in the archive have been loaded and initialized. When an
object receives an awakeFromNib message, it is guaranteed to have all
its outlet instance variables set.
More details here.
Other observations:
As for your code, you have slideShow correctly set by Interface Builder when entering viewDidLoad but you're replacing that instance by assigning _slideShow = [[MASlideShowView alloc] initWithModel], which results in a completely different object.
Moreover your initWithModel doesn't look at all like a correct init method as it doesn't call any of its super's init methods. You should start with Apple's snippet by writing init in an empty line and press escape:
Again the first paragraph of the answer should be enough for your problem.
There's a few ways you could go about fixing this.
One way is like #HoanNguyen mentioned to use awakeFromNib. Personally I don't use this but it's a valid lifecycle event for setup.
Another option is to override initWithCoder: which is the standard initializer storyboards use
- (id)initWithCoder:(NSCoder *)aDecoder{
self = [super initWithCoder:aDecoder];
if (self) {
[self initializeImages];
}
return self;
}
You could then remove your initWithModel call and the storyboard should handle everything.

Subclassing UITableView

I have a UIViewController which I placed UISegmenetedControl with 2 options and beneath I have a UIView which acts as a container for putting my custom UIView (that is actually a UITableView). When switching between segments I would like to switch between 2 different UITableViews.
My problem is with the UITableView.
I have created a custom UIView class with .xib and inside I put a UITableView and I'm able to populate the data into the table and see it correctly.
The problem is with the scrolling, it doesn't react to vertical scrolling at all!
Here is how I created the UIView with its table.
.h file
#interface LeaderboardTableView : UIView
#property (strong, nonatomic) IBOutlet UIView *view;
#property (strong, nonatomic) IBOutlet UITableView *tableView;
#property (strong, nonatomic) NSDictionary *myScore;
#property (strong, nonatomic) NSArray *players;
- (id)initWithBoardType:(LeaderboardType)boardType myScore:(NSDictionary*)myScore leaderboardData:(NSArray*)data;
#end
.m file
#implementation LeaderboardTableView
- (id)initWithBoardType:(LeaderboardType)boardType myScore:(NSDictionary*)myScore leaderboardData:(NSArray*)data {
self = [super init];
if(self) {
_players = data;
_myScore = myScore;
_boardType = boardType;
self.tableView.delegate = self;
self.tableView.dataSource = self;
}
return self;
}
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if(self) {
[self setup];
}
return self;
}
- (void)setup {
[[NSBundle mainBundle] loadNibNamed:#"LeaderboardTableView" owner:self options:nil];
[self addSubview:self.view];
}
Here is my .XIB
What am I doing wrong?? I suspect that my UITableView resides in UIView and that's why I can't scroll but I cannot figure out how to solve this.
Thank you!
Assuming that you use initWithBoardType:myScore:leaderboardData: to instantiate your view, try to change :
self = [super init];
by
self = [self initWithNibName:#"LeaderboardTableView" bundle:[NSBundle mainBundle]];
in this method.
But it's not sure that it will fix your scrolling problem. It looks like if there were a "invisible" view over your table. Let me know how you display your view.
A better idea would be to use one table view and switch out the data source for each different UISegmentedControl tap.
Finally I was able to resolve this problem with a lot of help from zbMax !
Eventually I made my custom Table to subclass UITableViewController with XIB. I implemented all the logic of populating cells and embedded this TableView in my parent view controller, this way I could switch between 2 Views of tables.

xCode Detail View is Empty

I am creating an iPad application (iOS6.1) which has a master detail view concept. First view is a table view has list of items that are been loaded from Plist, when each row gets selected the second table view gets loaded with another Plist. theirs is my Detail view which has to display an UIView with a UILabel ans an UIImage. I am using didSelectRowAtIndexPath method . The first two table Views are been displayed properly and loads the row and display corresponding View but the last detail view which is supposed to display the UILabel and an image is empty, can any one help me to solve this problem
My Code for the didSelectRowAtIndexPath method is
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
TaskDetailViewController *newTaskDetailViewController = [[TaskDetailViewController alloc] init];
// pass the row to newDetailViewController
if (weekNumber == 0)
{
newTaskDetailViewController.taskdescription = [weeklist1 objectAtIndex:indexPath.row];
}
if (weekNumber == 1)
{
newTaskDetailViewController.taskdescription = [weeklist2 objectAtIndex:indexPath.row];
}
if (weekNumber == 2)
{
newTaskDetailViewController.taskdescription = [weeklist3 objectAtIndex:indexPath.row];
}
// ...... repeated for 39 times because of the list
newTaskDetailViewController.taskNumber = indexPath.row;
[self.navigationController pushViewController:newTaskDetailViewController animated:YES];
}
DetailView header
#import <UIKit/UIKit.h>
#interface TaskDetailViewController : UIViewController
#property int taskNumber;
#property(strong , nonatomic) NSString *taskdescription;
#property (nonatomic , strong) NSMutableDictionary * tasks;
#property (strong, nonatomic) IBOutlet UIImageView *questionImage;
#property (strong, nonatomic) IBOutlet UILabel *displayText;
#end
Implemetation file has
#implementation TaskDetailViewController
#synthesize taskNumber;
#synthesize taskdescription;
#synthesize tasks;
#synthesize displayText;
#synthesize questionImage;
-(void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.title = taskdescription;
NSLog(#"%#", taskdescription);
}
Your problem is using alloc init to create an instance of TaskDetailViewController. You've created that controller in the storyboard so you should instantiate it from the storyboard using an identifier that you give it (DetailViewController in my example):
TaskDetailViewController *newTaskDetailViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"DetailViewController"];

Resources