How to dynamically update my gallery data - swift

Hello Respected Comrades,
I made a gallery app. initially I get a data of media from phone.
but when i add some new photos to device. i cant see them until :
re install app
fetching in view will appear (this is just a temperory fix)
I want to update my data dynamically with respect to phone data
code:
import UIKit
import Foundation
import Photos
import CoreData
enum MediaType{
case video, photo
}
View model
class GalleryPageViewModel : BaseViewModel{
var mediaArray = Spectator<MediaArray?>(value:
[])
var title = "Gallery"
var appDelegate:AppDelegate?
var context : NSManagedObjectContext?
let responder : AppResponder
var tempMedia = [MediaModel]()
init(with responder:AppResponder){
self.responder = responder
super.init()
}
}
extension GalleryPageViewModel{
func populatePhotos(){
mediaArray.value = []
tempMedia = []
PHPhotoLibrary.requestAuthorization{ [weak self] status in
if status == .authorized{
let assets = PHAsset.fetchAssets(with: nil)
assets.enumerateObjects{ (object,_,_) in
var image = UIImage()
image = self!.conversionPhotoToImage(asset: object)
var mediaType : MediaType = .photo
if object.mediaType == .video{
mediaType = .video
}
let media = MediaModel(img: image, asset: object, mediaType: mediaType)
self?.tempMedia.append(media)
}
}
else{
print("auth failed")
}
self?.setUpData()
}
}
func conversionPhotoToImage(asset : PHAsset) -> UIImage{
let manager = PHImageManager.default()
var media = UIImage()
let requestOptions=PHImageRequestOptions()
requestOptions.isSynchronous=true
requestOptions.deliveryMode = .highQualityFormat
manager.requestImage(for: asset, targetSize: CGSize(width: 1000, height: 1000), contentMode:.aspectFill, options: requestOptions) { image,_ in
media = image!
}
return media
}
func setUpData(){
self.mediaArray.value = tempMedia
}
}
extension GalleryPageViewModel{
func numberOfItemsInSection() -> Int{
return mediaArray.value?.count ?? 0
}
func didSelectAtRow(index:IndexPath){
self.responder.pushToDetailVc(data: mediaArray.value![index.row])
}
}
extension GalleryPageViewModel{
func setUpCoreData(){
appDelegate = UIApplication.shared.delegate as! AppDelegate
context = appDelegate?.persistentContainer.viewContext
}
func storeInCoreData(){
let entity = NSEntityDescription.entity(forEntityName: "MediaData", in: context!)
let newUser = NSManagedObject(entity: entity!, insertInto: context)
var i = 1
for data in mediaArray.value!{
newUser.setValue(data.img, forKey: "image")
newUser.setValue(data.duration, forKey: "duration")
newUser.setValue("data", forKey: "mediaType")
newUser.setValue(data.location, forKey: "location")
newUser.setValue(data.creationDate, forKey: "creationDate")
var id = String()
if data.mediaType == .photo{
id = "imgEn\(i)"
}
else{
id = "vidEn\(i)"
}
i+=1
newUser.setValue(id, forKey: "id")
}
}
}
View controller
import UIKit
import Photos
class GalleryPageViewController: BaseViewController {
var galleryCollectionView : UICollectionView?
var galleryCollectionViewFlowLayout : UICollectionViewFlowLayout? = nil
var viewModel: GalleryPageViewModel? {
didSet {
self.bindViewModel()
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.title = viewModel?.title
view.backgroundColor = .systemBackground
setUpFlowLayout()
galleryCollectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: galleryCollectionViewFlowLayout!)
galleryCollectionView?.register(MediaCollectionViewCell.self, forCellWithReuseIdentifier: "cell")
setUpCollectionView()
viewConstraintsForGalleryPage()
viewModel?.populatePhotos()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
}
// MARK: - UI WORKS
extension GalleryPageViewController{
func setUpFlowLayout(){
galleryCollectionViewFlowLayout = UICollectionViewFlowLayout()
galleryCollectionViewFlowLayout?.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)
galleryCollectionViewFlowLayout?.itemSize = CGSize(width: (view.frame.width/2) - 20, height: (self.view.frame.width/2)-10)
}
func setUpCollectionView(){
galleryCollectionView?.dataSource = self
galleryCollectionView?.delegate = self
}
func viewConstraintsForGalleryPage(){
// adding sub view to maintain heirarchy.
view.addSubview(galleryCollectionView!)
// constraints for views in this page
// collection view
galleryCollectionView?.translatesAutoresizingMaskIntoConstraints = false
// galleryCollectionView?.backgroundColor = .blue
galleryCollectionView?.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor,constant: 10).isActive = true
galleryCollectionView?.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor).isActive = true
galleryCollectionView?.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor,constant: 10).isActive = true
galleryCollectionView?.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor).isActive = true
}
}
//MARK: - COLLECTION VIEW DELEGATE AND DATA SOURCE
extension GalleryPageViewController : UICollectionViewDelegate{
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// vc.data = viewModel?.mediaArray.value?[indexPath.row]
viewModel?.didSelectAtRow(index: indexPath)
}
}
extension GalleryPageViewController : UICollectionViewDataSource{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return viewModel?.numberOfItemsInSection() ?? 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! MediaCollectionViewCell
let cellData = viewModel?.mediaArray.value?[indexPath.row]
cell.imageView.image = cellData?.img
if cellData?.mediaType == .video{
cell.playBtn.isHidden = false
cell.durationLabel.isHidden = false
let manager = PHImageManager.default()
manager.requestAVAsset(forVideo: (cellData?.asset)!, options: nil){asset,_,_ in
let duration = asset?.duration
let durationTime = CMTimeGetSeconds(duration!)
let finalTime = durationTime/60
DispatchQueue.main.async {
cell.durationLabel.text = "\(Int(finalTime)) : \(Int(durationTime) % 60)"
}
}
}
else{
cell.playBtn.isHidden = true
cell.durationLabel.isHidden = true
}
return cell
}
}
//MARK: - BINDING VARIABLES
extension GalleryPageViewController{
private func bindViewModel(){
viewModel?.mediaArray.bind { [weak self] _ in
print("i am gonna reload")
print(self?.viewModel?.mediaArray.value?.isEmpty)
DispatchQueue.main.async {
self?.galleryCollectionView?.reloadData()
}
}
}
}

