ReloadData in UICollectionView - swift

I use CoreData and want to reload the UICollectionView when I save a new entry in CoreData but the only self.collectionview.reloaddata()don´t run it reload nothing.
Thanks for your Help.
My CoreData and UICollectionView I have try it to reload the UICollectionView when clockblogalarm become a new entry:
var clockblogalarm = [ClockBlogAlarm] () {
didSet { //self.ClockCollectionView.reloadData()
}
}
var mgdContext = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext
func loadClockAlarms () {
let LoadRequestBlogAlarm: NSFetchRequest<ClockBlogAlarm> = ClockBlogAlarm.fetchRequest()
clockblogalarm = try! mgdContext.fetch(LoadRequestBlogAlarm as! NSFetchRequest<NSFetchRequestResult>) as! [ClockBlogAlarm]
}
#IBOutlet var ClockCollectionView: UICollectionView!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.loadClockAlarms()
}
Here I save the Entry in CoreData. When I click the Button Done view.bottomButtonHandler{} then I want to reload the data and show it in the UICollectionView with loadClockAlarms() .
else if index == 1 {
let view = AddClockView.instantiateFromNib()
let window = UIApplication.shared.delegate?.window!
view.closeButtonHandler = {[weak modal] in
modal?.closeWithLeansRandom()
return
}
view.bottomButtonHandler = {[weak modal] in
modal?.closeWithLeansRandom()
self.loadClockAlarms()
return
}
modal.show(modalView: view, inView: window!)
}
// MARK: UICollectionViewDataSource
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return clockblogalarm.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "AlarmBlogCell", for: indexPath) as! AlarmBlogCell
cell.layer.cornerRadius = 8
let clockblogalarms = clockblogalarm[indexPath.row]
if clockblogalarms.lock == "ClockblogAlarm" {
cell.Title.text = clockblogalarms.title
cell.Time.text = "SSSSS"
}
return cell
}

swift 5 & 4.2:
DispatchQueue.main.async {
self.collectionView.reloadData()
}

Ensure the reloadData() is called in the main thread, as it is the UI-responsible action:
dispatch_async(dispatch_get_main_queue()) {
self.ClockCollectionView.reloadData()
}

Related

Collectionview with coredata problems

The problem is when I switch between pages (TabNavigation) and I return in this page, a cell is added unwantedly, I rewrite the code the code many times, can someone help me?
CoreData is implemented it to save favorites in this collection view, and everything works except this little bug
var Distance : String!
var Logo : UIImage!
var pp : String!
var menuu : UIButton!
var loc : String!
var shop: [NSManagedObject] = []
#IBOutlet weak var ShopCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
ShopCollectionView.layer.cornerRadius = 10
ShopCollectionView.layer.masksToBounds = true
// register cell
let nibCell = UINib(nibName: ShopCollectionViewCellId, bundle: nil)
ShopCollectionView.register(nibCell, forCellWithReuseIdentifier: ShopCollectionViewCellId)
ShopCollectionView.delegate = self
ShopCollectionView.dataSource = self
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound]) { (granted, error) in }
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "ShopsData", in: managedContext)!
let item = NSManagedObject(entity: entity, insertInto: managedContext)
let fetch = NSFetchRequest<NSFetchRequestResult>(entityName: "ShopsData")
do {
let result = try? managedContext.fetch(fetch) as? [ShopsData]
shop = result ?? []
} catch {
fatalError()
}
collectionView.reloadData()
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of items
return shop.count + 1
}
<This is my writed method>
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.row >= shop.count {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ShopCollectionViewCellId, for: indexPath) as! ShopCollectionViewCell
return cell
} else {
let shop = shop[indexPath.row]
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ShopCollectionViewCellId, for: indexPath) as! ShopCollectionViewCell
cell.People.text = shop.value(forKey: "actualCustomers") as? String
cell.Location.text = shop.value(forKey: "location") as? String
return cell
}
}
This is the code I write
In your numberOfItemsInSection you return shop.count + 1 which means you are telling your collection view to show you 1 additional cell than the actual data you have.
Then in your cellForItemAt indexPath, you handle this by creating 1 blank cell.
If suggest you make the following changes to these functions as shown below and perhaps you will see the results you expect
override func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int
{
return shop.count
}
override func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let shop = shop[indexPath.row]
let cell =
collectionView.dequeueReusableCell(withReuseIdentifier: ShopCollectionViewCellId,
for: indexPath) as! ShopCollectionViewCell
cell.People.text = shop.value(forKey: "actualCustomers") as? String
cell.Location.text = shop.value(forKey: "location") as? String
return cell
}

