Remove UICollectionView cells on edit button - objective-c

I am using a UICollectionView to retrieve images and labels stored in the Cloud database Parse.
I now need an option that will let me delete a certain image and its corresponding label.
I am looking for something such as the typical iPhone "Edit" button on the top right hand corner which displays a swipe animation with a delete button next to the cell. I'm aware that such a thing can be done on a UITableView through
[[self tableView] setEditing:YES animated:YES];
but I can't seem to find the equivalent for a UICollectionView anywhere.
Any help appreciated, even if it doesn't deal with the deletion from Parse itself, just the editing style on the collection view would be ideal.
Here is how I populate my cells:
- (void)viewDidLoad
{
[super viewDidLoad];
[self retrieveSelectedImages];
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [imageFilesArray count];
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"myRoomsCell";
MyRoomsCell *cell = (MyRoomsCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
PFObject *imageObject = [imageFilesArray objectAtIndex:indexPath.row];
PFFile *imageFile = [imageObject objectForKey:#"imageFile"];
cell.loadingSpinner.hidden = NO; //show loading spinner to indicate work is happening until the image loads
[cell.loadingSpinner startAnimating];
// UILabel *label = (UILabel*) [cell viewWithTag:5];
cell.label.text= [imageObject objectForKey:#"roomLabel"]; //set room label as the label stored on parse previously inserted by the user
cell.label.font = [UIFont fontWithName:#"Helvetica-Bold" size:18];
cell.label.textAlignment = NSTextAlignmentCenter;
[imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error)
{
if (!error) {
cell.parseImage.image = [UIImage imageWithData:data];
[cell.loadingSpinner stopAnimating];
cell.loadingSpinner.hidden = YES;
}
}];
return cell;
}
-(void) retrieveSelectedImages
{
//parse query where we search the favorites array column and return any entry where the array contains the logged in user objectid
PFQuery *getFavorites = [PFQuery queryWithClassName:#"collectionViewData"];
[getFavorites whereKey:#"selectedImage" equalTo:[PFUser currentUser].objectId];
[getFavorites findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error)
{
imageFilesArray = [[NSArray alloc] initWithArray:objects];
[roomsCollection reloadData];
}
}];
}

Check out this answer with plenty of code for you to try out: https://stackoverflow.com/a/16190291/1914567
Basically, there is no Apple-provided way to do this.
There are also some really nice libraries. My personal favorite is DraggableCollectionView, and also check out LXReorderableCollectionViewFlowLayout.

-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
[[Singleton sharedSingleton].selectedProfileArray removeObjectAtIndex:indexPath.row];
[selectCollectionView reloadData];
}

Related

Best Way utilize PHPhotoLibrary for display Camera Roll image in UICollectionView with custom Cell

Hello everyone I have a problem with my app ... Within my View Controller hp a CollectionView with a custom cell that should return all of the photos in the Camera Roll section of the app pictures of my iphone.
Now I've done all the steps to show the photos in a ImageView in the custom cell and up to now I have no problem ... My problem is that when I start to scroll through photos, uploading photos is very slow and immediately after the app crashes giving me back this error in the log ..
[GatekeeperXPC]
Connection to assetsd was interrupted or assetsd died 25/02/2017 20:
[Generic] Creating an image
format with an unknown type is an error
Can you tell me if I've taken the right way to show pictures in my collection view? Where did I go wrong? because my app crashes?
Thank you all for any help you can give me
This is the code i utilize
- (void)viewDidLoad {
[super viewDidLoad];
self.nameTextField.delegate = self;
self.emailTextField.delegate = self;
self.passwordTextField.delegate = self;
self.collectionView.delegate = self;
self.collectionView.dataSource = self;
_collectionView.backgroundColor = [UIColor clearColor];
}
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[_nameTextField becomeFirstResponder];
[self queryImage];
}
-(void)queryImage {
PHFetchOptions *fetchOptions = [[PHFetchOptions alloc] init];
PHFetchResult *collection = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumUserLibrary options:fetchOptions];
if (collection.firstObject != nil ) {
_photoFound = YES;
_assetCollection = collection.firstObject;
} else {
}
_photoAsset = [PHAsset fetchAssetsInAssetCollection:_assetCollection options:nil];
[_collectionView reloadData];
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(80,80);
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
NSUInteger count = 0;
if (_photoAsset != nil) {
count = [_photoAsset count];
}
return count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *reuseIdentifier = #"imageCell";
UPCameraRollCollectionViewCell* cell = [cv dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
cell.backgroundColor = [UIColor redColor];
PHAsset *asset = [_photoAsset objectAtIndex:indexPath.item];
PHImageManager *imageManager = [PHImageManager defaultManager];
[imageManager requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFill options:nil resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
[cell setThumbnailImage:result];
}];
return cell;
}
Use PHCachingImageManager.
Apple has an example that shows exactly how to do the sort of thing you're after. Collection views are precisely the intended use case.

