UITableView reloadData lags wrong offset - ios

I'm making some kind of Facebook timeline similar app when new posts are added at certain offset of UITableView. After adding new posts to dataSource I [self.tableView reloadData] and everything is fine except small lag and sometimes wrong offset (+/- 150 px sometime depending in which direction you are scrolling).
Code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"PostCell";
PostCell *postCell = (PostCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
Post *post = self.displayPosts[indexPath.row];
[postCell setPost:post];
return postCell;
}
- (void)updatePosts
{
[[APIClient sharedInstance] downloadPostsForPage:_currentPage withSuccessionBlock:^(NSArray *posts) {
NSLog(#"Display new posts!");
[self.displayPosts addObjectsFromArray:posts];
[self.mainTableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
_isLoadingMore = NO;
} failureBlock:^(NSError *err) {
// handle error
[self handleError:err];
}];
}
Post Cell:
#interface PostCell ()
#property (weak, nonatomic) IBOutlet PostView *postView;
#property (nonatomic, strong) Post *post;
#end
#implementation PostCell
- (void)setPost:(Post *)newPost
{
self.postView.post = newPost;
}
PostView:
- (void)setPost:(Post *)newPost
{
if (_post != newPost) {
_post = newPost;
}
[self layoutSubviews];
[self refreshContent];
}
- (void)layoutSubviews
{
[super layoutSubviews];
// define title attributes
NSDictionary *attributes = #{
NSForegroundColorAttributeName : [UIColor blackColor],
NSFontAttributeName : [UIFont systemFontOfSize:20.0f]};
CGFloat boundingTitleWidth = self.bounds.size.width - LEFT_TITLE_OFFSET - RIGHT_TITLE_OFFSET;
CGRect titleRect = [_post.title boundingRectWithSize:CGSizeMake(boundingTitleWidth, CGFLOAT_MAX) options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading) attributes:attributes context:nil];
if (self.titleLabel == nil) {
self.titleLabel = [[UILabel alloc] init];
[self addSubview:self.titleLabel];
}
[self.titleLabel setFrame:CGRectMake(LEFT_TITLE_OFFSET, TOP_TITLE_OFFSET, titleRect.size.width, titleRect.size.height)];
[self.titleLabel setNumberOfLines:0];
[self.titleLabel sizeToFit];
// Draw the quarter image.
CGFloat imageY = TOP_TITLE_OFFSET + titleRect.size.height + TOP_IMAGE_OFFSET;
CGPoint point = CGPointMake(LEFT_IMAGE_OFFSET, imageY);
CGSize imageSize = self.post.image.size;
if (self.imageView == nil) {
self.imageView = [[UIImageView alloc] init];
[self addSubview:self.imageView];
}
[self.imageView setFrame:CGRectMake(point.x, point.y, imageSize.width, imageSize.height)];
}
- (void)refreshContent
{
[self.titleLabel setText:_post.title];
[self.imageView setImage:self.post.image];
}
Any help?
Thanks.

Related

How to change UITableViewCell height when download image finished?

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

How to add UIImageView on popup block in ios