Some UICollectionViewDropDelegateMethods get not called

I have an iPad application where you can drag images from Safari into a collection view. I also want to to drag and drop within the collection view to rearrange the collection View cells.
The drag and drop from safari is working. Dragging a cell within the collection view is also possible, but dropping is not possible. I took a look at the UICollectionViewDropDelegate methods "canLoadObjects", "sessionDidUpdate" and "performDrop" which get called in this order. I made another simple collection view app with drag and drop, so I know what to do.
I recognized that in the simple app, when I drag the cell onto another place "canLoadObjects" get called. I confirmed that with a breakpoint. In the other app this does not happen. Instead only "performDrop" gets called, but not "canLoadObjects" and "sessionDidUpdate". I set the delegate correctly (otherwise "performDrop would not get called either).
Does anybody know why some delegate methods doesn't get called? Thanks!
import UIKit
class ImageGalleryViewController: UIViewController {
var cellWidthScale: CGFloat = 1.0
var currentCellSize = CGSize()
var imageFetcher : ImageFetcher!
var loadAllImages = false
var tappedCellIndex = 0
#IBOutlet weak var collectionView: UICollectionView!{
didSet{
collectionView.delegate = self
collectionView.dataSource = self
collectionView.dragInteractionEnabled = true
collectionView.dragDelegate = self
collectionView.dropDelegate = self
collectionView.addGestureRecognizer(UIPinchGestureRecognizer(target: self, action: #selector(adjustCellWidth(with:))))
}
}
var userIsPinching = false
var imageDataTuple : [(NSURL?, CGSize)]? {
didSet{
if loadAllImages == true{
collectionView?.reloadData()
loadAllImages = false
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
collectionView.register(UINib(nibName: "ImageCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "ImageCell")
}
#objc func adjustCellWidth(with recognizer: UIPinchGestureRecognizer){
switch recognizer.state {
case .changed:
userIsPinching = true
cellWidthScale *= recognizer.scale
recognizer.scale = 1.0
collectionView.collectionViewLayout.invalidateLayout()
default: break
}
}
}
//MARK: UICollectionViewDelegate
extension ImageGalleryViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageDataTuple?.count ?? 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCell", for: indexPath)
if let imageCell = cell as? ImageCollectionViewCell{
imageCell.imageView.image = nil
imageCell.spinner.startAnimating()
if let url = imageDataTuple?[indexPath.row].0{
imageCell.imageUrl = url
//never fetch data on the main queue
DispatchQueue.global(qos: .userInitiated).async {
let urlContent = try? Data(contentsOf: (url as URL).imageURL)
//update the UI always on the main queue
DispatchQueue.main.async {
//check if the url is really the one we want to show
if let imageData = urlContent, url == imageCell.imageUrl, let image = UIImage(data: imageData){
imageCell.spinner.stopAnimating()
imageCell.imageView.image = image
}
else{
imageCell.spinner.stopAnimating()
imageCell.imageView.image = UIImage(systemName: "xmark.octagon.fill")
imageCell.imageView.tintColor = UIColor.red
imageCell.imageView.sizeToFit()
}
}
}
}
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if let checkedImageData = imageDataTuple{
let imageHeightToWidth = checkedImageData[indexPath.row].1.height/checkedImageData[indexPath.row].1.width
let calculatedWidth = (self.view.frame.width/4) * cellWidthScale
currentCellSize = CGSize(width: calculatedWidth, height: calculatedWidth * imageHeightToWidth)
return currentCellSize
}
return CGSize.zero
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
tappedCellIndex = indexPath.item
performSegue(withIdentifier: "ShowImage", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ShowImage"{
if let destVC = segue.destination as? DetailImageViewController{
destVC.imageUrl = imageDataTuple![tappedCellIndex].0
}
}
}
}
//MARK: UICollectionViewDropDelegate
extension ImageGalleryViewController: UICollectionViewDropDelegate{
//1. Can the dropDelegate handle the object?
func dropInteraction(_ interaction: UIDropInteraction, canHandle session: UIDropSession) -> Bool {
//requirement: only drop with image and url should be handled
return session.canLoadObjects(ofClass: NSURL.self)
}
//2. update the session. Return a propsal in which manner the object schould be dropped (.copy; .move...)
func dropInteraction(_ interaction: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal {
//Es wird überprüft, ob der collectionView auf dem gedroppt werden soll der ist, von dem das DragItem stammt
let isSelf = (session.localDragSession?.localContext as? UICollectionView) == collectionView
let dropOperation: UIDropOperation = isSelf ? .move : .copy
//intent: Soll eine neue Cell erstellt werden oder in die eingefügt werden, über der man sich gerde befindet?
return UICollectionViewDropProposal(operation: dropOperation, intent: .insertAtDestinationIndexPath)
}
//3. perform the actual drop. update UI and the model
func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) {
let destinationIntexPath = coordinator.destinationIndexPath ?? IndexPath(row: 0, section: 0)
for item in coordinator.items{
//Is the drop from the same collectionView or external? internal --> != nil
if let sourceIndexPath = item.sourceIndexPath{
if let url = item.dragItem.localObject as? NSURL{
collectionView.performBatchUpdates {
imageDataTuple?.remove(at: sourceIndexPath.item)
imageDataTuple?.insert((url, currentCellSize), at: destinationIntexPath.item)
collectionView.deleteItems(at: [sourceIndexPath])
collectionView.insertItems(at: [destinationIntexPath])
}
coordinator.drop(item.dragItem, toItemAt: destinationIntexPath)
}
}
//external --> nil
else{
var dataTupel: (NSURL?, CGSize?) {
didSet{
DispatchQueue.main.async {
if let controllerTitel = self.title, let presentImageSize = dataTupel.1, let presentURL = dataTupel.0{
if ImageGalleryModel.imageURLs[controllerTitel] != nil {
ImageGalleryModel.imageURLs[controllerTitel]!.append((presentURL, presentImageSize))
print(ImageGalleryModel.imageURLs)
self.imageDataTuple = ImageGalleryModel.imageURLs[controllerTitel]!
self.collectionView.insertItems(at: [IndexPath(item: ImageGalleryModel.imageURLs[controllerTitel]!.count - 1, section: 0)])
}
}
}
}
}
item.dragItem.itemProvider.loadObject(ofClass: NSURL.self) { provider, error in
dataTupel.0 = provider as? NSURL
}
item.dragItem.itemProvider.loadObject(ofClass: UIImage.self) { provider, error in
if let receivedImage = provider as? UIImage{
dataTupel.1 = receivedImage.size
}
}
}
}
}
}
//MARK: UICollectionViewDragDelegate
extension ImageGalleryViewController: UICollectionViewDragDelegate{
//Proveide inital drag items
func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
return dragItem(at: indexPath)
}
//Provide drag items which were added while dragging
func collectionView(_ collectionView: UICollectionView, itemsForAddingTo session: UIDragSession, at indexPath: IndexPath, point: CGPoint) -> [UIDragItem] {
session.localContext = collectionView
return dragItem(at: indexPath)
}
private func dragItem(at indexPath: IndexPath) -> [UIDragItem]{
if let image = (collectionView.cellForItem(at: indexPath) as? ImageCollectionViewCell)?.imageView.image{
let dragItem = UIDragItem(itemProvider: NSItemProvider(object: image))
dragItem.localObject = image
return [dragItem]
}
return []
}
}
//MARK: New selected Gallery
extension ImageGalleryViewController: GalleryListViewControllerDelegate{
func gallerySelected(name: String) {
loadAllImages = true
imageDataTuple = ImageGalleryModel.imageURLs[name]
self.title = name
}
}
The problem was that the auto correction chose delegate methods of the UIDropInteraction-delegate and not from the UICollectionViewDropDelegate. Just picked the correct methods and everything works as intended.

How can I update a UICollectionView from another class?

I am trying this for a couple of days now and haven't achieved anything yet. What I am trying to do is when a user picks a User item form the ViewController class, I want to save it in Realm and show it in the CollectionView of the SavedInterestsViewController class. I use a delegate pattern as suggested in this post How to access and refresh a UITableView from another class in Swift, but unfortunately I still receive nil, I guess because the GC removed the collectionView outlet already right? (please correct me if I misunderstood it). However, how can I get this to work by using a delegate pattern? Here is my code, this is the class where the user Picks a new User-item:
protocol ViewControllerDelegate {
func didUpdate(sender: ViewController)
}
class ViewController: UIViewController {
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var collectionView: UICollectionView!
var delegate: ViewControllerDelegate?
let numberOfTweets = 5
let realm = try! Realm()
var image = UIImage()
var imageArray: [String] = []
var userArray: [User] = []
override func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(UINib(nibName: "CollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "CollectionCell")
searchBar.delegate = self
}
}
extension ViewController: UISearchBarDelegate {
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
print("One second...")
let functionClass = NetworkingFunctions()
var loopCount = 0
functionClass.getWikipediaAssumptions(for: searchBar.text!) { [self] (articleArray) in
self.userArray.removeAll()
for x in articleArray {
functionClass.performWikipediaSearch(with: x, language: WikipediaLanguage("en")) { (user) in
self.userArray.append(user)
collectionView.reloadData()
loopCount += 1
}
}
}
}
}
extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return userArray.count
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCell", for: indexPath) as! CollectionViewCell
let image = UIImage.init(data: userArray[indexPath.item].image as Data)
cell.userImage.image = image
cell.nameLabel.text = userArray[indexPath.item].name
cell.userImage.layer.borderColor = image?.averageColor?.cgColor
if userArray[indexPath.item].checked == false {
cell.checkmark.isHidden = true
} else {
cell.checkmark.isHidden = false
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if userArray[indexPath.item].checked == false {
userArray[indexPath.item].checked = true
collectionView.reloadData()
let newUser = User()
newUser.image = userArray[indexPath.item].image
newUser.name = userArray[indexPath.item].name
newUser.checked = true
try! realm.write {
realm.add(newUser)
}
self.delegate = SavedInterestsViewController()
self.delegate?.didUpdate(sender: self)
}
else {
userArray[indexPath.item].checked = false
collectionView.reloadData()
}
}
}
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = UIScreen.main.bounds.width/3 - 10
let height = width
return CGSize(width: width, height: height)
}
}
class User: Object {
#objc dynamic var image: NSData = NSData()
#objc dynamic var name: String = ""
#objc dynamic var checked: Bool = false
}
... and this is the class where I want to show the selected item, after the User clicked on the 'Back' Button of the navigation controller of the ViewController class:
class SavedInterestsViewController: UIViewController, ViewControllerDelegate {
func didUpdate(sender: ViewController) {
DispatchQueue.main.async {
self.collectionView.reloadData()
}
}
#IBOutlet weak var addButton: UIBarButtonItem!
#IBOutlet weak var collectionView: UICollectionView!
let realm = try! Realm()
var userArray: [User] = []
override func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(UINib(nibName: "CollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "CollectionCell")
fetchDataFromRealm()
}
#IBAction func addButtonPressed(_ sender: UIBarButtonItem) {
performSegue(withIdentifier: "SavedToNew", sender: self)
}
func fetchDataFromRealm() {
userArray.append(contentsOf: realm.objects(User.self))
collectionView.reloadData()
}
}
extension SavedInterestsViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return userArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCell", for: indexPath) as! CollectionViewCell
let image = UIImage.init(data: userArray[indexPath.item].image as Data)
cell.userImage.image = image
cell.nameLabel.text = userArray[indexPath.item].name
cell.userImage.layer.borderColor = image?.averageColor?.cgColor
if userArray[indexPath.item].checked == false {
cell.checkmark.isHidden = true
} else {
cell.checkmark.isHidden = false
}
return cell
}
}
extension SavedInterestsViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = UIScreen.main.bounds.width/3 - 10
let height = width
return CGSize(width: width, height: height)
}
}
in your code you have lines
self.delegate = SavedInterestsViewController()
self.delegate?.didUpdate(sender: self)
but it do mostly nothing - you set the delegate to newly created class, didUpdate it - but I don't see any use of it - you don't present it in any way.
If I understand you right - you have SavedInterestsViewController, from it - you open ViewController, do something and when back to SavedInterestsViewController. (I can be wrong with your flow - correct me if so)
In this flow - you have delegate property in ViewController, but it must be of type SavedInterestsViewController. And you have to set it to SavedInterestsViewController when you open ViewController from it. And later in ViewController you have to call didUpdate method of delegate.

