I have a UILabel in a UITableViewCell, I want it to be multilines according to context, and I use masonry to manage autolayout, here is the code
CommunityTableViewCell.m :
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
_postContentLabel = [UILabel new];
_postContentLabel.numberOfLines = 2;
_postContentLabel.font = DefaultFont(15);
_postContentLabel.textColor = COLOR(117, 117, 117);
[self.contentView addSubview:_postContentLabel];
[self makeConstraints];
}
return self;
}
- (void)makeConstraints{
[_postContentLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(_userAvatar);
make.right.equalTo(_groupNameButton);
make.top.equalTo(_postTitleLabel.mas_bottom).offset(20);
make.height.greaterThanOrEqualTo(#20);
}];
}
- (void)updateCellWithModel:(PostsModel *)model{
if (model.content && ![model.content isEqualToString:#""]) {
_postContentLabel.text = model.content;
_postContentLabel.preferredMaxLayoutWidth = _postContentLabel.frame.size.width;
[_postContentLabel sizeToFit];
} else{
_postContentLabel = nil;
[_postContentLabel removeFromSuperview];
}
[self updateConstraints];
}
- (void)updateConstraints {
//some other code here
[super updateConstraints];
}
CommunityViewController.m :
- (void)viewDidLoad {
[super viewDidLoad];
_communityTableView = [UITableView new];
_communityTableView.delegate = self;
_communityTableView.dataSource = self;
_communityTableView.estimatedRowHeight = 80;
_communityTableView.rowHeight = UITableViewAutomaticDimension;
[_communityTableView registerClass:[CommunityTableViewCell class] forCellReuseIdentifier:#"CommunityTableViewCell"];
[self.view addSubview:_communityTableView];
[self makeConstraints];
[self requestPostData];
}
- (void)makeConstraints{
[_communityTableView mas_makeConstraints:^(MASConstraintMaker *make) {
UIEdgeInsets padding = UIEdgeInsetsMake(0, 0, 0, 0);
make.edges.equalTo(self.view).insets(padding);
}];
}
- (void)requestPostData{
[[NetEngine engine] GET:[NSString stringWithFormat:#"posts"] success:^(id responseObject) {
//receive the data
[self.communityTableView reloadData];
} failure:^(NSError *error) {
}];
}
#pragma mark - TableView DataSource & Delegate
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return _postArrary.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
CommunityTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CommunityTableViewCell" forIndexPath:indexPath];
PostsModel *model = _postArrary[indexPath.row];
//some other code
[cell updateCellWithModel:model];
return cell;
}
enter code here
It doesn't show up to 2 lines as I wish, it shows only one line, but when I scroll down and back or pull to refresh the tableview, it shows 2 lines.
I don't know what's going on.
Related
After opening the side menu, whenever I click any item of it the side menu goes totally blank and displays only a white screen.
How can I solve this issue?
viewCotroller file:
enum TranslateDirection {
LEFT, RIGHT
};
const float TRANSLATE_CONST = 250;
float translateX = TRANSLATE_CONST;
enum TranslateDirection td = RIGHT;
bool flag = 0;
- (void)viewDidLoad {
[super viewDidLoad];
NavViewController *view;
view = [self.storyboard instantiateViewControllerWithIdentifier:#"navigationView"];
[self.navigationController.view.window insertSubview:view.view atIndex:0];
// Do any additional setup after loading the view, typically from a nib.
}
- (IBAction)showMenu:(id)sender {
[UIView animateWithDuration:0.5f
delay:0.02
options:UIViewAnimationOptionCurveEaseIn
animations:^{
if (td == LEFT) {
translateX = 0;
} else if (td == RIGHT) {
translateX = TRANSLATE_CONST;
}
CGAffineTransform trans = CGAffineTransformMakeTranslation(translateX, 0);
self.navigationController.view.transform = trans;
}
completion:^(BOOL finished){
if (td == LEFT) {
td = RIGHT;
} else if (td == RIGHT) {
td = LEFT;
}
}
];
/*if (flag == 0) {
[_showMenubar setStyle:UIBarButtonSystemItemAdd];
flag = 1;
} else {
flag = 0;
}*/
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)menu:(id)sender {
}
#end
sideMenuFile Code:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
//_navItems = [[NSMutableArray alloc] initWithObjects:#"abc", #"abc", #"abc", nil];
_navItems = [NSArray arrayWithObjects:#"Inbox", #"* Important and unread", #"* Starred", #"* Everything", #"Sent Mail", #"Drafts", #"Spam" ,nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return #"Hello";
}
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
return #" bye";
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [_navItems count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *SimpleIdentifier = #"SimpleIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SimpleIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SimpleIdentifier];
}
// Configure the cell...
/*cell.textLabel.font = [UIFont fontWithName:#"Sans Serif" size:12];
cell.textLabel.textColor = [UIColor whiteColor];
cell.textLabel.backgroundColor = [UIColor clearColor];*/
cell.textLabel.text = [_navItems objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
}
I want to resize the tableviewcell when SDWebImage download finished.
Where should I put [UITableViewCell setNeedsUpdateConstraints]?
Or just send notification to UIViewController and reload tableview data?
ViewController.m
#import "ViewController.h"
#import <Masonry/Masonry.h>
#import <SDWebImage/UIImageView+WebCache.h>
#define WEAKSELF typeof(self) __weak weakSelf = self;
#interface ViewController ()
<UITableViewDataSource, UITableViewDelegate> {
UITableView *myTableView;
}
#property (nonatomic, retain) NSArray *items;
#end
#implementation ViewController
- (UIRectEdge)edgesForExtendedLayout {
return UIRectEdgeNone;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(reloadRows:)
name:#"ReloadRows"
object:nil];
NSMutableArray *array = [NSMutableArray array];
for (NSInteger i = 0; i < 30; i ++) {
CGFloat width = arc4random() % 100 + 20.0f;
CGFloat height = arc4random() % 100 + 20.0f;
CGSize size = CGSizeMake(width, height);
[array addObject:[NSValue valueWithCGSize:size]];
}
self.items = array;
myTableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
myTableView.dataSource = self;
myTableView.delegate = self;
myTableView.estimatedRowHeight = 60.0f;
myTableView.rowHeight = UITableViewAutomaticDimension;
[self.view addSubview:myTableView];
UIView *superview = self.view;
[myTableView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.top.bottom.equalTo(superview);
}];
}
- (void)reloadRows:(NSNotification *)notification {
NSIndexPath *ip = notification.object;
if (ip) {
TestCell *cell = [myTableView cellForRowAtIndexPath:ip];
[cell setNeedsUpdateConstraints];
[myTableView reloadRowsAtIndexPaths:#[ip] withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
#pragma mark - UITableViewDataSource, UITableViewDelegate
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.items count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellID = #"Contact_People_Cell";
TestCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (!cell) {
cell = [[TestCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
NSValue *value = [self.items objectAtIndex:indexPath.row];
cell.imageSize = [value CGSizeValue];
[cell refreshInterface];
return cell;
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
}
#end
TestCell
#define SIZE_DEFAULT CGSizeMake(140.0f, 100.0f)
#interface TestCell () {
UIImageView *imv;
}
#end
#implementation TestCell
#synthesize imageSize;
#synthesize indexPath;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
[self setupView];
}
return self;
}
- (void)setupView {
imv = [[UIImageView alloc] initWithFrame:CGRectZero];
imv.backgroundColor = [UIColor darkGrayColor];
[self.contentView addSubview:imv];
self.translatesAutoresizingMaskIntoConstraints = NO;
UIView *superView = self.contentView;
[imv mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.equalTo(#(SIZE_DEFAULT.width));
make.height.equalTo(#(SIZE_DEFAULT.height));
make.left.top.bottom.equalTo(superView).with.offset(10.0f);
}];
}
- (void)updateConstraints {
[super updateConstraints];
UIView *superView = self.contentView;
[imv mas_updateConstraints:^(MASConstraintMaker *make) {
make.left.top.equalTo(superView).with.offset(10.0f);
make.bottom.equalTo(superView).with.offset(-10.0f);
make.width.equalTo(#(ceilf(self.imageSize.width)));
make.height.equalTo(#(ceilf(self.imageSize.height)));
}];
}
- (void)refreshInterface {
WEAKSELF
[imv sd_setImageWithURL:[NSURL URLWithString:#"http://www.baidu.com"]
placeholderImage:nil
options:SDWebImageProgressiveDownload
progress:^(NSInteger receivedSize, NSInteger expectedSize) {}
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
imv.backgroundColor = [UIColor purpleColor];
dispatch_async(dispatch_get_main_queue(), ^{
CGFloat width = arc4random() % 100 + 140.0f;
CGFloat height = arc4random() % 100 + 140.0f;
CGSize size = CGSizeMake(width, height);
weakSelf.imageSize = size;
[weakSelf setNeedsUpdateConstraints];
// NSIndexPath *ip = [weakSelf.indexPath copy];
// [[NSNotificationCenter defaultCenter] postNotificationName:#"ReloadRows" object:ip];
});
}];
}
#end
Use self-sized cells. After load image, change height constraint of UIImage and call reloadRowsAtIndexPaths: method
implement tableView heightForRowAtIndexPath: method to change the cell height as per downloaded image height
In my app I have a popup with a [table view][1] .
When compiled with Xcode 5.1 everything works fine, but the same code compiled with Xcode 6.1 failed to call the [cellForRowAtIndexPath][3] [delegate][4] method.
The other delegate meths are called.
One intersting point is self.tableView.rowHeight; returns -1
I have tried explicitly setting the delegate and data source to self but that makes not difference
The class is called by the following code;
`-(IBAction)selectLanguage:(id)sender
{
ATLMLanguagePopoverTableViewController *pvc = [[ATLMLanguagePopoverTableViewController alloc] initWithNibName:nil bundle:nil];
pvc.target = self;
pvc.action = #selector(popoverDidSelectItem:);
pvc.items = [[[ATLMLibraryManager getManager]libraryDefaults]getAvailableLanguageNames];
_myPopoverController.contentViewController = pvc;
[_myPopoverController setPopoverContentSize:[pvc popoverContentSize]];
[_myPopoverController presentPopoverFromBarButtonItem:(UIBarButtonItem *)sender permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}
`
Hear is the definition of the class
/
/ LanguagePopoverTableViewController.m
// SalesAid
//
// Created by phuang on 1/16/13.
// Copyright (c) 2013 Align Technology. All rights reserved.
//
#import "ATLMLanguagePopoverTableViewController.h"
#import "ATLMLocalizationManager.h"
#import "ATLMUtils.h"
#interface ATLMLanguagePopoverTableViewController ()
#end
#implementation ATLMLanguagePopoverTableViewController
#synthesize items, selectedItem, target, action;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
selectedItem = -1;
target = nil;
action = NULL;
}
return self;
}
-(void) resetLocalization {
[self.tableView reloadData];
}
- (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)setItems:(NSArray *)newItems {
items = [newItems copy];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
selectedItem=0;
NSString *curLang = (NSString *) [[ATLMLocalizationManager getManager]getCurrentLanguage] ;
for(int i = 0; i < items.count ; i++ ){
if([curLang isEqualToString:(NSString *)[items objectAtIndex:i]]){
selectedItem = i;
break;
}
}
NSIndexPath *i = [NSIndexPath indexPathForRow:selectedItem inSection:0];
[self.tableView selectRowAtIndexPath:i animated:NO scrollPosition:UITableViewScrollPositionNone];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
- (CGSize)popoverContentSize {
NSInteger rowHeight = self.tableView.rowHeight;
UITableView *tv = self.tableView;
rowHeight = 50;
return CGSizeMake(100, [items count] * rowHeight);
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [items count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.font = [UIFont systemFontOfSize:14];
UIView *myBackView = [[UIView alloc] initWithFrame:cell.frame];
myBackView.backgroundColor = [ATLMUtils getAlignBlue];
cell.selectedBackgroundView = myBackView;
[cell setSelectedBackgroundView: myBackView ];
NSString *textLabelKey = [items objectAtIndex:[indexPath indexAtPosition:1]];
cell.textLabel.text = ATLMLocalizedString(textLabelKey, nil);
cell.textLabel.textAlignment = NSTextAlignmentCenter;
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
selectedItem = indexPath.row;
if (target != nil && action != NULL) {
[target performSelector:action withObject:self];
}
}
#end
`
OK to answer my own question;
Basically the code adds the model to the view controller after the init method is called. However is seem the thread model has changed a bit and the view is created before the model is added so the row count in the model is zero
The solution is to pass the model as part of the init method.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil items:(NSArray *)itemArray
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
items = [itemArray copy];
selectedItem = -1;
target = nil;
action = nil;
}
return self;
}
I have a UITableView for an Instagram feed. I have implemented UIRefreshControl for pull to refresh functionality.
After drag and release the refresh control, and while the spinner is going, I'm able to drag the tableview down without the app crashing. However, if I scroll the tableview upwards, the app crashes (maybe because of cell 2, 3 etc?)
Here's a video showing the problem: http://www.screenmailer.com/v/DukT4lt2aUGm8c5MLRlGMg/2586/3a23tXo7uXs.mp4
Why is this happening?
Code for the .m file:
#import "InstagramViewController.h"
#import "InstagramCell.h"
#import <InstagramKit/InstagramKit.h>
#import "UIImageView+AFNetworking.h"
#interface InstagramViewController ()
{
NSMutableArray *mediaArray;
}
#property (nonatomic, strong) InstagramPaginationInfo *currentPaginationInfo;
#end
#implementation InstagramViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
//mediaArray = [[NSMutableArray alloc] init];
}
return self;
}
- (void)viewDidLoad
{
mediaArray = [[NSMutableArray alloc] init];
[super viewDidLoad];
[self loadMedia];
self.refreshControl = [[UIRefreshControl alloc] init];
[self.refreshControl addTarget:self action:#selector(reloadMedia) forControlEvents:UIControlEventValueChanged];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
-(void)reloadMedia
{
self.currentPaginationInfo = nil;
[mediaArray removeAllObjects];
[self loadMedia];
}
-(IBAction)loadMedia
{
// start network indicator
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
[[InstagramEngine sharedEngine] getMediaWithTagName:#"AUFsommer" count:10 maxId:self.currentPaginationInfo.nextMaxId withSuccess:^(NSArray *media, InstagramPaginationInfo *paginationInfo) {
if (paginationInfo)
{
self.currentPaginationInfo = paginationInfo;
}
[mediaArray addObjectsFromArray:media];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
[self reloadData];
} failure:^(NSError *error) {
NSLog(#"Search Media Failed");
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
}];
}
-(void)reloadData
{
[self.refreshControl endRefreshing];
[self.tableView reloadData];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *headerView = [[UIView alloc] init];
headerView.backgroundColor = [UIColor colorWithWhite:1.0f alpha:0.9f];
InstagramMedia *media = mediaArray[section];
// create imageview for profile photo
AsyncImageView *profilePhoto = [[AsyncImageView alloc] initWithFrame:CGRectMake(8, 8, 32, 32)];
profilePhoto.layer.borderColor = [[UIColor colorWithRed:204.0/255.0f green:204.0/255.0f blue:204.0/255.0f alpha:1.0f] CGColor];
profilePhoto.layer.borderWidth = 1;
profilePhoto.layer.masksToBounds = YES;
profilePhoto.layer.cornerRadius = 16.0;
[profilePhoto loadImageFromURL:[media.user.profilePictureURL absoluteString]];
// uifont settings
UIFont *labelFont = [UIFont boldSystemFontOfSize:13.0];
// create label for username
UILabel *usernameLabel = [[UILabel alloc] initWithFrame:CGRectMake(48, 0, 210, 48)];
usernameLabel.text = media.user.username;
usernameLabel.font = labelFont;
usernameLabel.textColor = [UIColor colorWithRed:235.0/255.0 green:24.0/255.0 blue:22.0/255.0 alpha:1.0f];
// create label for timestamp
UILabel *timestampLabel = [[UILabel alloc] initWithFrame:CGRectMake(250, 0, 54, 48)];
timestampLabel.textAlignment = NSTextAlignmentRight;
timestampLabel.font = labelFont;
// timestampLabel.text = [self stringForDisplayFromDate:media.createdDate];
// add to view
[headerView addSubview:profilePhoto];
[headerView addSubview:usernameLabel];
[headerView addSubview:timestampLabel];
return headerView;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return mediaArray.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
InstagramCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[InstagramCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// clear photo
[cell.igPhoto setImage:nil];
if (mediaArray.count >= indexPath.section+1)
{
InstagramMedia *media = mediaArray[indexPath.section];
cell.title.text = media.caption.text;
[cell.igPhoto loadImageFromURL:[media.standardResolutionImageURL absoluteString]];
}
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
InstagramMedia *media = mediaArray[indexPath.section];
CGSize maximumLabelSize = CGSizeMake(304.0f, 20000.0f);
CGSize expectedLabelSize = [media.caption.text sizeWithFont:[UIFont systemFontOfSize:13.0f] constrainedToSize:maximumLabelSize lineBreakMode:NSLineBreakByWordWrapping];
return (320.0f + expectedLabelSize.height + 20.0f);
}
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
CGFloat currentOffset = scrollView.contentOffset.y;
CGFloat maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height;
if (maximumOffset - currentOffset < 10.0)
{
[self loadMedia];
}
}
#end
The first thing you should do is to add an exception breakpoint in your project, so you will know why and where it crashes.
The reason why your app is crashing is that you try to read in an empty array. In the method reloadMedia, you do this :
self.currentPaginationInfo = nil;
[mediaArray removeAllObjects];
So at this point, your array is empty, but your UITableView is not aware of that. By scrolling before your data is reloaded, the methods cellForRowAtIndexPath will get called and try to access an index in your empty array.
To fix this, you can call [self.tableView reloadData]; after [mediaArray removeAllObjects];. This way, the UITableView will makes its call to know how many rows and sections it should have and will be aware there is no more rows and sections.
Or, if you want the old information to still be in your UITableView during the loading, just don't nil the currentPaginationInfo or empty mediaArray in reloadMedia,
This question already has answers here:
UITableView cells strangely disappearing
(2 answers)
Closed 9 years ago.
Very strange problem here.
Essentially what is happening is that our Tableview cells are becoming hidden in some cases when we simply put the app to sleep and then re-unlock. Our normal tableview looks like this:
And then when we re-open the app it will look like this:
All the rows and sections are set correctly, yet the cells are hidden.:
When this happens, our cellForRowAtIndexPath no longer gets called. This surely has to be the problem. Has anyone ever seen behavior like this? Here is how we set up the tableview. (sorry it is long)
//
// SPHomeViewController.m
// Spek
#interface SPHomeViewController () <UITableViewDataSource, UITableViewDelegate, MKMapViewDelegate, SPCreationViewDelegate, UIAlertViewDelegate, CLLocationManagerDelegate>
#property (nonatomic, strong) UITableView* tableView;
#property (nonatomic, strong) NSMutableArray* tableDatasource;
#property (nonatomic, strong) NSMutableArray* datasource;
#property (nonatomic, strong) NSMutableArray* friendsDatasource;
#property (nonatomic, strong) UISegmentedControl* userFilterSegment;
#property (nonatomic) BOOL isLoadingData;
#end
#implementation SPHomeViewController
#synthesize datasource = _datasource;
#synthesize friendsDatasource = _friendsDatasource;
#synthesize tableDatasource = _tableDatasource;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
//[[SPLocationManager locationManager] startUpdatingLocationForSig];
[self setNeedsStatusBarAppearanceUpdate];
self.view.backgroundColor = [UIColor colorWithRed:230.0f/255.0f green:230.0f/255.0f blue:230.0f/255.0f alpha:1.0];
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - kTopBarHeight)];
self.tableView.separatorColor = [UIColor clearColor];
self.tableView.backgroundColor = [UIColor clearColor];
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.view addSubview:self.tableView];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
if (self.creationView.center.y > self.view.frame.size.height) {
self.creationView = nil;
}
NSLog(#"Mem warning");
}
//****************************************
//****************************************
#pragma mark - UITableViewDelegate/DataSource
//****************************************
//****************************************
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"INDEX PATH ROW: %d AND SECTION: %d", indexPath.row, indexPath.section);
if (indexPath.section == 0) {
UITableViewCell* cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"SPMapCellSpace"];
cell.backgroundColor = [UIColor clearColor];
cell.backgroundView = [[UIView alloc] init];
cell.selectedBackgroundView = [[UIView alloc] init];
return cell;
} else if (indexPath.section == self.tableDatasource.count + 1) {
UITableViewCell* cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"SPBottomCellSpace"];
cell.backgroundColor = [UIColor clearColor];
cell.backgroundView = [[UIView alloc] init];
cell.selectedBackgroundView = [[UIView alloc] init];
return cell;
}
SPMark* mark = self.tableDatasource[indexPath.section - 1];
NSString* reuseId = [SPHomeViewController cellIdentifierFromData:mark];
SPTableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:reuseId];
if (cell == nil) {
cell = [SPTableViewCell cellFromMark:mark reuseID:reuseId];
[cell updateView:YES];
}
[cell addDataToCell:mark];
if (indexPath.section >= self.tableDatasource.count - 2 && !self.isLoadingData && self.pageNumber != -1) {
self.fetchNextPage = YES; // When the scrollview stops it will load more data if available.
}
return cell;
}
- (unsigned int)getPageNumber {
return (self.userFilterSegment.selectedSegmentIndex == 0) ? self.pageNumber : self.friendsPageNumber;
}
- (void)setCurrentPageNumber:(unsigned int)page {
if (self.userFilterSegment.selectedSegmentIndex == 0) {
self.pageNumber = page;
} else {
self.friendsPageNumber = page;
}
}
- (void)incrementCurrentPageNumber {
if (self.userFilterSegment.selectedSegmentIndex == 0) {
self.pageNumber++;
} else {
self.friendsPageNumber++;
}
}
// Every cell has a section header so this should be equal to the number of speks returned from the server
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSLog(#"section count is: %d",self.tableDatasource.count + 2 );
return self.tableDatasource.count + 2; // Add two because the mapview needs to go on the top and extra spacing at the bottom.
}
// There is a section for every cell, so there is only one cell per section
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0) {
return kMapHeight+2;
} else if (indexPath.section == self.tableDatasource.count + 1) {
return kExtraSpaceBelowHomeView;
}
SPMark* mark = self.tableDatasource[indexPath.section - 1];
return [SPTableViewCell cellHeightForMark:mark];
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0 || indexPath.section == self.tableDatasource.count + 1) {
cell.backgroundColor = [UIColor clearColor];
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0 || indexPath.section == self.tableDatasource.count + 1)
return;
SPMark* mark = self.datasource[indexPath.section - 1 ];
SPMarkViewController* markVC = [SPMarkViewController withMark:mark];
[markVC displayData];
[self.navigationController pushViewController:markVC animated:YES];
}
-(void)reloadTableview {
[self.tableView setDelegate:self];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
[self.tableView setNeedsDisplay];
});
}
- (void)showNoItems {
if (self.tableDatasource.count == 0 && self.accuracyBad == NO) {
self.opaqueIcon.hidden = NO;
self.noItems.hidden = NO;
self.beTheFirst.hidden = NO;
self.downArrow.hidden = NO;
self.noItemsBackround.hidden = NO;
[self.view bringSubviewToFront:self.noItemsBackround];
[self.view bringSubviewToFront:self.downArrow];
[self.view bringSubviewToFront:self.beTheFirst];
[self.view bringSubviewToFront:self.noItems];
[self.view bringSubviewToFront:self.opaqueIcon];
}
}
- (void)showTableView {
if (self.tableDatasource.count != 0) {
self.noItems.hidden = YES;
self.beTheFirst.hidden = YES;
self.downArrow.hidden = YES;
self.noItemsBackround.hidden = YES;
self.opaqueIcon.hidden = YES;
[self.view sendSubviewToBack:self.noItemsBackround];
[self.view sendSubviewToBack:self.downArrow];
[self.view sendSubviewToBack:self.beTheFirst];
[self.view sendSubviewToBack:self.noItems];
[self.view sendSubviewToBack:self.opaqueIcon];
}
}
//****************************************
//****************************************
#pragma mark - Setters/Getters
//****************************************
//****************************************
- (NSMutableArray*)datasource {
if (!_datasource) {
_datasource = [NSMutableArray array];
if (!self.firstLoad) {
[self loadDataForPagination:NO];
}
}
return _datasource;
}
- (NSMutableArray*)friendsDatasource {
if (!_friendsDatasource) {
_friendsDatasource = [NSMutableArray array];
if (!self.firstLoad) {
[self loadDataForPagination:NO];
}
}
return _friendsDatasource;
}
- (NSMutableArray*)tableDatasource {
if (!_tableDatasource) {
_tableDatasource = (self.userFilterSegment.selectedSegmentIndex == 0) ? self.datasource : self.friendsDatasource;
}
return _tableDatasource;
}
- (SPCreationView*)creationView {
if (!_creationView) {
UIView* window = [SPUtils getAppDelegate].window;
CGSize viewSize = window.frame.size;
CGRect startFrame = CGRectMake(0, viewSize.height, [SPUtils screenWidth], [SPUtils screenHeight]);
_creationView = [SPCreationView creationView:startFrame delegate:self];
[window insertSubview:_creationView belowSubview:self.creationButton];
_creationView.frame = startFrame;
}
return _creationView;
}
- (void)setTableDatasource:(NSMutableArray *)tableDatasource {
_tableDatasource = tableDatasource;
[self preFetchImages];
dispatch_async(dispatch_get_main_queue(), ^{
if(_tableDatasource == nil || _tableDatasource.count == 0) {
[self showNoItems];
} else {
[self showTableView];
}
[self reloadTableview];
});
}
- (void)setDatasource:(NSMutableArray *)datasource {
_datasource = datasource;
}
- (void)setFriendsDatasource:(NSMutableArray *)friendsDatasource {
_friendsDatasource = friendsDatasource;
}
#end
If you think it's a AppDelegate problem, we don't do anything with this controller in there, so I don't see how it could be.
I've only seen this occur previously when I was reloading data (incorrectly) from a background thread. I see you're trying to push the reloads onto the main thread already.
It looks like you're flailing a bit trying to be sure updates are occurring on the main thread. You should probably just verify that your actions are occurring on main by checking [NSThread isMainThread] rather than making your code async to the main thread, making lots of async flow changes can lead to unexpected behavior.
That said, since this only happens on wake from sleep maybe you have some background mode on and you aren't updating the UI from the correct thread there?