Hi I am very new to iOS and in my project iI have created one UITableView with images as like my below screen ok that's fine
And here when I tapped on tableView images I want show that related row images with popup block using one UIView.
But using my code image is not showing on popup UIView. Please see my below screen image is not adding on UIView popup block please help me some one.
My Code:
#import "imageTableViewController.h"
#interface imageTableViewController ()<UITableViewDataSource,UITableViewDelegate>
{
UITableView *mainTable;
NSMutableArray *imageArray;
UIButton *imageButton;
UIView *popUpView;
BOOL isFullScreen;
CGRect prevFrame;
}
#end
#implementation imageTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
imageArray = [[NSMutableArray alloc] initWithObjects:#"flower.jpeg",#"Bird.jpg",#"Browser.jpeg", nil];
mainTable = [[UITableView alloc] initWithFrame:CGRectMake(0, 20, 320, 480)];
mainTable.dataSource = self;
mainTable.delegate = self;
[self.view addSubview:mainTable];
popUpView = [[UIView alloc] initWithFrame:CGRectMake(30, 30, 25, 25)];
popUpView.backgroundColor = [UIColor orangeColor];
popUpView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.001, 0.001);
[mainTable addSubview:popUpView];
UIImageView * imageView = [[UIImageView alloc] initWithFrame:CGRectMake(5, 5, 20, 20)];
imageView.image = [UIImage imageNamed:#"flower.jpeg"];
[popUpView addSubview:imageView];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return imageArray.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];
}
imageButton = [[UIButton alloc] initWithFrame:CGRectMake(10, 10, 50, 50)];
[imageButton setImage:[UIImage imageNamed:[imageArray objectAtIndex:indexPath.row]] forState:UIControlStateNormal];
[imageButton addTarget:self action:#selector(imgToFullScreen:) forControlEvents:UIControlEventTouchUpInside];
[Cell.contentView addSubview:imageButton];
return Cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 60;
}
-(void)imgToFullScreen:(UITapGestureRecognizer*)sender {
if (!isFullScreen) {
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
popUpView.hidden = NO;
prevFrame = CGRectMake(30, 30, 25, 25);
[popUpView setFrame:CGRectMake(120, 50, 150, 150)];
}completion:^(BOOL finished){
isFullScreen = TRUE;
}];
return;
}
else{
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
[popUpView setFrame:prevFrame];
}completion:^(BOOL finished){
isFullScreen = FALSE;
popUpView.hidden = YES;
}];
return;
}
}
Looks like it's happened because of
popUpView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.001, 0.001);
you create view and scale it to really small, also all subview will be downscaled. And then in show animation block you change frame of popup, but you have to change scale like:
popUpView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1, 1);
Edit due comment
hmm yes that's fine and one small problem is coming #in.disee that is
when i zoom in popup block images are popup like my above screen and
when i zoom out that images are must zoom out near related
rows,understand?
Your current realisation have few problems including:
Your architecture do not allow you get index path of selected cell - it will be a problem anyway, so among other you have to make this part.
It will be too hard explain in words everything you have to chage, so i write code for you) I almost do not change your code, but it would be cool if you change it to the way i write mine, because it's more convenient to apple guides
What i do:
1) create custom class for cell
2) add ability for cell say something to tableview via delegation pattern
3) when user click on button in cell - cell tells to tableview, which button of which was was pressed
4) table view convert frame of cell's image to own coordinates and show popup
you can just replace you code with this one:
#import "imageTableViewController.h"
#class CustomCell;
#protocol CustomCellDelegate <NSObject>
- (void)didSelectImageNamed:(NSString *)name fromCell:(CustomCell *)cell;
#end
#interface CustomCell : UITableViewCell
#property (nonatomic, strong) NSString *imageName;
#property (nonatomic, strong) UIButton *imageBtn;
#property (nonatomic, weak) id <CustomCellDelegate> delegate;
#property (nonatomic, assign, readonly) CGRect imageRect;
#end
#implementation CustomCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self){
[self setup];
}
return self;
}
- (CGRect)imageRect {
return self.imageBtn.frame;
}
- (void)setup {
self.imageBtn = [[UIButton alloc] initWithFrame:CGRectMake(10, 10, 50, 50)];
[self.imageBtn addTarget:self action:#selector(imgToFullScreen:) forControlEvents:UIControlEventTouchUpInside];
[self.contentView addSubview:self.imageBtn];
}
- (void)prepareForReuse {
[self.imageBtn setImage:nil forState:UIControlStateNormal];
}
- (void)setImageName:(NSString *)imageName {
_imageName = imageName;
[self.imageBtn setImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal];
}
- (void)imgToFullScreen:(UIButton *)sender {//btw it's not UITapGestureRecognizer *
[self.delegate didSelectImageNamed:self.imageName fromCell:self];
}
#end
#interface imageTableViewController ()
<CustomCellDelegate>
#end
#implementation imageTableViewController {
UITableView *mainTable;
NSMutableArray *imageArray;
UIButton *imageButton;
UIView *popUpView;
BOOL isFullScreen;
CGRect prevFrame;
}
- (void)viewDidLoad {
[super viewDidLoad];
imageArray = [[NSMutableArray alloc] initWithObjects:#"flower.jpeg",#"Bird.jpg",#"Browser.jpeg", nil];
mainTable = [[UITableView alloc] initWithFrame:CGRectMake(0, 20, 320, 480)];
mainTable.dataSource = self;
mainTable.delegate = self;
[self.view addSubview:mainTable];
popUpView = [[UIView alloc] initWithFrame:CGRectMake(30, 30, 25, 25)];
popUpView.backgroundColor = [UIColor orangeColor];
popUpView.hidden = YES;
[mainTable addSubview:popUpView];
UIView * imageView = [[UIView alloc] initWithFrame:CGRectMake(5, 5, 20, 20)];
imageView.backgroundColor = [UIColor colorWithRed:255./255. green:0 blue:0 alpha:1];
[popUpView addSubview:imageView];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return imageArray.count;
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"cell";
CustomCell *Cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (Cell == nil)
{
Cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
Cell.delegate = self;
}
Cell.imageName = [imageArray objectAtIndex:indexPath.row];
return Cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 60;
}
-(void)imgToFullScreen:(NSString *)imageName fromRect:(CGRect)frame {
if (!isFullScreen) {
[popUpView setFrame:frame];
[popUpView setHidden:NO];
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
[popUpView setFrame:CGRectMake(120, 50, 150, 150)];
}completion:^(BOOL finished){
isFullScreen = YES;
prevFrame = frame;
}];
return;
}
else{
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
[popUpView setFrame:prevFrame];
}completion:^(BOOL finished){
isFullScreen = NO;
popUpView.hidden = YES;
}];
return;
}
}
#pragma mark - CustomCellDelegate
- (void)didSelectImageNamed:(NSString *)name fromCell:(CustomCell *)cell {
CGRect imageFrame = cell.imageRect;
CGRect imageFrameGlobalCoord = [mainTable convertRect:imageFrame fromView:cell];
[self imgToFullScreen:name fromRect:imageFrameGlobalCoord];
}
#end