accessing an array of images from 1 view controller to another, to add swipe gesture recognizer

i have a collection view which has an array of images. when i press on any of the images it will open that image in full screen in another class. i tried to add swipe gesture recognizer in the second view controller but i dont know how to access the array that is in the first view controller.
This is my first view controller that displays the images in collection view
class sowrController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource{
#IBOutlet weak var collectionView: UICollectionView!
var albums = [AlbumModel]()
let db : DBHelperMo2lfat = DBHelperMo2lfat()
var selectedIndex : Int = -1
var posts : Post!
override func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
collectionView.dataSource = self
self.albums.removeAll()
self.albums.append(contentsOf: self.db.fetchAllImages())
self.collectionView.reloadData()
DataService.ds.REF_POSTS_SOWR.observe(.value, with: { (snapshot) in
if let snapshot = snapshot.children.allObjects as? [FIRDataSnapshot] {
self.albums.removeAll()
for snap in snapshot {
print ("SNAP: \(snap)")
if let postDict = snap.value as? Dictionary<String, AnyObject>{
let album : AlbumModel = AlbumModel(id: postDict["id"] as! String, name: postDict["image_name"] as! String, path: postDict["image_path"] as! String, url: postDict["image_path"] as! String, localPath: "")
if let items = snap.children.allObjects as? [FIRDataSnapshot] {
for itemSnap in items {
if let albumSnap = itemSnap.value as? Dictionary<String, AnyObject> {
album.childAlbums.append(AlbumModel(id: albumSnap["id"] as! String, name: albumSnap["image_name"] as! String, path: albumSnap["image_path"] as! String, url: albumSnap["image_path"] as! String, localPath: ""))
}
}
}
self.albums.append(album)
}
}
self.collectionView.reloadData()
}
})
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.albums.count
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Constants.BookCellReuseIdentifier, for: indexPath) as? collectionViewCellSowr {
let album = albums[indexPath.item]
cell.initWithAlbumModel(album: album)
return cell
}else {
return collectionViewCellSowr()
}
}
private struct Constants {
static let BookCellReuseIdentifier = "cell"
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.selectedIndex = indexPath.row
self.performSegue(withIdentifier: "showAlbum", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.identifier == "showAlbum"
{
let vc = segue.destination as! imageFullScreen
vc.images = self.albums[self.selectedIndex]
}
}
This is the second view controller that makes the images go in full screen
class imageFullScreen: UIViewController{
var images : AlbumModel?
let db : DBHelperMo2lfat = DBHelperMo2lfat()
#IBAction func pictureSwipe(_ sender: Any) {
}
#IBOutlet weak var caption: UILabel!
#IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
self.caption.text = images?.imageName
let url = URL(string: (images?.imagePath)!)
self.imageView.sd_setImage(with: url, placeholderImage: nil, options: [.progressiveDownload,.retryFailed])
}
EDIT:
Ok, so here is a collection view controller that creates image view as a subview and responding to swipe gestures. Please make sure you have two images "Image" and "Image-1" in your assets folder.
//
// CollectionViewController.swift
// test
//
// Created by Yonatan Vainer on 05/08/2017.
// Copyright © 2017 Sensus Healthcare LLC. All rights reserved.
//
import UIKit
private let reuseIdentifier = "id"
class CollectionViewController: UICollectionViewController {
var imageView = UIImageView(frame: CGRect(x: 0, y: 100, width: 300, height: 300))
var index = 0;
let names = ["Image","Image-1"]
override func viewDidLoad() {
super.viewDidLoad()
//For left swipe
let left = UISwipeGestureRecognizer(target: self, action: #selector(self.goLeft(_:)))
left.direction = .left
imageView.addGestureRecognizer(left)
//For right swipe
let right = UISwipeGestureRecognizer(target: self, action: #selector(self.goRight(_:)))
right.direction = .right
imageView.addGestureRecognizer(right)
imageView.isUserInteractionEnabled = true
self.view.addSubview(imageView)
self.view.layoutSubviews()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Register cell classes
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
// MARK: UICollectionViewDataSource
override func numberOfSections(in collectionView: UICollectionView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of items
return names.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath)
// Configure the cell
let nail = UIImageView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
nail.image = UIImage(named: names[indexPath.row])
cell.backgroundView = nail
return cell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
imageView.image = UIImage(named: names[indexPath.row])
index = indexPath.row
}
func goLeft(_ gesture: UISwipeGestureRecognizer){
index += 1
if index<0{
index = 0
}
imageView.image = UIImage(named: names[index])
}
func goRight(_ gesture: UISwipeGestureRecognizer){
index -= 1
if index>1{
index = 1
}
imageView.image = UIImage(named: names[index])
}
// MARK: UICollectionViewDelegate
/*
// Uncomment this method to specify if the specified item should be highlighted during tracking
override func collectionView(_ collectionView: UICollectionView, shouldHighlightItemAt indexPath: IndexPath) -> Bool {
return true
}
*/
/*
// Uncomment this method to specify if the specified item should be selected
override func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
return true
}
*/
/*
// Uncomment these methods to specify if an action menu should be displayed for the specified item, and react to actions performed on the item
override func collectionView(_ collectionView: UICollectionView, shouldShowMenuForItemAt indexPath: IndexPath) -> Bool {
return false
}
override func collectionView(_ collectionView: UICollectionView, canPerformAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) -> Bool {
return false
}
override func collectionView(_ collectionView: UICollectionView, performAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) {
}
*/
}
==================================================================
In storyboard, click on your collection view and embed navigation controller.
This will add a top bar with the back button.
Attached image.
I'm not sure I completely understand your question, because I don't understand what the array has to do with a gesture recognizer, but if you are just trying to access the array from the previous ViewController, this should work if you have a navigation controller :
let vcIndex = self.navigationController?.viewControllers.index(where: { (viewController) -> Bool in
if let _ = viewController as? sowrController {
return true
}
return false
})
let prevVC = self.navigationController?.viewControllers[vcIndex!] as! sowrController
let albums:[AlbumModel] = prevVC.albums

Error when peeking and popping from collection view

Received an error
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
when trying to peek and pop from a collection view. I've checked my data struct and index path but everything seems to be fine.
Here's my code for the collections view
class thisSeaonViewController: UICollectionViewController, UIViewControllerPreviewingDelegate {
#IBOutlet weak var activityIndicator: UIActivityIndicatorView!
var URLArrayStringThisSeason = [String]()
var currentURL = String()
override func viewDidLoad() {
generateData()
if( traitCollection.forceTouchCapability == .available){
registerForPreviewing(with: self as! UIViewControllerPreviewingDelegate, sourceView: view)
}
}
override func viewDidAppear(_ animated: Bool) {
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
let imageView = cell.viewWithTag(1) as! UIImageView
let url = NSURL(string: URLArrayStringThisSeason[indexPath.row])
let placeholderImage = UIImage(named: "Rectangle")!
let filter = AspectScaledToFillSizeWithRoundedCornersFilter(
size: imageView.frame.size,
radius: 0
)
imageView.af_setImage(withURL: url as! URL, placeholderImage: placeholderImage, filter: filter, imageTransition: .crossDissolve(0.2)
)
cell.backgroundColor = UIColor.init(hexString: "#F3F3F3")
cell.layer.cornerRadius = 3.0
return cell
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return URLArrayStringThisSeason.count
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let vc = storyboard?.instantiateViewController(withIdentifier: "gridDetailedView") as! gridDetailedViewController
vc.imageURL = URLArrayStringThisSeason[indexPath.row]
self.navigationController?.pushViewController(vc, animated: true)
}
func generateData() {
if URLArrayStringThisSeason.count == 0 {
self.activityIndicator.isHidden = false
self.activityIndicator.startAnimating()
}
let queryThisSeason = FIRDatabase.database().reference().child("thisSeason")
queryThisSeason.keepSynced(true)
queryThisSeason.observeSingleEvent(of: .value, with: {(snapshot) in
if snapshot.childrenCount != 0 {
let urlArray = snapshot.value as! [String]
let urlLimitedArray = Array(urlArray.reversed())
self.URLArrayStringThisSeason = urlLimitedArray
self.collectionView?.reloadData()
self.activityIndicator.stopAnimating()
self.activityIndicator.isHidden = true
}
})
}
func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
guard let indexPath = collectionView?.indexPathForItem(at: location) else { return nil }
guard let cell = collectionView?.cellForItem(at: indexPath) else { return nil }
guard let detailVC = storyboard?.instantiateViewController(withIdentifier: "gridDetailedView") as? gridDetailedViewController else { return nil }
//let photo = UIImage(named: "Rectangle")
detailVC.imageURL = URLArrayStringThisSeason[indexPath.row]
print(URLArrayStringThisSeason[indexPath.row])
detailVC.preferredContentSize = CGSize(width: 300, height: 300)
previewingContext.sourceRect = cell.frame
print("peek")
return detailVC
}
func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
self.navigationController?.show(viewControllerToCommit, sender: Any?.self)
print("pop")
}
}
when peeking and popping, the function is supposed to send the imageURL to the detailed view controller and AlamofireImage will handle the image download and loading.
However, I've been getting misalignment issues with the collections view as the source rect will appear slightly above the cells and preventing peek and pop at certain parts of the cell. I think that this could be the cause of the peek and pop crash too.
edit:
here's what happens when I try to do peek and pop, you can see the focus of the cell is slightly shifted on top.
Ok I fixed the misalignment problem by changing this registerForPreviewingWithDelegate(self, sourceView: view)
to this
registerForPreviewingWithDelegate(self, sourceView: self.collectionView!)
however, the app is still crashes everytime I try to peek and pop.
Edit:
Ok the other problem is pretty much just some errors in the code. Just follow the above to fix the misalignment problem.