Related

delegate not being called in Network class

I am working with stackoverflow api in Worker class I am getting data and adding to tableView. I managed to connect and get the data and I'm trying to add it to the main view controller using a delegate, but the compiler ignores this line, what could be the matter?
When writing to the searchButton procedure, I call a method of the Worker class that receives data from the API and adds it to the array. Then, with the help of a delegate, I return a mass, but this delegate is not called.
class viewController
import UIKit
protocol WorkerDelegate: AnyObject {
func getListModels(noteModels: [CellModel])
}
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, WorkerDelegate{
private var listModels: [CellModel] = []
private var searchText = UITextField()
private var searchButton = UIButton()
private var table = UITableView()
private let worker = Worker()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
let worker = Worker()
worker.workerDelegate = self
setupSearchText()
setupSearchButton()
table.register(CustomCell.self, forCellReuseIdentifier: "Cell")
table.delegate = self
table.dataSource = self
setupUI()
// Do any additional setup after loading the view.
}
func getListModels(noteModels: [CellModel]) {
listModels += noteModels
table.reloadData()
}
private func setupSearchText() {
searchText.translatesAutoresizingMaskIntoConstraints = false
searchText.font = UIFont.systemFont(ofSize: 14, weight: .bold)
searchText.textColor = .black
searchText.backgroundColor = .white
searchText.borderStyle = UITextField.BorderStyle.roundedRect
searchText.layer.borderWidth = 1
searchText.layer.borderColor = UIColor.black.cgColor
//date.textAlignment = .center
view.addSubview(searchText)
searchText.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
searchText.leadingAnchor.constraint(
equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 20
).isActive = true
searchText.trailingAnchor.constraint(
equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -70
).isActive = true
}
private func setupSearchButton() {
searchButton.translatesAutoresizingMaskIntoConstraints = false
// searchButton.font = UIFont.systemFont(ofSize: 14, weight: .bold)
// searchButton.textColor = .black
searchButton.backgroundColor = .white
// searchButton.borderStyle = UITextField.BorderStyle.roundedRect
searchButton.layer.borderWidth = 1
searchButton.setTitle("OK",
for: .normal)
// searchButton.titleLabel?.font = UIFont.systemFont(ofSize: 24)
searchButton.setTitleColor(.black, for: .normal)
searchButton.layer.borderColor = UIColor.black.cgColor
//date.textAlignment = .center
view.addSubview(searchButton)
searchButton.addTarget(self, action: #selector(didSearchButtonnTap(_:)), for: .touchUpInside)
searchButton.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
searchButton.leadingAnchor.constraint(
equalTo: searchText.safeAreaLayoutGuide.trailingAnchor, constant: 10
).isActive = true
searchButton.trailingAnchor.constraint(
equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -20
).isActive = true
}
private func setupUI() {
table.translatesAutoresizingMaskIntoConstraints = false
table.separatorStyle = .none
view.addSubview(table)
table.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
table.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
table.topAnchor.constraint(equalTo: searchText.bottomAnchor,constant: 20).isActive = true
table.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
listModels.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as? CustomCell else {
fatalError("не CustomCell")
}
cell.selectionStyle = .none
cell.model = listModels[indexPath.row]
cell.layer.cornerRadius = 14
cell.layer.shadowRadius = 14
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// нажатие
}
#objc private func didSearchButtonnTap(_ sender: Any) {
worker.fetch(question: searchText.text ?? "")
table.reloadData()
}
}
class Worker
import Foundation
class Worker {
let session: URLSession
var workerDelegate: WorkerDelegate?
func fetch(question: String) {
var listModels: [CellModel] = [CellModel(title: "123",name: "312",date: Date.now, answer_count: Int32(0)
)]
if let url = createURLComponents(question: question) {
url.asyncDownload { data, _, error in
guard let data = data else {
print("URLSession dataTask error:", error ?? "nil")
return
}
do {
let jsonObject = try JSONDecoder().decode(SearchModels.self, from: data)
_ = String(data: data, encoding: .utf8)
for object in jsonObject.items {
let timeInterval = TimeInterval(object.creationDate)
let newDate = Date(timeIntervalSince1970: timeInterval)
var model = CellModel(
title: object.title,
name: object.owner.displayName,
date: newDate,
answer_count: Int32(object.answerCount)
)
listModels.append(model)
}
DispatchQueue.main.async {
self.workerDelegate?.getListModels(noteModels: listModels)
}
} catch {
print(error.localizedDescription)
}
}
}
}
init(
session: URLSession = URLSession(configuration: .default)
) {
self.session = session
}
private func createURLComponents(question: String) -> URL? {
var urlComponents = URLComponents()
urlComponents.scheme = "https"
urlComponents.host = "api.stackexchange.com"
urlComponents.path = "/2.3/search"
urlComponents.queryItems = [
URLQueryItem(name: "order", value: "desc"),
URLQueryItem(name: "sort", value: "activity"),
URLQueryItem(name: "intitle", value: question),
URLQueryItem(name: "site", value: "stackoverflow")
]
return urlComponents.url!
}
private func createURLRequest(question: String) -> URLRequest {
var request = URLRequest(url: createURLComponents(question: question)!)
request.httpMethod = "GET"
return request
}
}
extension URL {
func asyncDownload(completion: #escaping (_ data: Data?, _ response: URLResponse?, _ error: Error?) -> Void) {
URLSession.shared
.dataTask(with: self, completionHandler: completion)
.resume()
}
}