App crashes while reloading and scrolling tableview one direction

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,

UITableView skips one indexPath between every one of custom UITableViewCell, disappears when scrolling

The problem in pictures:
Basically, my table view adds an empty cell between each other, and I don't know why. I already tried putting an NSLog statement in cellForRowAtIndexPath:, willDisplayCell:forRowAtIndexPath:, and didSelectRowAtIndexPath:, and the data source in each cell's indexPath is correct. It's just that the displayed cells are skipping in between, and I don't understand why.
My view controller and table view cell subclasses are also very simple. Here's the code:
PrivateMessagesViewController.m
static NSString * const kCellIdentifier = #"kCellIdentifier";
#interface PrivateMessagesViewController () <UITableViewDataSource, UITableViewDelegate>
#property (strong, nonatomic) NSMutableArray *messages;
#property (strong, nonatomic) SCPFInboxQuery *query;
#property (nonatomic) BOOL hasAlreadyFetchedBefore;
#property (strong, nonatomic) UITableView *tableView;
// This is a custom view that either shows a loading animation,
// a "No Results Found" label, or an error message with a Retry button
// at the center of the view of a view controller.
#property (strong, nonatomic) SCPCenterView *centerView;
#end
#implementation PrivateMessagesViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"Private Messages";
self.messages = [NSMutableArray array];
self.query = [[SCPFInboxQuery alloc] init];
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, [UIScreen mainScreen].bounds.size.height - 113) style:UITableViewStylePlain];
self.tableView.dataSource = self;
self.tableView.delegate = self;
[self.tableView registerClass:[SCPPrivateMessageListCell class] forCellReuseIdentifier:kCellIdentifier];
self.tableView.alpha = 0; // The table view starts out invisible.
[self.view addSubview:self.tableView];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (!self.hasAlreadyFetchedBefore) {
[self.view addSubview:self.centerView];
[self.centerView showLoadingView];
__weak PrivateMessagesViewController *weakSelf = self;
[self.query runInBackgroundWithCompletion:^(NSArray *messages, NSError *error) {
PrivateMessagesViewController *innerSelf = weakSelf;
// If there is an error, handle it.
if (error) {
// ...
return;
}
// If there weren't any messages before and none were found,
// the user has no messages in the inbox.
if (!innerSelf.hasAlreadyFetchedBefore && messages.count == 0) {
[innerSelf.centerView showNoResultsLabel];
}
else {
if (!innerSelf.hasAlreadyFetchedBefore) {
[innerSelf.centerView fadeOutAndRemoveFromSuperview];
innerSelf.tableView.alpha = 1;
} else {
}
[innerSelf.messages addObjectsFromArray:messages];
[innerSelf.tableView reloadData];
}
innerSelf.hasAlreadyFetchedBefore = YES;
}];
}
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.messages.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
SCPPrivateMessageListCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIdentifier];
SCPFMessage *message = self.messages[indexPath.row];
cell.message = message;
return cell;
}
#pragma mark - Table view delegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [SCPPrivateMessageListCell heightForMessage:self.messages[indexPath.row]];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
SCPPrivateMessageListCell *theCell = (SCPPrivateMessageListCell *)cell;
NSLog(#"Message at %d: %#", indexPath.row, theCell.message.rawData);
}
#pragma mark - Getters
- (SCPCenterView *)centerView
{
if (!_centerView) {
_centerView = [[SCPCenterView alloc] initWithParent:self.view];
_centerView.noResultsText = #"You don't have any private messages yet.";
}
return _centerView;
}
#end
SCPPrivateMessageListCell.m
static const CGFloat kInnerMargin = 10;
static const CGFloat kSpaceBetweenImageAndRightLabel = 10;
static const CGFloat kImageViewSize = 60;
static const CGFloat kRightLabelX = kInnerMargin + kImageViewSize + kSpaceBetweenImageAndRightLabel;
static const CGFloat kMaxRightLabelWidth = 320 - (kRightLabelX + kInnerMargin);
#interface SCPPrivateMessageListCell ()
#property (strong, nonatomic) UIImageView *thumbnailImageView;
#property (strong, nonatomic) UILabel *dateLabel;
#property (strong, nonatomic) UILabel *senderLabel;
#property (strong, nonatomic) UILabel *subjectLabel;
#property (strong, nonatomic) UILabel *summaryLabel;
#end
#implementation SCPPrivateMessageListCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
if (self) {
_thumbnailImageView = [[UIImageView alloc] init];
_thumbnailImageView.contentMode = UIViewContentModeScaleAspectFill;
_thumbnailImageView.layer.cornerRadius = kImageViewSize / 2;
_thumbnailImageView.clipsToBounds = YES;
_dateLabel = [[UILabel alloc] init];
_dateLabel.font = [UIFont systemFontOfSize:10];
_dateLabel.textAlignment = NSTextAlignmentCenter;
_dateLabel.numberOfLines = 1;
_dateLabel.lineBreakMode = NSLineBreakByTruncatingTail;
_senderLabel = [SCPPrivateMessageListCell senderLabel];
_subjectLabel = [SCPPrivateMessageListCell subjectLabel];
_summaryLabel = [SCPPrivateMessageListCell summaryLabel];
[self.contentView addSubview:_thumbnailImageView];
[self.contentView addSubview:_dateLabel];
[self.contentView addSubview:_senderLabel];
[self.contentView addSubview:_subjectLabel];
[self.contentView addSubview:_summaryLabel];
}
return self;
}
- (void)setMessage:(SCPFMessage *)message
{
_message = message;
[self.thumbnailImageView setImageWithURL:message.thumbnailURL];
self.dateLabel.text = message.dateSent;
self.senderLabel.text = message.nameOfSender;
self.subjectLabel.text = message.subject;
self.summaryLabel.text = message.summary;
[self setNeedsLayout];
}
- (void)layoutSubviews
{
self.thumbnailImageView.frame = CGRectMake(kInnerMargin, kInnerMargin, kImageViewSize, kImageViewSize);
[self.dateLabel sizeToFitWidth:kImageViewSize];
self.dateLabel.frame = CGRectMake(kInnerMargin, kInnerMargin + kImageViewSize, kImageViewSize, self.dateLabel.frame.size.height);
[self.senderLabel sizeToFitWidth:kMaxRightLabelWidth];
self.senderLabel.frame = CGRectMake(kRightLabelX, kInnerMargin, kMaxRightLabelWidth, self.senderLabel.frame.size.height);
CGFloat subjectLabelY = self.senderLabel.frame.origin.y + self.senderLabel.frame.size.height;
[self.subjectLabel sizeToFitWidth:kMaxRightLabelWidth];
self.subjectLabel.frame = CGRectMake(kRightLabelX, subjectLabelY, kMaxRightLabelWidth, self.subjectLabel.frame.size.height);
CGFloat summaryLabelY = self.subjectLabel.frame.origin.y + self.subjectLabel.frame.size.height;
[self.summaryLabel sizeToFitWidth:kMaxRightLabelWidth];
self.summaryLabel.frame = CGRectMake(kRightLabelX, summaryLabelY, kMaxRightLabelWidth, self.summaryLabel.frame.size.height);
CGFloat cellHeight = [SCPPrivateMessageListCell heightForMessage:self.message];
self.contentView.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, cellHeight);
self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, cellHeight);
}
#pragma mark - Class methods
+ (UILabel *)senderLabel
{
UILabel *label = [[UILabel alloc] init];
label.font = [UIFont boldSystemFontOfSize:17];
label.textColor = [UIColor colorFromHex:0x0076be];
label.numberOfLines = 1;
label.lineBreakMode = NSLineBreakByTruncatingTail;
return label;
}
+ (UILabel *)subjectLabel
{
UILabel *label = [[UILabel alloc] init];
label.font = [UIFont systemFontOfSize:14];
label.numberOfLines = 1;
label.lineBreakMode = NSLineBreakByTruncatingTail;
return label;
}
+ (UILabel *)summaryLabel
{
UILabel *label = [[UILabel alloc] init];
label.font = [UIFont systemFontOfSize:12];
label.textColor = [UIColor grayColor];
label.numberOfLines = 3;
label.lineBreakMode = NSLineBreakByTruncatingTail;
return label;
}
+ (CGFloat)heightForMessage:(SCPFMessage *)message
{
CGFloat height = kInnerMargin;
UILabel *senderLabel = [SCPPrivateMessageListCell senderLabel];
senderLabel.text = message.nameOfSender;
[senderLabel sizeToFitWidth:kMaxRightLabelWidth];
height += senderLabel.frame.size.height;
UILabel *subjectLabel = [SCPPrivateMessageListCell subjectLabel];
subjectLabel.text = message.subject;
[subjectLabel sizeToFitWidth:kMaxRightLabelWidth];
height += subjectLabel.frame.size.height;
UILabel *summaryLabel = [SCPPrivateMessageListCell summaryLabel];
summaryLabel.text = message.summary;
[summaryLabel sizeToFitWidth:kMaxRightLabelWidth];
height += summaryLabel.frame.size.height;
height += kInnerMargin;
return height;
}
#end
There. I'm not doing anything non-standard. The subviews of the cells also disappear when I scroll, but when I scroll them back in, the content becomes displayed, still with a skipping empty cell. Anyone have any idea why this is happening?
The problem was in my table view cell's layoutSubviews.
self.contentView.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, cellHeight);
That should have been:
self.contentView.frame = CGRectMake(self.contentView.frame.origin.x, self.contentView.frame.origin.y, self.contentView.frame.size.width, cellHeight);
I found out by setting a different color for self.backgroundColor and self.contentView.backgroundColor from inside the init method.