IOS - How to retrieve images and strings from parse and set UIImageview and UIlabel in UICollectionView

Ok so Im using storyboards and Trying to add String data that goes with the images
the images are in the same row with the name of the picture in parse
I got the image and was able to put it on a UICollectionView im just having trouble connecting the name that goes with it in the same cell
.
how do i get a different name that goes with the image for each cell
- (void)viewDidLoad {
[super viewDidLoad];
[self queryParseMethod];
self.userCollection.alwaysBounceVertical = YES;
}
- (void)queryParseMethod {
PFQuery *query = [PFQuery queryWithClassName:#"imageandtitle"];
[query findObjectsInBackgroundWithBlock:^(NSArray * _Nullable objects, NSError * _Nullable error) {
if (!error) {
imagefilesArray = [[NSArray alloc] initWithArray:objects];
[userCollection reloadData];
}
}];
}
-(NSInteger) numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
-(NSInteger) collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [imagefilesArray count];
}
-(UICollectionViewCell *) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
userCCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"userCard" forIndexPath:indexPath];
PFQuery *query = [PFQuery queryWithClassName:#"_User"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error)
{
self.affiliates = objects;
for(NSDictionary *affiliate in self.affiliates) {
//cell.Name.text = affiliate[#"Name"];
NSArray* array = [[NSArray alloc] initWithObjects:affiliate[#"Name"], nil];
for (NSString *name in array) {
PFObject *imageObject = [array objectAtIndex:indexPath.row];
cell.Name.text = name;
}
}
}
}];
PFObject *imageObject = [imagefilesArray objectAtIndex:indexPath.row];
PFFile *imageFile = [imageObject objectForKey:#"imageFile"];
PFObject *nameofUser = [imageObject objectForKey:#"Name"];
[imageFile getDataInBackgroundWithBlock:^(NSData * _Nullable data, NSError * _Nullable error) {
if (!error) {
cell.userPI.image = [UIImage imageWithData:data];
}
}];
return cell;
}
I Am currently only getting one name and if i try to uncomment the other cell.text i still get one name but in all cells.
Thank you in advanced.
sorry guys the answer was really simple i just had to remove the for loop and query since i already queried as a method then type
cell.Name.text = [imageObject objectForKey:#"Name"];
thank you for your time.

Why are my UITableViewCell images only being loaded when I leave then return to a controller and not during viewDidLoad?

Having a slight problem with my UITableViewCell images. I'm loading my data straight from parse.com. My objects array that returns PFObject's is stored inside an NSMutable array named "people".
This is how I display the data in my table:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [[self tableView] dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
Person *current;
if (tableView == [[self searchDisplayController] searchResultsTableView]) {
current = [searchResults objectAtIndex:indexPath.row];
} else {
current = [people objectAtIndex:[indexPath row]];
}
[[cell textLabel] setText: [current valueForKey:#"name"]];
PFFile *userImageFile = [current valueForKey:#"image"];
[userImageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
UIImage *image = [UIImage imageWithData:imageData];
[[cell imageView] setImage: image];
}];
// [[cell imageView] setImage: [current image]];
[[cell detailTextLabel] setText: [current valueForKey:#"notes"]];
return cell;
}
The problem is when I load the app up and this view which is my main loads it doesn't load any images. However when I tap on a row just before the next controller is popped on screen I see the image for that row load and then when I tap the back button and go back to the main view again the rest of the tableViews images load.
Is this something to do with the images not being thumbnail versions?
I've tried wrapping the code in dispatch_async(dispatch_get_main_queue(), ^ { )}; with no luck. Can someone help me solve this issue?
Kind regards
Update to show where I call reload data:
-(void)viewDidAppear:(BOOL)animated {
dispatch_async(dispatch_get_main_queue(), ^{
[[self tableView] reloadData];
});
}
- (void)viewDidLoad
{
[super viewDidLoad];
people = [[NSMutableArray alloc] init];
PFQuery *query = [PFQuery queryWithClassName:#"People"];
[query whereKey:#"active" equalTo:#1];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
people = objects.mutableCopy;
dispatch_async(dispatch_get_main_queue(), ^ {
[[self tableView] reloadData];
});
I don't think there is anything wrong with your loading in your viewDidLoad.
My suspicion is that the UIImageView's frame is actually zero as you did not have a placeholder image while loading the actual images. The cell will not be redrawn again until the next time layoutSubviews is called again, even if your fetched image has loaded. So either set a placeholder image, or call:
[cell setNeedsLayout];
once your image is fully loaded.
Another alternative is to use PFImageView, a subclass of UIImageView, which takes care of everything for you.
PFFile *userImageFile = [current valueForKey:#"image"];
[cell imageView].image = [UIImage imageNamed:#"placeholder.jpg"]; // placeholder image
[cell imageView].file = userImageFile;
[[cell imageView] loadInBackground];
Instead of loading my data directly from parse.com into my tableView I loaded it into an object first. So each object was no longer an PFObject and now a Person object and I stored these in a mutable array which I accessed in my tableView.
Try it:
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear]; //this is necessary for most time
//viewDidAppear be called in main thread, so just call reloadData directly
[self.tableView reloadData];
}
As mentioned in Apple document about - (id)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath:
You must register a class or nib file using the registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier: method before calling this method.
If you registered a class for the specified identifier and a new cell must be created, this method initializes the cell by calling its initWithStyle:reuseIdentifier: method.
For nib-based cells, this method loads the cell object from the provided nib file. If an existing cell was available for reuse, this method calls the cell’s prepareForReuse method instead.
So, do you forget to use the registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier: method before calling cellForRowAtIndexPath method?
Here is a discussion about this.
How I am doing this
In my UIViewController.m
#property (nonatomic, strong) NSMutableDictionary *imageDownloadsInProgress;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.imageDownloadsInProgress = [NSMutableDictionary dictionary];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
SRKProduct *productRecord = [stockArray objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if (!productRecord.image || [productRecord.image isEqualToData:NULL] || productRecord.image.length == 0) {
if (_itemTableView.dragging == NO && _itemTableView.decelerating == NO)
{
[self startIconDownload:productRecord forIndexPath:indexPath];
}
cell.imageView.image = [[UIImage imageNamed:#"Placeholder.png"] makeThumbnailOfSize:CGSizeMake(50,50)];//This is just a placeholder and will be removed when original image is downloaded.
}
return cell;
}
#pragma mark -
- (void)startIconDownload:(SRKProduct *)srkproduct forIndexPath:(NSIndexPath *)indexPath
{
SRKIconDownloader *iconDownloader = [self.imageDownloadsInProgress objectForKey:indexPath];
if (iconDownloader == nil)
{
iconDownloader = [[SRKIconDownloader alloc] init];
iconDownloader.srkproduct = srkproduct;
[iconDownloader setCompletionHandler:^{
UITableViewCell *cell = [_itemTableView cellForRowAtIndexPath:indexPath];
// Display the newly loaded image
cell.imageView.image = [UIImage imageWithData:srkproduct.image];
NSLog(#"Image %d",[productAdapter updateproductImage:srkproduct]);
// Remove the IconDownloader from the in progress list.
// This will result in it being deallocated.
[self.imageDownloadsInProgress removeObjectForKey:indexPath];
}];
[self.imageDownloadsInProgress setObject:iconDownloader forKey:indexPath];
[iconDownloader startDownload];
}
}
Then in SRKIconDownloader.h
#interface SRKIconDownloader : NSObject
#property (nonatomic, strong) SRKProduct *srkproduct;
#property (nonatomic, copy) void (^completionHandler)(void);
And in SRKIconDownloader.m
#implementation SRKIconDownloader
#pragma mark
- (void)startDownload
{
PFQuery *queryCouple = [PFQuery queryWithClassName:#"Product"];
[queryCouple whereKey:#"Name" equalTo:_srkproduct.productName];
[queryCouple findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
if ([objects count] > 0) {
for (PFObject *object in objects) {
PFFile *image = (PFFile *)[object objectForKey:#"Image"];
[image getDataInBackgroundWithBlock:^(NSData *data, NSError *error){
_srkproduct.image = data;
// call our delegate and tell it that our icon is ready for display
if (self.completionHandler)
self.completionHandler();
}];
break;
}
}
else{
}
}
}];
}
#end

I'm trying to implement infinite scrolling into my UITableViewController and unsure how to use the database results returned

Currently trying to implement infinite scrolling into my app using this plugin: https://github.com/pronebird/UIScrollView-InfiniteScroll
So far I've added this code to my tableview controller viewDidAppear and viewDidDisappear methods:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// setup infinite scroll
// keep a weak reference to table view
__weak UITableView *weakTableView = self.tableView;
[self.tableView addInfiniteScrollWithHandler:^{
// keep a strong reference to table view
__strong UITableView *strongTableView = weakTableView;
// seems like our table view didn't make it
if(strongTableView == nil) return;
//
// fetch your data here, can be async operation,
// just make sure to call finishInfiniteScroll in the end
// finish infinite scroll animation
[strongTableView finishInfiniteScroll];
}];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
// remove infinite scroll
[self.tableView removeInfiniteScroll];
[[self tableView] reloadData];
}
I drag the table and the spinner shows underneath the last row and disappears after a second or two. Now all I need to do is get the data from my array and add it to block in the viewDidAppear code.
This is how I currently get my parse.com data into an NSMuteableArray instance named "people":
- (void)populatePeopleArrayWithCloudData {
// Grab data for datasource and store in people array
NSLog(#"view did load");
people = [[NSMutableArray alloc] init];
PFQuery *query = [PFQuery queryWithClassName:#"People"];
[query whereKey:#"active" equalTo:#1];
[query orderByDescending:#"createdAt"];
[query setLimit:10];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
for (PFObject *object in objects) {
Person *person = [[Person alloc] init];
[person setName:[object objectForKey:#"name"]];
[person setNotes:[object objectForKey:#"notes"]];
[person setAge:[[object objectForKey:#"age"] intValue]];
[person setSince:[object objectForKey:#"since"]];
[person setFrom:[object objectForKey:#"from"]];
[person setReferenceNumber:[object objectForKey:#"referenceNumber"]];
PFFile *userImageFile = object[#"image"];
[userImageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
if (!error) {
UIImage *image = [UIImage imageWithData:imageData];
[person setImage:image];
}
}];
[person setActive:[[object objectForKey:#"active"] intValue]];
[person setObjectId:[object objectId]];
[people addObject:person];
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
NSLog(#"Calling reloadData on %# in viewDidLoad", self.tableView);
[self.tableView reloadData];
}];
}
I limit results to 10. Now what I wish to do is keep grabbing the next 10 results that haven't already been grabbed every time I scroll to the bottom of the table. This code that helps me do this needs to go in the block mentioned above.
The "people" instance is used by my tableviewdatasource methods:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [[self tableView] dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
// Configure the cell...
Person *current;
if (tableView == [[self searchDisplayController] searchResultsTableView]) {
current = [searchResults objectAtIndex:indexPath.row];
} else {
current = [people objectAtIndex:[indexPath row]];
}
[[cell textLabel] setText: [current name]];
[[cell imageView] setImage: [current image]];
[[cell detailTextLabel] setText: [current notes]];
return cell;
}
How do I use my database results with this plugin? As you can see I limit results to 10 and I need to grab the next 10 when I've scrolled to the bottom of the table and add them after the last row in the table.
Kind regards
UPDATE - my numbers of rows in section method as it stands:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
if (tableView == [[self searchDisplayController] searchResultsTableView]) {
return [searchResults count];
} else {
return [people count];
}
}
Happy to help, but you should probably give it a shot first for us to provide feedback. A few thoughts to get you going...
The general idea is to use the "skip" property on PFQuery to get the next 10. Each time you call it, you add 10.
So create your query as you do, keep it around in a property, but move your findObjectsInBackgroundWithBlock call to your infiniteScrollHandler, adding 10 to skip each time after you call it. Then at the end of the handling (where you call table reload now), call [strongTableView finishInfiniteScroll]
In your numberOfRows, you'll have to provide the maximum number of people available at your source.

Data doesn't load in UITableView until I scroll

I am trying to load parsed data in cells, but the problem is that it is happening synchronously and UitableView doesn't show until the data has finished loading. I tried to solve the problem by using performSelectorInBackground, but now data isn't loaded in the cells until I start scrolling. Here is my code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self performSelectorInBackground:#selector(fethchData) withObject:nil];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
self.listData = nil;
self.plot=nil;
}
-(void) fethchData
{
NSError *error = nil;
NSURL *url=[[NSURL alloc] initWithString:#"http://www.website.com/"];
NSString *strin=[[NSString alloc] initWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
HTMLParser *parser = [[HTMLParser alloc] initWithString:strin error:&error];
if (error) {
NSLog(#"Error: %#", error);
return;
}
listData =[[NSMutableArray alloc] init];
plot=[[NSMutableArray alloc] init];
HTMLNode *bodyNode = [parser body];
NSArray *contentNodes = [bodyNode findChildTags:#"p"];
for (HTMLNode *inputNode in contentNodes) {
[plot addObject:[[inputNode allContents] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
}
NSArray *divNodes = [bodyNode findChildTags:#"h2"];
for (HTMLNode *inputNode in divNodes) {
[listData addObject:[[inputNode allContents] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
//here you check for PreCreated cell.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
//Fill the cells...
cell.textLabel.text = [listData objectAtIndex:indexPath.row];
cell.textLabel.font = [UIFont boldSystemFontOfSize:14];
cell.textLabel.numberOfLines=6;
cell.textLabel.textColor=[UIColor colorWithHue:0.7 saturation:1 brightness:0.4 alpha:1];
cell.detailTextLabel.text=[plot objectAtIndex:indexPath.row];
cell.detailTextLabel.font=[UIFont systemFontOfSize:11];
cell.detailTextLabel.numberOfLines=6;
return cell;
}
Put this somewhere after the data is loaded successfully:
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
This fix the problem of calling a GUI update while you're not in the main thread.
This code uses the GCD Technology from Apple to force the reload data function to run on main thread. Read more about
Concurrency Programming Guide for more understanding (it's quite large field so that it's hard to explain in the comment)
Anyway, it's not very recommended if you don't understand it well because it causes the program to crash some rare cases.
For swift 3:
DispatchQueue.main.async(execute: { () -> Void in
self.tableView.reloadData()
})
For swift 2:
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.reloadData()
})
All you really need to do is any time you have an update to your back-end data, call
[tableView reloadData];
Since this is happening synchronously, you should probably have a function like
-(void) updateTable
{
[tableView reloadData];
}
and after adding the data in your download call
[self performSelectorOnMainThread:#selector(updateTable) withObject:nil waitUntilDone:NO];
U can use [cell setNeedsDisplay];
for example:
dispatch_async(dispatch_get_main_queue(), ^{
[cell setNeedsDisplay];
[cell.contentView addSubview:yourView];
});
I had this problem and I was dealing with it all the day.
I am using static cells and reloadData is causing the wrong loading, it displays only the visible cells and remove the others.
What I noticed is that when I scrolled down (y in negative value) the cells where loaded correctly, so I wrote this code and it worked, even though I don't like to let it in this way.
Shoot if you find any better solution.
-(void)reloadTableView{
CGPoint point = self.tableSettings.tableView.contentOffset;
[self.tableSettings.tableView reloadData];
[UIView animateWithDuration:.001f animations:^{
[self.tableSettings.tableView setContentOffset:CGPointMake(point.x, -10)];
} completion:^(BOOL finished) {
[UIView animateWithDuration:.001f animations:^{
[self.tableSettings.tableView setContentOffset:point];
} completion:^(BOOL finished) {
}];
}];
}
I was having the exact same problem! I wanted the UITableView to be fully populated before the view controller appeared. Envil's post gave me the information I needed, but my solution ended up being different.
Here's what I did (remodeled to fit the context of the question asker).
- (void)viewDidLoad {
[super viewDidLoad];
[self performSelectorInBackground:#selector(fethchData) withObject:nil];
}
- (void)viewWillAppear {
[tableView reloadData];
}
First, this semi-solved my related problem. I want to round corners of an image in a table cell. Dispatching asynchronously fixed the problem for some but not all of the images. Any ideas?
Second, I think you are supposed to avoid creating a strong reference cycle by using a closure capture list like this:
DispatchQueue.main.async(execute: { [weak weakSelf = self] () -> Void in
weakSelf!.tableView.reloadData()
})
See: https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html#//apple_ref/doc/uid/TP40014097-CH20-ID52
I experienced the same issue when using self-sizing cells, and I found that setting the estimatedHeight to 50 would fix the problem.
Set estimatedHeight on the tableView itself or return an estimate from estimatedHeightForRowAt in your UITableViewDelegate.
It seems to work as long as the estimate is more than 0.