The background of the TableView at the bottom displays a blank cell

I have this UITableView that has xib files as cells and it all works as intended, however the last cell only when I scroll down doesn't have a background color. It only happens when I scroll down and then it pops back to normal position. I'm essentially wondering how I can change the color of that cell just to my background color. Thank you.
//
// BlogViewController.swift
// testAPI
//
// Created by Dilan Piscatello on 4/2/20.
// Copyright © 2020 Dilan Piscatello. All rights reserved.
//
import Foundation
import UIKit
import Firebase
class BlogViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
var x = 0
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0{
return 1
}else{
return posts.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0{
let cell = Bundle.main.loadNibNamed("QuestionTableViewCell", owner: self, options: nil)?.first as! QuestionTableViewCell
print("this is how many times it ran")
cell.setPost(question: self.question)
return cell
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: "postcell", for: indexPath) as! PostTableViewCell
cell.setPost(post: posts[indexPath.row])
return cell
}
}
var question = "sdfsdfs"
var tableView:UITableView!
var lastUploadPostID:String?
var discussion:UILabel! = UILabel()
var posts = [Post]()
var fetchingMore = false
var endReached = false
let leadingScreensForBatching:CGFloat = 3.0
var cellHeights: [IndexPath:CGFloat] = [:]
var refreshControl:UIRefreshControl!
var postRef:DatabaseReference{
return Database.database().reference().child("posts")
}
var oldPostQuery:DatabaseQuery{
var queryRef:DatabaseQuery
let lastPost = self.posts.last
if lastPost == nil{
queryRef = postRef.queryOrdered(byChild: "timestamp")
}else{
let lastTimestamp = lastPost!.createdAt.timeIntervalSince1970*1000
queryRef = postRef.queryOrdered(byChild: "timestamp").queryEnding(atValue: lastTimestamp)
}
return queryRef
}
var newPostQuery:DatabaseQuery{
var queryRef:DatabaseQuery
let firstPost = self.posts.first
if firstPost == nil{
queryRef = postRef.queryOrdered(byChild: "timestamp")
}else{
let firstTimestamp = firstPost!.createdAt.timeIntervalSince1970*1000
queryRef = postRef.queryOrdered(byChild: "timestamp").queryStarting(atValue: firstTimestamp)
}
return queryRef
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
func hi(){
let db = Firestore.firestore()
db.collection("blog").document("question").getDocument { (document,error) in
if error != nil{
print("cant get data")
}
if document != nil && document!.exists{
if let documentdata = document?.data() {
self.question = documentdata["question"] as! String
self.tableView.reloadData()
}
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
discussion.text = "Discussion"
//longTitleLabel.font = ................
discussion.font = UIFont(name: "HelveticaNeue-Bold", size: 31)
discussion.translatesAutoresizingMaskIntoConstraints = false
if let navigationBar = self.navigationController?.navigationBar {
navigationBar.addSubview(discussion)
//navigationBar.shadowImage = UIImage()
// navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
// navigationBar.isTranslucent = true
navigationBar.barTintColor = UIColor( red: 128/255, green: 117/255, blue: 255/255, alpha: 1)
discussion.leftAnchor.constraint(equalTo: navigationBar.leftAnchor, constant: 22).isActive = true
discussion.widthAnchor.constraint(equalToConstant: 300).isActive = true
tableView = UITableView()
tableView.translatesAutoresizingMaskIntoConstraints = false
self.tableView.separatorStyle = .none
view.addSubview(tableView)
hi()
print(question)
// Do any additional setup after loading the view.
let cellNib = UINib(nibName: "PostTableViewCell", bundle: nil)
tableView.register(cellNib, forCellReuseIdentifier: "postcell")
var layoutGuide:UILayoutGuide!
layoutGuide = view.safeAreaLayoutGuide
tableView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 10).isActive = true
tableView.topAnchor.constraint(equalTo: view.topAnchor, constant: 40).isActive = true
tableView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -10).isActive = true
tableView.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor).isActive = true
tableView.delegate = self
tableView.dataSource = self
tableView.tableFooterView = UIView()
tableView.reloadData()
refreshControl = UIRefreshControl()
tableView.refreshControl = refreshControl
refreshControl.addTarget(self, action: #selector(handleRefresh), for: .valueChanged)
beginBatchFetch()
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// if let navigationController = navigationController as? ScrollingNavigationController {
// navigationController.followScrollView(tableView, delay: 0.0)
//}
listenForNewPosts()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
stopListeningForNewPosts()
}
#objc func handleRefresh(){
print()
newPostQuery.queryLimited(toFirst: 20).observeSingleEvent(of: .value, with: { (snapshot) in
var tempPosts = [Post]()
let firstPost = self.posts.first
for child in snapshot.children{
if let childSnapshot = child as? DataSnapshot,
let dict = childSnapshot.value as? [String:Any],
let post = Post.parse(childSnapshot.key, dict),
childSnapshot.key != firstPost?.id{
tempPosts.insert(post, at: 0)
}
}
self.posts.insert(contentsOf: tempPosts, at: 0)
self.tableView.reloadData()
self.refreshControl.endRefreshing()
//let newIndexPaths = (1..<tempPosts.count).map { i in
// return IndexPath(row: i, section: 1)
//}
//self.tableView.insertRows(at: newIndexPaths, with: .top)
// self.refreshControl.endRefreshing()
// self.tableView.scrollToRow(at: IndexPath(row:0,section: 0), at: .top, //animated:true)
//self.listenForNewPosts()
//return completion(tempPosts)
//self.posts = tempPosts
//self.tableView.reloadData()
})
}
func fetchPosts(completion: #escaping(_ posts:[Post])->()){
oldPostQuery.queryLimited(toLast: 20).observeSingleEvent(of: .value, with: { (snapshot) in
var tempPosts = [Post]()
let lastPost = self.posts.last
for child in snapshot.children{
if let childSnapshot = child as? DataSnapshot,
let dict = childSnapshot.value as? [String:Any],
let post = Post.parse(childSnapshot.key, dict),
childSnapshot.key != lastPost?.id{
tempPosts.insert(post, at: 0)
}
}
return completion(tempPosts)
//self.posts = tempPosts
//Zself.tableView.reloadData()
})
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cellHeights[indexPath] = cell.frame.size.height
cell.selectionStyle = UITableViewCell.SelectionStyle.none
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return cellHeights[indexPath] ?? 72.0
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let offsetY = scrollView.contentOffset.y
let contentHeight = scrollView.contentSize.height
if offsetY > contentHeight - scrollView.frame.size.height * leadingScreensForBatching {
if !fetchingMore && !endReached {
beginBatchFetch()
}
}
}
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
func beginBatchFetch(){
fetchingMore = true
fetchPosts{ newPosts in
self.posts.append(contentsOf: newPosts)
self.endReached = newPosts.count == 0
self.fetchingMore = false
UIView.performWithoutAnimation {
self.tableView.reloadData()
self.listenForNewPosts()
}
}
//fetch the post
}
var postListenerHandle:UInt?
func listenForNewPosts(){
guard !fetchingMore else{ return}
//to avoid the listeners twice (duplicate)
stopListeningForNewPosts()
postListenerHandle = newPostQuery.observe(.childAdded) { (snapshot) in
if snapshot.key != self.posts.first?.id {
if let data = snapshot.value as? [String:Any],
//let post = Post.parse(snapshot.key,data)
let _ = Post.parse(snapshot.key,data){
self.stopListeningForNewPosts()
if snapshot.key == self.lastUploadPostID{
self.handleRefresh()
self.lastUploadPostID = nil
}else{
}
}
}
}
}
func stopListeningForNewPosts(){
if let handle = postListenerHandle{
newPostQuery.removeObserver(withHandle: handle)
postListenerHandle = nil
}
}
// func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool {
//if let navigationController = navigationController as? //ScrollingNavigationController {
// navigationController.showNavbar(animated: true, scrollToTop: true)
//}
// return true
//}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let newPostNavBar = segue.destination as? UINavigationController,
let newPostVC = newPostNavBar.viewControllers[0] as? WritePostViewController{
newPostVC.delegate = self
}
}
}
extension BlogViewController: NewPostVCDelegate{
func didUploadPost(withID id: String) {
print("what up this is the id \(id)")
self.lastUploadPostID = id
}
}
In the storyboard add inside the tableView as last element a transparent view with height equal to 1

