CollectionView not display data after parsing JSON
As this
GettingMoney.fetchData()
is a sign of asynchronous process that doesn't reload the collection , so do
func fetchData(completion:@escaping ([String]) -> ()) {
Api.load {
completion(arr)
}
}
Then use like
GettingMoney.fetchData { arr in
self.arraOfData = arr
DispatchQueue.main.async {
self.collectionView.reloadData()
}
}
A not direct case like yours is here Returning data from async call in Swift function
Collection View Not Showing Data
Try instead of
nc.post(name: Notification.Name("didFinishParsing"), object: nil)
send
nc.post(name: Notification.Name("didFinishParsing"), object: news)
Then instead of
guard let news = notification.object as? Article else { return}
write
guard let news = notification.object as? News else { return}
print("News == \(news)")
self.news = news.articles
How to parse json Data into dynamic collection view sections and cells in swift
First of all declare the struct with uppercased name, with non-optional members and without the init
method.
struct JobsData : Decodable
{
let employeeName : String
let startTime : String
let endTime : String
var startDate : String
}
To group the data declare a Section
struct
struct Section
{
let title : String
let jobsData : [JobsData]
}
and declare the data source array
var sections = [Section]()
After decoding the array
let jobsDataArray = try JSONDecoder().decode([JobsData].self, from: data)
group it with Dictionary(grouping:by:)
, map
it to a Section
array and sort
it
let grouped = Dictionary(grouping: jobsDataArray, by: {$0.startDate})
self.sections = grouped.map{Section(title: $0.key, jobsData: $0.value)}
.sorted{$0.title < $1.title}
You can even sort the JobsData
items in the sections simultaneously for example by startTime
self.sections = grouped.map{Section(title: $0.key, jobsData: $0.value.sorted{$0.startTime < $1.startTime})}
.sorted{$0.title < $1.title}
To display the sections implement the datasource methods
override func numberOfSections(in collectionView: UICollectionView) -> Int
return sections.count
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return sections[section].jobsData.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! AvailableJobsCell
let jobData = sections[indexPath.section].jobsData[indexPath.item]
let sTime = self.timeInAmPm(String: jobData.startTime)
let eTime = self.timeInAmPm(String: jobData.endTime)
cell.jobAddedTime.text = "\(sTime) - \(eTime)"
cell.jobTitle.text = jobData.employeeName
cell.schoolName.text = "\(jobData.organizationName ?? "")\n\(jobData.organizationAddress ?? "")"
cell.jobNo.text = jobData.confirmationNumber!
cell.personOnHiatus.text = jobData.positionDescription!
cell.index = indexPath
cell.delegate = self
return cell
}
Swift: How to Display Parsed JSON Data in CollectionView inside a TableView?
Collection view delegate methods don't know context of their collection view. You should calculate onlineNews index depending on the collectionView instance instead of using indexPath.row, which is internal collection view index path.
Edit: better option (to avoid scrolling and layout issues) is to use single collection view, where cells are grouped in rows. If you don't want to make layout manager, you can achieve such layout by adding small, but very wide separator views between sections
Edit2:
cell.contentType.text = categoryResults[indexPath.row]["ContentType"].stringValue
uses local indexPath of this collection view. You could assign tag to tableViewCell.collectionView
with a value of desired categoryResults index. Then you can use this tag as in categoryResults[collectionView.tag]
Collectionview not show JSON Parsing image
You should probably use a custom UICollectionViewCell class that has a UIImageView property, init it with a frame that's the same as your UICOllectionView's frame.
Then in your viewController's cellForRow method, use SDWebImage to asynchronously set your cell's custom photo.
Cell Header File
@interface CustomCell: UICollectionViewCell
@property (nonatomic, strong) UIImageView *photo;
@end
Cell Implementation File
@implementation CustomCell
-(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if(self)
{
self.photo = [[UIImageView alloc] initWithFrame:frame];
self.photo.contentMode = UIViewContentModeScaleAspectFill;
[self.contentView addSubview:self.photo];
}
return self;
}
@end
View Controller Implementation File
#import "CustomCell.h"
#import <SDWebImage/UIImageView+WebCache.h>
-(void)viewDidLoad
{
...
self.collectionView = [[UICollectionView alloc] init....];
self.collectionView registerClass:[CustomCell class] forCellWithReuseIdentifier:@"cellID"];
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cellID" forIndexPath:indexPath];
// using SDWebImage to download photo asynchronously.
[cell.photo sd_setImageWithURL:[NSURL urlWithString:[json valueForKey:@"imageURL"]] placeholderImage:[UIImage imageNamed:@"placeholderImage.png"]];
}
Spinner
Modify your custom cell class to include a new UIActivitiyIndicator property:
@interface CustomCell: UICollectionViewCell
@property (nonatomic, strong) UIImageView *photo;
@property (nonatomic, strong) UIActivityIndicatorView *spinner;
@end
@implementation CustomCell
-(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if(self)
{
self.photo = [[UIImageView alloc] initWithFrame:frame];
self.photo.contentMode = UIViewContentModeScaleAspectFill;
self.spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
// might or might not need to set frame of spinner
[self.contentView addSubview:self.photo];
[self.photo addSubview:self.spinner];
}
return self;
}
@end
Then change the SDWebImage call to the one with the completion block:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cellID" forIndexPath:indexPath];
// using SDWebImage to download photo asynchronously.
[cell.spinner startAnimating];
[cell.photo sd_setImageWithURL:[NSURL urlWithString:[json valueForKey:@"imageURL"]] placeholderImage:[UIImage imageNamed:@"placeholderImage.png"] options:0 completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
// tell spinner to stop animating after image finished downloading
[cell.spinner stopAnimating];
}];
}
Reloading UICollection view after data parse
Same problem i faced..your url having many images means reload t
dispatch_async(dispatch_get_main_queue(), {
self.collectionView.reloadData()
})
Related Topics
How to Handle Hash Collisions for Dictionaries in Swift
Generatesdecimalnumbers for Numberformatter Does Not Work
Print the Nstableview's Row Number of the Row Clicked by the User
Appending Tuples to an Array of Tuples
How to Declare Swift Implicitly Unwrapped Optional as a Constant
Pagination with Firebase Firestore - Swift 4
Appearance Proxies/Ui_Appearance_Selector in Swift
Read and Write Permission for User Selected Folder in MAC Os App
Swift 2: !, ? -" Value of Optional Type "..." Not Unwrapped"
Why Does Swift Not Allow Stored Properties in Extensions
Nested Types in Swift - What Is the Good Practice
How to Stream Remote Audio in iOS 13? (Swiftui)
How Do Generators Whose Element Is Optional Know When They'Ve Reached the End
How to Access a Swift Enum Associated Value Outside of a Switch Statement