I want to get an if statement which, if the selected button corresponded to the first image view, set it to the first image, else set it to the second image view... But, once I select the image from the image picker, it just ignores it and moves on like if nothing happened.
Here is my code:
(it down under the image picker controller func...)
class UploadSubPostCell: UICollectionViewCell {
#IBOutlet weak var previewStep: UIImageView!
}
class UploadViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var previewImage: UIImageView!
#IBOutlet weak var postBtn: UIButton!
#IBOutlet weak var selectBtn: UIButton!
#IBOutlet weak var postscollectionview: UICollectionView!
#IBOutlet weak var selectStepsBtn: UIButton!
var picker = UIImagePickerController()
var isThumbnailImage = true
var subpostsArray = [UIImage]()
var subposts = [SubPost]()
var posts = [Post]()
override func viewDidLoad() {
super.viewDidLoad()
setupNavigationBarItems()
picker.delegate = self
}
func setupNavigationBarItems() {
navigationItem.title = "Upload"
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerEditedImage] as? UIImage {
let path = IndexPath(item: 0, section: 0)
let cell = self.postscollectionview.cellForItem(at: path) as? UploadSubPostCell
if isThumbnailImage{
previewImage.image = image
} else {
cell?.previewStep.image = image
}
selectBtn.isHidden = false
selectStepsBtn.isHidden = false
postBtn.isHidden = false
if isThumbnailImage == false {
subpostsArray.append(image)
subposts.count + 1
print("Appended image to array:", subpostsArray)
}
}
picker.dismiss(animated: true, completion: nil)
}
#IBAction func selectStepPressed(_ sender: Any) {
picker.allowsEditing = true
picker.sourceType = .photoLibrary
isThumbnailImage = false
self.present(picker, animated: true, completion: nil)
}
#IBAction func selectPressed(_ sender: Any) {
picker.allowsEditing = true
picker.sourceType = .photoLibrary
isThumbnailImage = true
self.present(picker, animated: true, completion: nil)
}
#IBAction func addNewPressed(_ sender: Any) {
}
#IBAction func postPressed(_ sender: Any) {
AppDelegate.instance().showActivityIndicator()
let uid = Auth.auth().currentUser!.uid
let ref = Database.database().reference()
let storage = Storage.storage().reference(forURL: "gs://mobile-d9fcd.appspot.com")
let key = ref.child("posts").childByAutoId().key
let imageRef = storage.child("posts").child(uid).child("\(key).jpg")
let data = UIImageJPEGRepresentation(self.previewImage.image!, 0.6)
let uploadTask = imageRef.putData(data!, metadata: nil) { (metadata, error) in
if error != nil {
print(error!.localizedDescription)
AppDelegate.instance().dismissActivityIndicator()
return
}
imageRef.downloadURL(completion: { (url, error) in
if let url = url {
let feed = ["userID" : uid,
"pathToImage" : url.absoluteString,
"likes" : 0,
"author" : Auth.auth().currentUser!.displayName!,
"postID" : key] as [String : Any]
let postFeed = ["\(key)" : feed]
ref.child("posts").updateChildValues(postFeed)
AppDelegate.instance().dismissActivityIndicator()
self.picker.dismiss(animated: true, completion: nil)
}
})
}
uploadTask.resume()
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.posts.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "postCell", for: indexPath) as! PostCell
cell.postImage.downloadImage(from: self.posts[indexPath.row].pathToImage)
cell.authorLabel.text = self.posts[indexPath.row].author
cell.likeLabel.text = "\(self.posts[indexPath.row].likes!) Likes"
cell.postID = self.posts[indexPath.row].postID
}
}
}
In didFinishPickingMediaWithInfo, you should save the image with the dataSource, if you know what cell the image goes into, use tableView.reloadRows(at indexPaths:) to reload the cell. Add the image to cell.previewStep.image in cellForRowAt()
if you are using swift version 4.2 and above, you should be replacing:
if let image = info[UIImagePickerControllerEditedImage] as? UIImage {
by:
if let image = info[UIImagePickerController.InfoKey.editedImage] as? UIImage {
Related
PostViewController
I'm working on a social app. In which I want to upload photos from gallery to my TableViewCell by UploadButton. By programmatically I created some posts, as shown in MainScreenViewController, like facebook or instagram. But now I want to add a photo by picking up from gallery and upload to the VC.
This is my PostViewController in which I'm getting a photo from library and now I want to post it on MainScreenViewController's ViewControllersTableView.
Kindly help at this point
import UIKit
import Firebase
import FirebaseDatabase
import FirebaseStorage
class PostViewController: UIViewController {
var ref = DatabaseReference.init()
#IBOutlet weak var txtText: UITextField!
#IBOutlet weak var myImageView: UIImageView!
#IBOutlet weak var btnUpload: UIButton!
let imagePicker = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
btnUpload.designButton(borderWidth: 0, borderColor: UIColor.clear)
self.ref = Database.database().reference()
let tapGesture = UITapGestureRecognizer()
tapGesture.addTarget(self, action: #selector(PostViewController.openGallery(tapGesture:)))
myImageView.isUserInteractionEnabled = true
myImageView.addGestureRecognizer(tapGesture)
}
func saveFIRData() {
self.uploadImage(self.myImageView.image!) { url in
self.saveImage(name: self.txtText.text!, profileURL: url!) { success in
if success != nil {
print("Good")
}
}
}
}
#objc func openGallery(tapGesture: UITapGestureRecognizer) {
self.setUpImagePicker()
}
#IBAction func btnSaveClick(_ sender: UIButton) {
self.saveFIRData()
}
}
extension PostViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func setUpImagePicker() {
if UIImagePickerController.isSourceTypeAvailable(.savedPhotosAlbum) {
imagePicker.sourceType = .savedPhotosAlbum
imagePicker.delegate = self
imagePicker.isEditing = true
self.present(imagePicker, animated: true, completion: nil)
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let image = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
myImageView.image = image
self.dismiss(animated: true, completion: nil)
}
}
extension PostViewController {
func uploadImage(_ image:UIImage, completion: #escaping ((_ url: URL?) -> ())) {
let storageRef = Storage.storage().reference().child("myImage.png")
let imgData = myImageView.image?.pngData()
let metaData = StorageMetadata()
metaData.contentType = "image/png"
storageRef.putData(imgData!, metadata: metaData) { (metdata, error) in
if error == nil {
print("Success")
storageRef.downloadURL(completion: { (url, error) in
completion(url!)
})
} else {
print("error in save image")
completion(nil)
}
}
}
func saveImage(name: String, profileURL: URL, completion: #escaping ((_ url: URL?) -> ())) {
let dict = ["name": "Omer", "text": txtText.text!, "profileURL": profileURL.absoluteString] as [String: Any]
self.ref.child("chat").childByAutoId().setValue(dict)
}
}
MainScreenViewController
import UIKit
import Firebase
import FirebaseAuth
class MainScreenViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var cardTableView: UITableView!
let pictures: [UIImage] = [UIImage(named: "1")!, UIImage(named: "2")!, UIImage(named: "3")!]
let images: [UIImage] = [UIImage(named: "aa")!, UIImage(named: "ab")!, UIImage(named: "ac")!]
let titles: [String] = ["Che Guevara", "BatMan", "Information Technology"]
let descriptions: [String] = ["Ernesto Che Guevara was an Argentine Marxist revolutionary, guerrilla leader.", "Batman ventures into Gotham City's underworld.", "Information technology is defined as a broad term that includes the development."]
override func viewDidLoad() {
super.viewDidLoad()
cardTableView.delegate = self
cardTableView.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return pictures.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 400
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cardCell", for: indexPath) as! CardCell
cell.configure(picture: pictures[indexPath.row], img: images[indexPath.row], title: titles[indexPath.row], description: descriptions[indexPath.row])
return cell
}
}
CardCell
import UIKit
import Firebase
import FirebaseAuth
class CardCell: UITableViewCell {
#IBOutlet weak var cardView: UIView!
#IBOutlet weak var pictureView: UIImageView!
#IBOutlet weak var profileImage: UIImageView!
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var descriptionLabel: UILabel!
#IBOutlet weak var btnLike: UIButton!
// set up the cell
func configure(picture: UIImage, img: UIImage, title: String, description: String) {
pictureView.image = picture
profileImage.image = img
titleLabel.text = title
descriptionLabel.text = description
cardView.layer.shadowColor = UIColor.gray.cgColor
cardView.layer.shadowOffset = CGSize(width: 1.0, height: 1.0)
cardView.layer.shadowOpacity = 1.0
cardView.layer.masksToBounds = false
cardView.layer.cornerRadius = 2.0
}
#IBAction func btnLike_Click(_ sender: UIButton) {
if btnLike.tag == 0 {
btnLike.setImage(UIImage(named: "h1"), for: .normal)
btnLike.tag = 1
} else {
btnLike.setImage(UIImage(named: "h4"), for: .normal)
btnLike.tag = 0
}
}
}
I think you can use closure to pass data back to MainVC which I found it lot easier
Create a closure in PostViewController :
var uploadedImage : ((UIImage)->Void)?
Assign the uploadedImage property before the picker is dismissed
uploadedImage(myUplodedImage)?
Use the property of the closure when you initiate it on MainViewController
let vc = PostViewController(nibName : "something", bundle : nil)
vc.uploadedImage = {
// Add some action here when the PostViewController dismiss
}
navigationController.pushViewController(vc, animated : true)
Additional references :
Passing Data Between View Controllers
I have a view controller with a table. The view controller has a button that segues to another controller with 4 textfields. There is a name textfield and three others where numbers can be inputed. When a user presses add, an array is appended and the view controller is dismissed while updating the table in the previous view controller. The user is then presented a table with a new cell added. The cell has 4 labels.
I am trying to figure out how to set each label in a cell to the 4 textfields that are in the view controller that created the new cell. Here is a picture of the view controller with a cell created:
Here is the view controller when the plus button is pressed that creates the cell by updating the array:
I would like to be able to set the far left label to represent the name that is added to the array every time. The first time a person clicks the plus button, the textfields view controller will pop up and the the user can put the name in the textfield. When the add button is pressed the label on the left would show the name in the controller that appended the array. The next name that is added through the view controller will be in the cell below the previous name entered and so forth. I need to get the array to show the text properly. I originally wanted the cells to have textfields that the user could put the info in there but the cells data wasn't sending to firebase database properly.
Here is the code for the first view controller:
import UIKit
import Firebase
class ConsiderationsTestViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var tableView: UITableView!
static var numberOfPeople: [String] = []
var AddPersonCell = "AddPersonCell"
#IBOutlet weak var CompanyImage: UIImageView!
#IBOutlet weak var companyNameTextFieldConsiderations: UITextField!
#IBOutlet weak var companyDescriptionTextFieldConsiderations: UITextField!
#IBOutlet weak var startDateTextFieldConsiderations: UITextField!
#IBOutlet weak var endDateTextFieldConsiderations: UITextField!
let datePickerS = UIDatePicker()
let datePickerE = UIDatePicker()
var database: Database!
var storage: Storage!
var selectedImage: UIImage?
var ref:DatabaseReference?
var databaseHandle:DatabaseHandle = 0
let dbref = Database.database().reference()
let uid = Auth.auth().currentUser?.uid
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
self.companyNameTextFieldConsiderations.delegate = self
self.companyDescriptionTextFieldConsiderations.delegate = self
// Set the Firebase reference
ref = Database.database().reference()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(ConsiderationsTestViewController.handleSelectCompanyImageView))
CompanyImage.addGestureRecognizer(tapGesture)
CompanyImage.isUserInteractionEnabled = true
self.navigationController!.navigationBar.isTranslucent = false
navigationItem.backBarButtonItem = UIBarButtonItem(
title: "", style: .plain, target: nil, action: nil)
createDatePickerForStart()
createDatePickerForEnd()
NotificationCenter.default.addObserver(self, selector: #selector(loadList), name: NSNotification.Name(rawValue: "load"), object: nil)
}
#objc func loadList(){
//load data here
self.tableView.reloadData()
}
#objc func handleSelectCompanyImageView() {
let pickerController = UIImagePickerController()
pickerController.delegate = self
pickerController.allowsEditing = true
present(pickerController, animated: true, completion: nil)
}
#IBAction func AddPersonTapped(_ sender: Any) {
}
#IBAction func sendButtonTapped(_ sender: Any) {
let companyNameC = companyNameTextFieldConsiderations.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let companyDescriptionC = companyDescriptionTextFieldConsiderations.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let today = Date()
let formatter1 = DateFormatter()
formatter1.dateFormat = "MMM d y"
print(formatter1.string(from: today))
let todaysDate = formatter1.string(from: today)
let storageRef = Storage.storage().reference(forURL: "STORAGE URL HERE")
let imageName = companyNameTextFieldConsiderations.text!
let storageCompanyRef = storageRef.child("Company_Image_Considerations").child("\(todaysDate)").child(imageName)
let companyDescriptionTextFieldText = companyDescriptionTextFieldConsiderations.text
let dateToStart = startDateTextFieldConsiderations.text
let dateToDecide = endDateTextFieldConsiderations.text
let companyRef = Database.database().reference().child("Considerations").child("\(todaysDate)").child(imageName)
let considerationInfluencerRef = Database.database().reference().child("Considerations").child("\(todaysDate)").child(imageName).child("Users")
//let values = ["Feed_Quantity": "feedTFC", "Story_Quantity": "storyTFC", "Compensation": "compensationTFC"]
guard let imageSelected = self.CompanyImage.image else {
print ("Avatar is nil")
return
}
var dict: Dictionary<String, Any> = [
"Company Image": "",
"Company Description": companyDescriptionTextFieldText!,
"Start Date": dateToStart!,
"Decision Date": dateToDecide! ]
guard let imageData = imageSelected.jpegData(compressionQuality: 0.5) else {
return
}
let metadata = StorageMetadata()
metadata.contentType = "image/jpeg"
storageCompanyRef.putData(imageData, metadata: metadata, completion:
{ (StorageMetadata, error) in
if (error != nil) {
return
}
storageCompanyRef.downloadURL { (url, error) in
if let metadateImage = url?.absoluteString {
dict["Company Image"] = metadateImage
companyRef.updateChildValues(dict, withCompletionBlock: {
(error, ref) in
if error == nil {
print("Done")
return
}
}
)
}
}
storageRef.updateMetadata(metadata) { metadata, error in
if error != nil {
//Uh-oh, an error occurred!
} else {
// Updated metadata for 'images/forest.jpg' is returned
}
}
})
// considerationInfluencerRef.updateChildValues(values as [AnyHashable : Any]) { (error, ref) in
// if error != nil {
// print(error ?? "")
// return
// }
self.navigationController?.popViewController(animated: true)
// }
}
func createDatePickerForStart() {
// center text in field
startDateTextFieldConsiderations.textAlignment = .center
// toolbar
let toolbar = UIToolbar()
toolbar.sizeToFit()
// barbutton
let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: nil, action: #selector(donePressedStart))
toolbar.setItems([doneButton], animated: true)
// assign toolbar to textfield
startDateTextFieldConsiderations.inputAccessoryView = toolbar
// assign datePicker to text field
startDateTextFieldConsiderations.inputView = datePickerS
// date picker mode
datePickerS.datePickerMode = .date
}
func createDatePickerForEnd() {
// center text in field
endDateTextFieldConsiderations.textAlignment = .center
// toolbar
let toolbar = UIToolbar()
toolbar.sizeToFit()
// barbutton
let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: nil, action: #selector(donePressedEnd))
toolbar.setItems([doneButton], animated: true)
// assign toolbar to textfield
endDateTextFieldConsiderations.inputAccessoryView = toolbar
// assign datePicker to text field
endDateTextFieldConsiderations.inputView = datePickerE
// date picker mode
datePickerE.datePickerMode = .dateAndTime
}
#objc func donePressedStart() {
// formatter
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .none
startDateTextFieldConsiderations.text = formatter.string(from: datePickerS.date)
self.view.endEditing(true)
}
#objc func donePressedEnd() {
// formatter
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .medium
endDateTextFieldConsiderations.text = formatter.string(from: datePickerE.date)
self.view.endEditing(true)
}
#IBAction func testTapped(_ sender: Any) {
print(ConsiderationsTestViewController.numberOfPeople)
}
}
extension ConsiderationsTestViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
//print("did Finish Picking Media")
if let image = info[UIImagePickerController.InfoKey(rawValue: "UIImagePickerControllerEditedImage")] as? UIImage{
selectedImage = image
CompanyImage.image = image
}
dismiss(animated: true, completion: nil)
}
}
extension ConsiderationsTestViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return ConsiderationsTestViewController.numberOfPeople.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: AddPersonCell, for: indexPath) as! ConsiderationsCell
return cell
}
}
Here is the code for the second view controller:
import UIKit
import Firebase
class DropDownCellViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate, UITextFieldDelegate {
var numberOfPeople = [String]()
var users = [User]()
var userName = [String]()
var filteredNames: [String]!
let dropDownCell = "dropDownCell"
var emptyField = [String]()
override func viewDidLoad() {
super.viewDidLoad()
updateDataArray()
tableView.register(UserCell.self, forCellReuseIdentifier: dropDownCell)
filteredNames = userName
tableView.delegate = self
tableView.dataSource = self
nameTextField.delegate = self
tableView.isHidden = true
// Manage tableView visibility via TouchDown in textField
nameTextField.addTarget(self, action: #selector(textFieldActive), for: UIControl.Event.touchDown)
}
#IBOutlet weak var nameTextField: NoCopyPasteUITextField!
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var gridTextField: UITextField!
#IBOutlet weak var storyTextField: UITextField!
#IBOutlet weak var compensationTextField: UITextField!
#IBAction func textFieldChanged(_ sender: AnyObject) {
tableView.isHidden = true
}
#IBAction func cancelButtonTapped(_ sender: Any) {
self.navigationController?.popViewController(animated: true)
}
#IBAction func addButtonTapped(_ sender: Any) {
ConsiderationsTestViewController.numberOfPeople.append("\(nameTextField.text!)")
self.navigationController?.popViewController(animated: true)
print(ConsiderationsTestViewController.numberOfPeople)
DispatchQueue.main.async {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "load"), object: nil)
}
}
let searchController = UISearchController(searchResultsController: nil)
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
{
guard let touch:UITouch = touches.first else
{
return;
}
if touch.view != tableView
{
nameTextField.endEditing(true)
tableView.isHidden = true
}
}
#objc func textFieldActive() {
tableView.isHidden = !tableView.isHidden
}
// MARK: UITextFieldDelegate
func textFieldDidEndEditing(_ textField: UITextField) {
// TODO: Your app can do something when textField finishes editing
print("The textField ended editing. Do something based on app requirements.")
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return filteredNames.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: dropDownCell, for: indexPath) as!
UserCell
let user = users[indexPath.row]
cell.textLabel?.text = user.name
if let profileImageUrl = user.profileImageUrl {
cell.profileImageView.loadImageUsingCacheWithUrlString(urlString: profileImageUrl)
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 72
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Row selected, so set textField to relevant value, hide tableView
// endEditing can trigger some other action according to requirements
nameTextField.text = userName[indexPath.row]
tableView.isHidden = true
nameTextField.endEditing(true)
}
//Mark: Search Bar Config
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filteredNames = []
if searchText == "" {
filteredNames = userName
}
else {
for names in userName {
if names.lowercased().contains(searchText.lowercased()) {
filteredNames.append(names)
}
}
}
self.tableView.reloadData()
}
func updateDataArray() {
Database.database().reference().child("users").observe(.childAdded, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = User()
//self.setValuesForKeys(dictionary)
user.name = dictionary["name"] as? String
user.email = dictionary["email"] as? String
user.facebookUrl = dictionary["facebookUrl"] as? String
user.instagramUrl = dictionary["instagramUrl"] as? String
user.linkedInUrl = dictionary["linkedInUrl"] as? String
user.profileImageUrl = dictionary["profileImageUrl"] as? String
user.twitterUrl = dictionary["twitterUrl"] as? String
user.id = dictionary["id"] as? String
user.userType = dictionary["userType"] as? String
self.users.append(user)
self.userName.append(user.name!)
self.filteredNames.append(user.name!)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}, withCancel: nil)
}
}
I am trying to append the label with a function that is called in the addButton function called renameLabel. Here is the func rename label code:
func renameLabel() {
let cell = ConsiderationsTestViewController.init().tableView.dequeueReusableCell(withIdentifier: AddPersonCell) as! ConsiderationsCell
cell.nameLabelC.text = ("\(ConsiderationsTestViewController.numberOfPeople)")
}
I am now getting the error:
Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
Any help would be awesome!
First of all create a protocol above second VC.
protocol UpdatingArrayDelegate: class {
func updateArray(newArray: [String])
}
And inside the second VC create:
var updatingArrayDelegate: UpdatingArrayDelegate!
Then before pushing to the second VC, set the delegate to self:
#objc func pushToSecondVCButtonTapped() {
let destVC = secondVC()
updatingArrayDelegate = self
self.navigationController?.pushViewController(destVC, animated: true)
// if you don't have self.navigationController use:
// present(destVC(), animated: true, completion: nil)
}
Now when finishing the edit on secondVC when pressing your addButton do the following:
#objc func doneButtonTapped() {
updatingArrayDelegate?.updateArray(newArray: myNewArrayCreatedOnThisSecondVC)
self.navigationController?.popViewController(animated: true)
}
Then add the delegate function on first
extension FirstVC: UpdatingArrayDelegate {
func updateArray(newArray: [String]) {
print("updateArray")
let myCell = myTableView.cellForRow(at: IndexPath(row: x, section: y)) as! MyCell
myCell.textLabel1.text = newArray[0]
myCell.textLabel2.text = newArray[1]
myCell.textLabel3.text = newArray[2]
myCell.textLabel4.text = newArray[3]
}
}
You can think about delegate like this:
The boss (secondVC) gives a the worker (firstVC) a protocol of what to do. The Worker reads the protocol and is doing the work with his function given in the protocol. Before the worker runs to the boss, he must be sure that he can do the next task (written on the protocol he is going to have.)
building my first iOS app here and I am stuck. I searched online and did not find anything about this particular issue.
Basically I have a UICollectionView displaying some data. Everything works fine on the simulator, but on the actual iPhone, it's like the UICollectionView is just not there.
No error messages and the app doesn't crash, and all the other elements of the App are functioning properly so I am quite perplexed.
Code:
//
// SecondViewController.swift
//
// Created by pc on 3/5/19.
// Copyright © 2019 BF. All rights reserved.
//
import UIKit
import WebKit
import SwiftSoup
class SecondViewController: UIViewController, WKNavigationDelegate, UICollectionViewDataSource {
#IBOutlet var dataTable: UICollectionView!
#IBOutlet weak var viewHeader: UILabel!
#IBOutlet weak var viewFooter: UILabel!
#IBAction func backButtonClicked(_ sender: UIButton) {
dismissVC()
}
var webView: WKWebView!
var tableContent = [[String]]()
var vSpinner : UIView?
var testString = [[String]]()
var submittedValue2: String = ""
var currentSelection2: String = ""
override func viewDidAppear(_ animated: Bool) {
let alert = UIAlertController(title: nil, message: "Please wait...", preferredStyle: .alert)
let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50))
loadingIndicator.hidesWhenStopped = true
loadingIndicator.style = UIActivityIndicatorView.Style.gray
loadingIndicator.startAnimating();
alert.view.addSubview(loadingIndicator)
present(alert, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
self.dataTable.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
//dataTable.backgroundColor = UIColor.white
dataTable.delegate = self as? UICollectionViewDelegate
dataTable.dataSource = self
if let layout = dataTable.collectionViewLayout as? UICollectionViewFlowLayout {
layout.scrollDirection = .horizontal
}
webView = WKWebView()
webView.navigationDelegate = self
//view = webView
let url = URL(string: "https://someWebsite.com")!
webView.load(URLRequest(url: url))
webView.allowsBackForwardNavigationGestures = true
runData()
}
///////ADDS DELAY
func runData() {
DispatchQueue.main.asyncAfter(deadline: .now() + 4) { // Change `2.0` to the desired number of seconds.
self.setWebViewValue(name: "txtValue", data: self.submittedValue2, vin: self.currentSelection2)
}
}
///////// PULLS DATA
func setWebViewValue(name: String, data: String, vin: String) {
if vin == "VIN:" {
webView.evaluateJavaScript("document.getElementById('rbRequest_1').click()", completionHandler: nil)
}
else {
}
webView.evaluateJavaScript("document.getElementById(\"\(name)\").value = \"\(data)\"", completionHandler: nil)
webView.evaluateJavaScript("document.getElementById('btnSubmit').click()", completionHandler: nil)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { // Change `2.0` to the desired number of seconds.
self.webView.evaluateJavaScript("document.documentElement.outerHTML.toString()") { (result, error) -> Void in
if error != nil {
print(error!)
}
let document = try! SwiftSoup.parse(result as! String)
for row in try! document.select("table[id=\"gvTests\"] tr") {
var rowContent = [String]()
for col in try! row.select("td") {
let colContent = try! col.text()
rowContent.append(colContent)
}
self.tableContent.append(rowContent)
}
if self.tableContent.isEmpty == false {
//self.tableContent.remove(at: 0)
self.tableContent[0] = ["Make","Model","Year","Date","Pass/Fail","Certificate","Referee"]
}
print(self.tableContent)
self.tableContent = self.transpose(input: self.tableContent)
if self.tableContent.isEmpty == false {
self.dataTable.reloadData()
}
}
self.dismiss(animated: false, completion: nil)
}
}
////// Collection View functions
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if tableContent.isEmpty == false {
return tableContent[0].count
}
else {
return 0
}
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
if tableContent.isEmpty == false {
return tableContent.count
}
else {
return 0
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
let title = UILabel(frame: CGRect(x: 0,y: 0,width: cell.bounds.size.width,height: cell.bounds.size.height))
for subview in cell.contentView.subviews {
subview.removeFromSuperview()
}
cell.contentView.addSubview(title)
title.text = tableContent[indexPath.section][indexPath.item]
//title.textColor = UIColor.black
title.layer.borderWidth = 1
title.layer.borderColor = UIColor.black.cgColor
title.textAlignment = NSTextAlignment.center
return cell
}
public func transpose<T>(input: [[T]]) -> [[T]] {
if input.isEmpty { return [[T]]() }
let count = input[0].count
var out = [[T]](repeating: [T](), count: count)
for outer in input {
for (index, inner) in outer.enumerated() {
out[index].append(inner)
}
}
return out
}
func dismissVC() {
dismiss(animated: true, completion: nil)
}
}
This might cause from constraint on your collectionView.
Turns out the issue is not with the UIcollectionview, but that the data is empty because instead of being extracted from the website like it is when ran in the simulator. I will post another question for that. Thanks all.
Working on an app where I store data on Firebase and load the data into my TableView. Had to change the (old) code a little from a tutorial i found so I hope someone can spot the mistake i made. The user can add an event with a: name, date, description (all strings) and Image. This data is loaded into the TableView onto three "labels" and and image on top.
import UIKit
import Firebase
import FirebaseDatabaseUI
class EventViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
//outlets for text & image
#IBOutlet weak var photoImageView: UIImageView!
#IBOutlet weak var eventName: UITextField!
#IBOutlet weak var eventDate: UITextField!
#IBOutlet weak var eventDes: UITextView!
//Database connection
let rootref = FIRDatabase().reference()
var imagePicker: UIImagePickerController = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func submitEvent(sender: AnyObject) {
let name = eventName.text
let date = eventDate.text
let text = eventDes.text
var data: NSData = NSData()
if let image = photoImageView.image {
data = UIImageJPEGRepresentation(image,0.1)!
}
let base64String = data.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
let user: NSDictionary = ["name":name!, "date":date!, "text":text!, "photoBase64":base64String]
//Add firebase child node
let event = FIRDatabase().reference().child(name!)
// Write data to Firebase
event.setValue(user)
navigationController?.popViewControllerAnimated(true)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
view.endEditing(true)
super.touchesBegan(touches, withEvent: event)
}
//UIImagePickerControllerDelegate methods
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
imagePicker.dismissViewControllerAnimated(true, completion: nil)
photoImageView.image = info[UIImagePickerControllerOriginalImage] as? UIImage
}
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
dismissViewControllerAnimated(true, completion: nil)
}
#IBAction func addPicture(sender: AnyObject) {
if(UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera)) {
imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .Camera
presentViewController(imagePicker, animated: true, completion: nil)
} else {
imagePicker.allowsEditing = false
imagePicker.sourceType = .PhotoLibrary
imagePicker.delegate = self
presentViewController(imagePicker, animated: true, completion:nil)
}
}
}
My TABLEVIEWCONTROLLER
import UIKit
import Firebase
class EventTableViewController: UITableViewController {
#IBOutlet weak var eventImage: UIImageView!
#IBOutlet weak var eventName: UILabel!
#IBOutlet weak var eventDate: UILabel!
#IBOutlet weak var eventText: UITextView!
let rootref = FIRDatabase().reference()
var items = [NSDictionary]()
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
items = [NSDictionary]()
FIRDatabase.load()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
//TableView Data
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
configureCell(cell, indexPath: indexPath)
return cell
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
let dict = items[indexPath.row]
let name = dict["name"] as! String
// delete data from firebase
let event = FIRDatabase().reference().child(name)
event.removeValue()
}
}
// MARK:- Configure Cell
func configureCell(cell: UITableViewCell, indexPath: NSIndexPath) {
let dict = items[indexPath.row]
eventName.text = dict["name"] as? String
eventDate.text = dict["name"] as? String
eventText.text = dict["name"] as? String
let base64String = dict["photoBase64"] as! String
populateImage(cell, imageString: base64String)
}
func populateImage(cell:UITableViewCell, imageString: String) {
let decodedData = NSData(base64EncodedString: imageString, options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)
let decodedImage = UIImage(data: decodedData!)
cell.imageView!.image = decodedImage
}
//load data from Firebase
func loadDataFromFirebase() {
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
rootref.observeEventType(.Value, withBlock: { snapshot in
var tempItems = [NSDictionary]()
for item in snapshot.children {
let child = item as! FIRDataSnapshot
let dict = child.value as! NSDictionary
tempItems.append(dict)
}
self.items = tempItems
self.tableView.reloadData()
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
})
}
}
IMAGE TO GET AN IDEA OF MY WORK
My app so far
Look at this line:
let user: NSDictionary = ["name":name!, "date":date!, "text":text!, "photoBase64":base64String]
You are doing a lot of forced unwrapping here. In fact, you do a lot of forced unwrapping in several places. When you do this you are saying "I am 100% sure there will ALWAYS be a value here". Avoid this a nearly all costs. That line should look like this.
if let unwrappedName = name , unwrappedDate = date, unwrappedText = text{
let user: NSDictionary = ["name":unwrappedName, "date":unwrappedDate, "text":unwrappedText, "photoBase64":base64String]
}
Unwrapping optionals like this will keep your app from crashing. You should put a breakpoint here to see what value is nil. Every time you use a ! you should think VERY carefully about about it.
I believe the error is where you set up your database connection.
You have: let rootref = FIRDatabase().reference()
It should be:let rootref = FIRDatabase().database().reference()
I was getting the same error and this fixed it for me.
This code is simple:
import UIKit
import CoreData
class PhotoList: UIViewController, UITableViewDelegate, UITableViewDataSource, sendDetailsDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBOutlet var tableView: UITableView!
var whoTookArray: [String] = []
var imageArray: [UIImage] = []
func sendDetails (name: String, photo: UIImage) {
whoTookArray.append(name)
imageArray.append(photo)
tableView!.reloadData()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return whoTookArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: nil)
let row = indexPath.row
let whoTookName = whoTookArray[row]
let image = imageArray[row]
cell.textLabel?.text = whoTookName
cell.imageView!.image = image
return cell
}
}
and
import UIKit
import CoreData
protocol sendDetailsDelegate {
func sendDetails(name: String, photo: UIImage)
}
class Details: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let tapGestureRecognizer: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "chooseImage:")
tapGestureRecognizer.numberOfTapsRequired = 1
imageSelected.addGestureRecognizer(tapGestureRecognizer)
imageSelected.userInteractionEnabled = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBOutlet var whoTookTextField: UITextField!
#IBOutlet var imageSelected: UIImageView!
var delegate: sendDetailsDelegate?
//Pick the image by tapping, accessing the PhotoLibrary
func chooseImage(recognizer: UITapGestureRecognizer) {
let imagePicker: UIImagePickerController = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
self.presentViewController(imagePicker, animated: true, completion: nil)
}
//Put the selected image into the screen
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
let pickedImage: UIImage = (info as NSDictionary).objectForKey(UIImagePickerControllerOriginalImage) as! UIImage
let smallPicture = scaleImageWith(pickedImage, newSize: CGSizeMake(288,148))
var sizeOfImageView: CGRect = imageSelected.frame
sizeOfImageView.size = smallPicture.size
imageSelected.frame = sizeOfImageView
imageSelected.image = smallPicture
picker.dismissViewControllerAnimated(true, completion: nil)
}
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
picker.dismissViewControllerAnimated(true, completion: nil)
}
func scaleImageWith(image: UIImage, newSize: CGSize) -> UIImage {
UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
image.drawInRect(CGRectMake(0,0, newSize.width, newSize.height))
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
#IBAction func addButton(sender: AnyObject) {
if whoTookTextField == nil || imageSelected == nil { return }
if imageSelected == nil { return }
let whoTook = whoTookTextField.text
let image = imageSelected.image
println("\(delegate)")
delegate!.sendDetails(whoTook, photo: image!)
println("whoTook: \(whoTook) image: \(image)")
if let navigation = self.navigationController {
navigation.popViewControllerAnimated(true)
}
}
}
I'm delegating a text and an image to the PhotoList view controller, but it crashes in the delegate line here:
delegate!.sendDetails(whoTook, photo: image!)
The print line says it's nil. Does anyone know why? Thanks!
EDIT
Solved!
add this code:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "toPhotoList") {
let view = segue.destinationViewController as! Details
view.delegate = self
}
}
And all your trouble is gone! Tableview updated successfully!
Thanks for the help!!