tableview doesn't see the tableview view for header in section method

I was trying to create a custom section for my tableview.Tableview itself works fine, but for some reason, compiler skips,
- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
delegate method, and i tried what is written on the reference , and this . I also added the tableView:heightForHeaderInSection: method as it suggests in reference page but for some reason it just doesn't read these methods. Obviously, I am doing something wrong. If someone can point my mistake out, I would appreciate. Thank you in advance.
profileViewController.h
#import <UIKit/UIKit.h>
#import "PeopleModel.h"
#import <QuartzCore/QuartzCore.h>
#interface profileViewController : UIViewController
<UITableViewDataSource,UITableViewDelegate>
#property(strong,nonatomic)NSMutableArray *People;
#property (weak, nonatomic) IBOutlet UITableView *profileTableView;
#end
profileViewController.m
#import "profileViewController.h"
#interface profileViewController ()
+ (UIImage *)scale:(UIImage *)image toSize:(CGSize)size;
#end
#implementation profileViewController
- (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 from its nib.
self.title = #"ProfileView";
self.profileTableView.dataSource = self;
self.profileTableView.dataSource = self;
PeopleModel *person1 = [[PeopleModel alloc]init];
person1.Name =#"mett";
person1.Email= #"mett#gmail.com";
person1.ProfilePicture =[UIImage imageNamed:#"profileImage.jpg"];
self.People = [NSMutableArray arrayWithObjects:person1,person1, nil];
self.profileTableView.layer.cornerRadius = 8.0;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.People count];
}
-(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];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.textLabel.font = [UIFont systemFontOfSize:19.0];
cell.detailTextLabel.font = [UIFont systemFontOfSize:12];
}
PeopleModel *item =[self.People objectAtIndex:indexPath.row];
cell.textLabel.text = item.Name;
cell.detailTextLabel.text = item.Email;
cell.imageView.image = item.ProfilePicture;
cell.imageView.image =[profileViewController scale:item.ProfilePicture toSize:CGSizeMake(115, 75)];
return cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 15;
}
- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
NSLog(#"cartman!");
if (section == 0) {
CGRect screenRect = [[UIScreen mainScreen] applicationFrame];
UIView* headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, screenRect.size.width, 44.0)];
//headerView.contentMode = UIViewContentModeScaleToFill;
// Add the label
UILabel *headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(10.0, -5.0, 300.0, 90.0)];
headerLabel.backgroundColor = [UIColor clearColor];
headerLabel.opaque = NO;
headerLabel.text = #"section one";
headerLabel.textColor = [UIColor blueColor];
headerLabel.highlightedTextColor = [UIColor blackColor];
//this is what you asked
headerLabel.font = [UIFont boldSystemFontOfSize:17];
headerLabel.shadowColor = [UIColor clearColor];
headerLabel.shadowOffset = CGSizeMake(0.0, 1.0);
headerLabel.numberOfLines = 0;
headerLabel.textAlignment = NSTextAlignmentCenter;
[headerView addSubview: headerLabel];
// Return the headerView
return headerView;
}
else return nil;
}
+ (UIImage *)scale:(UIImage *)image toSize:(CGSize)size
{
UIGraphicsBeginImageContext(size);
[image drawInRect:CGRectMake(0, 0, size.width, size.height)];
UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return scaledImage;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 3;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
You have a typo in the viewDidLoad method:
self.profileTableView.dataSource = self;
self.profileTableView.dataSource = self;
One of these should be delegate.

Resources