Pass image from collection to viewcontroller swift

i haave problem i can't Pass ImageView From collection to viewcontroller using Firebase Database
This My Code
import UIKit
import Firebase
import FirebaseDatabase
import SDWebImage
import FirebaseStorage
import KRProgressHUD
class ViewControllerCollocation: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var MyColloctaion: UICollectionView!
var imagePicker = UIImagePickerController()
var images = [ImagePost]()
var dbRef:DatabaseReference!
override func viewDidLoad() {
super.viewDidLoad()
setutxent()
designCollectionView()
imagePicker.delegate = self
dbRef = Database.database().reference().child("Images")
/////////
loadDB()
KRProgressHUD.set(style: .custom(background: .black, text: .white, icon: nil))
KRProgressHUD.show(withMessage: "Loading...")
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
KRProgressHUD.dismiss()
}
}
func loadDB(){
dbRef.observe(DataEventType.value, with: { (snapshot) in
var newImages = [ImagePost]()
for imageFireSnapshot in snapshot.children {
let ImagesFireObject = ImagePost(snapshot: imageFireSnapshot as! DataSnapshot)
newImages.append(ImagesFireObject)
}
self.images = newImages
self.MyColloctaion.reloadData()
}
)}
func collectionView(_ colloction: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return images.count
}
internal func collectionView(_ colloction: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = colloction.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! UploadOneCollectionViewCell
let image = images[indexPath.row]
cell.ImageView.layer.cornerRadius = 13
cell.ImageView.clipsToBounds = true
cell.ImageView.sd_setImage(with: URL(string: image.url), placeholderImage: UIImage(named: "Image1"))
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
}
func designCollectionView() {
let itemSize = UIScreen.main.bounds.width/3 - 3
let layout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 1, left: 1, bottom: 1, right: 1)
layout.itemSize = CGSize(width: itemSize, height: 230)
layout.minimumInteritemSpacing = 1
layout.minimumLineSpacing = 1
//layout.scrollDirection = .horizontal
self.MyColloctaion.isPagingEnabled = true
MyColloctaion.collectionViewLayout = layout
}
func steupbar(){
navigationController?.navigationBar.barTintColor = UIColor.black
tabBarController?.tabBar.barTintColor = UIColor.black
self.navigationController?.navigationBar.titleTextAttributes =
[NSAttributedString.Key.foregroundColor: UIColor.white,
NSAttributedString.Key.font: UIFont(name: "Baskerville-BoldItalic", size: 21)!]
}
#IBAction func Upload(_ sender: Any) {
imagePicker = UIImagePickerController()
imagePicker.allowsEditing = false
imagePicker.sourceType = .photoLibrary
imagePicker.delegate = self
self.present(imagePicker, animated: true, completion: nil)
}
func generateRandom(size: UInt) -> String {
let prefixSize = Int(min(size, 43))
let uuidString = UUID().uuidString.replacingOccurrences(of: "-", with: "")
return String(Data(uuidString.utf8)
.base64EncodedString()
.replacingOccurrences(of: "=", with: "")
.prefix(prefixSize))
}
}
this is My ""ImagePost.swift"""
import Foundation
import FirebaseDatabase
struct ImagePost {
let key: String!
let url:String!
let itemRef:DatabaseReference?
init(url:String, key:String) {
self.key = key
self.url = url
self.itemRef = nil
}
init(snapshot:DataSnapshot) {
key = snapshot.key
itemRef = snapshot.ref
let snapshotValue = snapshot.value as? NSDictionary
if let imageUrl = snapshotValue?["url"] as? String {
url = imageUrl
}else{
url = ""
}
}
}
and This is My detail view
import UIKit
class VC1: UIViewController {
var imageURL : String?
#IBOutlet weak var ImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
}
}
and Thanks for your help guys!
You can pass image to detail view by getting image in didselect method:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let image = images[indexPath.row]
let vc = self.storyboard?.instantiateViewController(withIdentifier: "VC1") as! VC1
vc.imageObject = images[indexPath.row]
self.navigationController?.pushViewController(vc, animated: false)
}
Just create a variable as imageObject in VC1 and pass data to it as shown above.

Swift Toolbar button triggers a exec_bad_instruction only on one scene

I'm changing my app to start to use toolbar buttons for the main pages instead of a menu. All of the menu links work and the toolbar buttons work on every page except one. When I click on the button the app freezes, and Xcode brings me to this line:
'weak var itemDetailPage = segue.destination as? ItemDetailViewController' with this error:
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
All the variables are nil.
Any help would be monumental!
Here is the code for the view controller it is specifically happening on:
import UIKit
import AVFoundation
import Alamofire
#objc protocol FavRefreshLikeCountsDelegate: class {
func updateLikeCounts(_ likeCount: Int)
}
#objc protocol FavRefreshReviewCountsDelegate: class {
func updateReviewCounts(_ reviewCount: Int)
}
class FavouriteItemsViewController: UICollectionViewController {
var populationItems = false
var selectedSubCategoryId:Int = 0
var selectedCityId:Int = 1
var selectedCityLat: String!
var selectedCityLng: String!
var items = [ItemModel]()
var currentPage = 0
var loginUserId:Int = 0
weak var selectedCell : AnnotatedPhotoCell!
#IBOutlet weak var menuButton: UIBarButtonItem!
var defaultValue: CGPoint!
override func viewDidLoad() {
if self.revealViewController() != nil {
menuButton.target = self.revealViewController()
menuButton.action = #selector(SWRevealViewController.revealToggle(_:))
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
collectionView!.register(AnnotatedPhotoCell.classForCoder(), forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: "AnnotatedPhotoCell")
if let layout = collectionView?.collectionViewLayout as? PinterestLayout {
layout.delegate = self
}
loadLoginUserId()
loadFavouriteItems()
defaultValue = collectionView?.frame.origin
animateCollectionView()
}
override func viewDidAppear(_ animated: Bool) {
updateNavigationStuff()
}
override var preferredStatusBarStyle : UIStatusBarStyle {
return UIStatusBarStyle.lightContent
}
override func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
loadFavouriteItems()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
weak var itemCell = sender as? AnnotatedPhotoCell
weak var itemDetailPage = segue.destination as? ItemDetailViewController
itemDetailPage!.selectedItemId = Int((itemCell!.item?.itemId)!)!
itemDetailPage!.selectedShopId = Int((itemCell!.item?.itemShopId)!)!
itemDetailPage!.favRefreshLikeCountsDelegate = self
itemDetailPage!.favRefreshReviewCountsDelegate = self
selectedCell = itemCell
updateBackButton()
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return items.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
var cell : AnnotatedPhotoCell
cell = collectionView.dequeueReusableCell(withReuseIdentifier: "AnnotatedPhotoCell", for: indexPath) as! AnnotatedPhotoCell
cell.item = items[(indexPath as NSIndexPath).item]
let imageURL = configs.imageUrl + items[(indexPath as NSIndexPath).item].itemImage
cell.imageView?.loadImage(urlString: imageURL) { (status, url, image, msg) in
if(status == STATUS.success) {
print(url + " is loaded successfully.")
self.items[indexPath.item].itemImageBlob = image
}else {
print("Error in loading image" + msg)
}
}
cell.imageView.alpha = 0
cell.captionLabel.alpha = 0
UIView.animate(withDuration: 1, delay: 0, options: UIViewAnimationOptions.curveEaseIn, animations: {
cell.imageView.alpha = 1.0
cell.captionLabel.alpha = 1.0
}, completion: nil)
return cell
}
func updateBackButton() {
let backItem = UIBarButtonItem()
backItem.title = ""
navigationItem.backBarButtonItem = backItem
}
func updateNavigationStuff() {
self.navigationController?.navigationBar.topItem?.title = language.favouritePageTitle
self.navigationController?.navigationBar.titleTextAttributes = [ NSAttributedStringKey.font: UIFont(name: customFont.boldFontName, size: CGFloat(customFont.boldFontSize))!, NSAttributedStringKey.foregroundColor:UIColor.white]
self.navigationController!.navigationBar.barTintColor = Common.instance.colorWithHexString(configs.barColorCode)
}
func loadLoginUserId() {
let plistPath = Common.instance.getLoginUserInfoPlist()
let myDict = NSDictionary(contentsOfFile: plistPath)
if let dict = myDict {
loginUserId = Int(dict.object(forKey: "_login_user_id") as! String)!
print("Login User Id : " + String(loginUserId))
} else {
print("WARNING: Couldn't create dictionary from LoginUserInfo.plist! Default values will be used!")
}
}
func loadFavouriteItems() {
if self.currentPage == 0 {
_ = EZLoadingActivity.show("Loading...", disableUI: true)
}
Alamofire.request(APIRouters.GetFavouriteItems( loginUserId, configs.pageSize, self.currentPage)).responseCollection {
(response: DataResponse<[Item]>) in
if self.currentPage == 0 {
_ = EZLoadingActivity.hide()
}
if response.result.isSuccess {
if let items: [Item] = response.result.value {
if(items.count > 0) {
for item in items {
let oneItem = ItemModel(item: item)
self.items.append(oneItem)
self.currentPage+=1
}
}
}
self.collectionView!.reloadData()
} else {
print(response)
}
}
}
func animateCollectionView() {
moveOffScreen()
UIView.animate(withDuration: 1, delay: 0,
usingSpringWithDamping: 0.9,
initialSpringVelocity: 0.9, options: UIViewAnimationOptions.curveEaseOut, animations: {
self.collectionView?.frame.origin = self.defaultValue
}, completion: nil)
}
fileprivate func moveOffScreen() {
collectionView?.frame.origin = CGPoint(x: (collectionView?.frame.origin.x)!,
y: (collectionView?.frame.origin.y)! + UIScreen.main.bounds.size.height)
}
}
extension FavouriteItemsViewController : PinterestLayoutDelegate {
func collectionView(_ collectionView:UICollectionView, heightForPhotoAtIndexPath indexPath:IndexPath , withWidth width:CGFloat) -> CGFloat {
let item = items[(indexPath as NSIndexPath).item]
let boundingRect = CGRect(x: 0, y: 0, width: width, height: CGFloat(MAXFLOAT))
let size = CGSize(width: item.itemImageWidth, height: item.itemImageHeight)
var rect : CGRect
if item.itemImageBlob != nil {
rect = AVMakeRect(aspectRatio: item.itemImageBlob!.size, insideRect: boundingRect)
}else{
rect = AVMakeRect(aspectRatio: size, insideRect: boundingRect)
}
return rect.size.height
}
func collectionView(_ collectionView: UICollectionView, heightForAnnotationAtIndexPath indexPath: IndexPath, withWidth width: CGFloat) -> CGFloat {
let annotationPadding = CGFloat(4)
let annotationHeaderHeight = CGFloat(17)
let height = annotationPadding + annotationHeaderHeight + annotationPadding + 30
return height
}
}
extension FavouriteItemsViewController : FavRefreshLikeCountsDelegate, FavRefreshReviewCountsDelegate {
func updateLikeCounts(_ likeCount: Int) {
if selectedCell != nil {
selectedCell.lblLikeCount.text = "\(likeCount)"
}
}
func updateReviewCounts(_ reviewCount: Int) {
if selectedCell != nil {
selectedCell.lblReviewCount.text = "\(reviewCount)"
}
}
}
You should try be checking your ItemDetailViewController.
for example:
if segue.identifier == "ItemDetailVC" {
weak var itemCell = sender as? AnnotatedPhotoCell
weak var itemDetailPage = segue.destination as? ItemDetailViewController
...
}

Implement UISearchBarController within UICollectionViewController (Swift 4)?

I'm trying to implement an UISearchBarController in UICollectionViewController, here are the codes:
class FirstViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout, UISearchResultsUpdating {
var titles: [String] = []
var card: [RecommendArticles]?
var searchArr = [String](){
didSet {
self.collectionView?.reloadData()
}
}
func updateSearchResults(for searchController: UISearchController) {
guard let searchText = searchController.searchBar.text else {
return
}
searchArr = titles.filter { (title) -> Bool in
return title.contains(searchText)
}
}
let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
navigationItem.hidesSearchBarWhenScrolling = true
self.navigationItem.searchController = searchController
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if (searchController.isActive) {
return searchArr.count
} else {
return self.counters
}
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: verticalCellId, for: indexPath) as! VerticalCellId
if (searchController.isActive) {
cell.titleLabel.text = searchArr[indexPath.row]
return cell
} else {
if let link = self.card?[indexPath.item]._imageURL {
let url = URL(string: link)
cell.photoImageView.kf.setImage(with: url)
}
if let title = self.card?[indexPath.item]._title {
cell.titleLabel.text = title
titles.append(title)
print("\(titles)")
}
if let source = self.card?[indexPath.item]._source {
cell.sourceLabel.text = source
}
return cell
}
}
Here are the errors locate:
titles.append(title)
print("\(titles)")
When I search a keyword, the filtered results are incorrect, because the collection view cell will change dynamically (I'm not sure if my expression is accurate).
But, if I set up the variable titles like this, it works perfectly:
var titles = ["Tom","Jack","Lily"]
But I have to retrieve the values of titles from internet. Any suggestions would be appreciated.
Here are the update question for creating an array after self.card:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
self.view.addSubview(activityView)
activityView.hidesWhenStopped = true
activityView.center = self.view.center
activityView.startAnimating()
let dynamoDbObjectMapper = AWSDynamoDBObjectMapper.default()
dynamoDbObjectMapper.load(TheUserIds2018.self, hashKey: "TheUserIds2018", rangeKey: nil, completionHandler: { (objectModel: AWSDynamoDBObjectModel?, error: Error?) -> Void in
if let error = error {
print("Amazon DynamoDB Read Error: \(error)")
return
}
DispatchQueue.main.async {
if let count = objectModel?.dictionaryValue["_articleCounters"] {
self.counters = count as! Int
self.collectionView?.reloadData()
self.updateItems()
self.activityView.stopAnimating()
}
}
})
}
func updateItems() {
let dynamoDbObjectMapper = AWSDynamoDBObjectMapper.default()
var tasksList = Array<AWSTask<AnyObject>>()
for i in 1...self.counters {
tasksList.append(dynamoDbObjectMapper.load(RecommendArticles.self, hashKey: "userId" + String(self.counters + 1 - i), rangeKey: nil))
}
AWSTask<AnyObject>.init(forCompletionOfAllTasksWithResults: tasksList).continueWith { (task) -> Any? in
if let cards = task.result as? [RecommendArticles] {
self.card = cards
DispatchQueue.main.async {
if let totalCounts = self.card?.count {
for item in 0...totalCounts - 1 {
if let title = self.card?[item]._title {
self.newTitle = title
}
self.titles.append(self.newTitle)
print("titles: \(self.titles)")
}
}
}
} else if let error = task.error {
print(error.localizedDescription)
}
return nil
}
}
This is not an issue with UISearchController . it is with your data. Collection view data source method -
cellForItemAtIndexPath works only when cell is presented in the view. So you can't keep the code for creating array of titles in the cellForItemAtIndexPath
Instead of separately keeping title strings in array for search you can directly filter self.card array with search text in title with below code
self.searchArr = self.card?.filter(NSPredicate(format:"_title CONTAINS[cd] %#",searchText)).sorted(byKeyPath: "_title", ascending: true)
or
you can create array of titles before loading collection view
Some where after you create self.card