config UI in background thread then assign back to mainthread - ios

Hi I'm a new swift developer and I'm trying to find a way to load all of my textfields in the background thread then make it go back to the mainthread before a viewcontroller appear.
Because in my viewcontroller I have like almost 20 textfield that need to setup like its style, placeholders and etc.. So it takes quite a while for the viewcontroller to appear when I tapped on the button that handle segue to that vc.
I know that I can use this to do the setup textfields in the background
DispatchQueue.global(qos: .userInteractive).async {
<#code#>
}
however I dont know where to put this code. I tried to put it in the viewDidLoad but that doesnt seem to work.
EDIT: ADD IN MY CODE
import UIKit
import MaterialComponents.MaterialTextFields
class AddNewDataVC: UIViewController {
//Outlet
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var saveNewDataBtn: UIButton!
#IBOutlet weak var sowInfoInputsStackView: UIStackView!
#IBOutlet weak var giltInfoInputsStackView: UIStackView!
#IBOutlet weak var matingInfoInputsStackView: UIStackView!
#IBOutlet weak var farrowInfoInputsStackView: UIStackView!
#IBOutlet weak var vaccinTable: UITableView!
#IBOutlet weak var pigTypeTextField: PickerTextField!
#IBOutlet weak var genderTextField: PickerTextField!
#IBOutlet weak var chipIDTextField: MDCTextField!
#IBOutlet weak var breedTextField: MDCTextField!
#IBOutlet weak var subBreedTextField: MDCTextField!
#IBOutlet weak var dadIDTextField: MDCTextField!
#IBOutlet weak var momIDTextField: MDCTextField!
#IBOutlet weak var penIDTextField: MDCTextField!
#IBOutlet weak var weightTextField: MDCTextField!
#IBOutlet weak var parityTextField: MDCTextField!
#IBOutlet weak var birthDateTextField: PickerTextField!
#IBOutlet weak var weanDateTextField: PickerTextField!
#IBOutlet weak var arrivalDateTextField: PickerTextField!
#IBOutlet weak var herdEntryDateTextField: PickerTextField!
#IBOutlet weak var startOffDutySowDateTextField: PickerTextField!
#IBOutlet weak var semenFromBoarIDTextField: MDCTextField!
#IBOutlet weak var technicianNameTextField: PickerTextField!
#IBOutlet weak var matingDateTextField: PickerTextField!
#IBOutlet weak var estimateBirthDateTextField: PickerTextField!
#IBOutlet weak var realBirthDateTextField: PickerTextField!
#IBOutlet weak var totalNumberOfNewBornsTextField: MDCTextField!
#IBOutlet weak var totalNumberOfDeadNewBornsTextField: MDCTextField!
#IBOutlet weak var averageWeightOfNewBornsTextField: MDCTextField!
#IBOutlet weak var accoucheurNameTextField: MDCTextField!
#IBOutlet weak var newBornDeathReason1TextField: MDCTextField!
#IBOutlet weak var newBornDeathReason2TextField: MDCTextField!
#IBOutlet weak var newBornDeathReason3TextField: MDCTextField!
#IBOutlet weak var newBornCullReason1TextField: MDCTextField!
#IBOutlet weak var newBornCullReason2TextField: MDCTextField!
#IBOutlet weak var newBornCullReason3TextField: MDCTextField!
//Properties
var pigTypeController: MDCTextInputControllerUnderline?
var genderController: MDCTextInputControllerUnderline?
var chipIDController: MDCTextInputControllerUnderline?
var breedController: MDCTextInputControllerUnderline?
var subBreedController: MDCTextInputControllerUnderline?
var dadIDController: MDCTextInputControllerUnderline?
var momIDController: MDCTextInputControllerUnderline?
var penIDController: MDCTextInputControllerUnderline?
var weightController: MDCTextInputControllerUnderline?
var parityController: MDCTextInputControllerUnderline?
var birthDateController: MDCTextInputControllerUnderline?
var weanDateController: MDCTextInputControllerUnderline?
var arrivalDateController: MDCTextInputControllerUnderline?
var herdEntryDateController: MDCTextInputControllerUnderline?
var startOffDutySowDateController: MDCTextInputControllerUnderline?
var semenFromBoarIDController: MDCTextInputControllerUnderline?
var techicianNameController: MDCTextInputControllerUnderline?
var matingDateController: MDCTextInputControllerUnderline?
var estimateBirthDateController: MDCTextInputControllerUnderline?
var realBirthDateController: MDCTextInputControllerUnderline?
var totalNumberOfNewBornsController: MDCTextInputControllerUnderline?
var totalNumberOfDeadNewBornsController: MDCTextInputControllerUnderline?
var averageWeightOfNewBornsController: MDCTextInputControllerUnderline?
var accoucheurNameController: MDCTextInputControllerUnderline?
var newBornDeathReason1Controller: MDCTextInputControllerUnderline?
var newBornDeathReason2Controller: MDCTextInputControllerUnderline?
var newBornDeathReason3Controller: MDCTextInputControllerUnderline?
var newBornCullReason1Controller: MDCTextInputControllerUnderline?
var newBornCullReason2Controller: MDCTextInputControllerUnderline?
var newBornCullReason3Controller: MDCTextInputControllerUnderline?
var allTextFieldControllers = [MDCTextInputControllerUnderline]()
var injectedVaccinArray = [[String : Any]]()
override func viewDidLoad() {
super.viewDidLoad()
setupTextFields()
registerKeyboardNotifications()
addGestureRecognizer()
vaccinTable.dataSource = self
vaccinTable.delegate = self
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
NotificationCenter.default.removeObserver(self)
}
#IBAction func closeAddNewDataPopupBtnPressed(_ sender: UIButton) {
dismiss(animated: true, completion: nil)
}
#IBAction func saveNewDataBtnPressed(_ sender: Any) {
}
#IBAction func addVaccinDataBtnPressed(_ sender: UIButton) {
let getDestStoryboard = UIStoryboard(name: "AddNewData", bundle: nil)
let popupVC = getDestStoryboard.instantiateViewController(withIdentifier: "addVaccinDataVC") as! AddVaccinInfoVC
popupVC.popupDelegate = self
self.present(popupVC, animated: true, completion: nil)
}
}
extension AddNewDataVC {
func setupTextFields() {
pigTypeController = MDCTextInputControllerUnderline(textInput: pigTypeTextField)
pigTypeTextField.delegate = self
pigTypeTextField.addData(data: PIG_TYPES_ENUM.allValues)
pigTypeController?.placeholderText = "Loại lợn"
allTextFieldControllers.append(pigTypeController!)
genderController = MDCTextInputControllerUnderline(textInput: genderTextField)
genderTextField.delegate = self
genderTextField.addData(data: GENDERS)
genderController?.placeholderText = "Giới tính"
allTextFieldControllers.append(genderController!)
chipIDController = MDCTextInputControllerUnderline(textInput: chipIDTextField)
chipIDTextField.delegate = self
chipIDController?.placeholderText = "Số chip"
allTextFieldControllers.append(chipIDController!)
breedController = MDCTextInputControllerUnderline(textInput: breedTextField)
breedTextField.delegate = self
breedController?.placeholderText = "Giống"
allTextFieldControllers.append(breedController!)
subBreedController = MDCTextInputControllerUnderline(textInput: subBreedTextField)
subBreedTextField.delegate = self
subBreedController?.placeholderText = "Giống phụ"
allTextFieldControllers.append(subBreedController!)
dadIDController = MDCTextInputControllerUnderline(textInput: dadIDTextField)
dadIDTextField.delegate = self
dadIDController?.placeholderText = "Số chip bố mẹ"
allTextFieldControllers.append(dadIDController!)
momIDController = MDCTextInputControllerUnderline(textInput: momIDTextField)
momIDTextField.delegate = self
momIDController?.placeholderText = "Số chip mẹ"
allTextFieldControllers.append(momIDController!)
penIDController = MDCTextInputControllerUnderline(textInput: penIDTextField)
penIDTextField.delegate = self
penIDController?.placeholderText = "Số chuồng"
allTextFieldControllers.append(penIDController!)
weightController = MDCTextInputControllerUnderline(textInput: weightTextField)
weightTextField.delegate = self
weightController?.placeholderText = "Số kg"
allTextFieldControllers.append(weightController!)
parityController = MDCTextInputControllerUnderline(textInput: parityTextField)
parityTextField.delegate = self
parityController?.placeholderText = "Số lứa"
allTextFieldControllers.append(parityController!)
birthDateController = MDCTextInputControllerUnderline(textInput: birthDateTextField)
birthDateTextField.delegate = self
birthDateController?.placeholderText = "Ngày sinh"
allTextFieldControllers.append(birthDateController!)
weanDateController = MDCTextInputControllerUnderline(textInput: weanDateTextField)
weanDateTextField.delegate = self
weanDateController?.placeholderText = "Ngày cai sữa"
allTextFieldControllers.append(weanDateController!)
arrivalDateController = MDCTextInputControllerUnderline(textInput: arrivalDateTextField)
arrivalDateTextField.delegate = self
arrivalDateController?.placeholderText = "Ngày đến"
allTextFieldControllers.append(arrivalDateController!)
herdEntryDateController = MDCTextInputControllerUnderline(textInput: herdEntryDateTextField)
herdEntryDateTextField.delegate = self
herdEntryDateController?.placeholderText = "Ngày nhập đàn"
allTextFieldControllers.append(herdEntryDateController!)
startOffDutySowDateController = MDCTextInputControllerUnderline(textInput: startOffDutySowDateTextField)
startOffDutySowDateTextField.delegate = self
startOffDutySowDateController?.placeholderText = "Ngày nái nghỉ"
allTextFieldControllers.append(startOffDutySowDateController!)
semenFromBoarIDController = MDCTextInputControllerUnderline(textInput: semenFromBoarIDTextField)
semenFromBoarIDTextField.delegate = self
semenFromBoarIDController?.placeholderText = "Mã heo nọc"
allTextFieldControllers.append(semenFromBoarIDController!)
techicianNameController = MDCTextInputControllerUnderline(textInput: technicianNameTextField)
technicianNameTextField.delegate = self
techicianNameController?.placeholderText = "Người phối"
technicianNameTextField.addData(data: TECHNICIAN_NAMES)
allTextFieldControllers.append(techicianNameController!)
matingDateController = MDCTextInputControllerUnderline(textInput: matingDateTextField)
matingDateTextField.delegate = self
matingDateController?.placeholderText = "Ngày phối"
allTextFieldControllers.append(matingDateController!)
estimateBirthDateController = MDCTextInputControllerUnderline(textInput: estimateBirthDateTextField)
estimateBirthDateTextField.delegate = self
estimateBirthDateController?.placeholderText = "Ngày đẻ dự kiến"
allTextFieldControllers.append(estimateBirthDateController!)
realBirthDateController = MDCTextInputControllerUnderline(textInput: realBirthDateTextField)
realBirthDateTextField.delegate = self
realBirthDateController?.placeholderText = "Ngày đẻ thực tế"
allTextFieldControllers.append(realBirthDateController!)
totalNumberOfNewBornsController = MDCTextInputControllerUnderline(textInput: totalNumberOfNewBornsTextField)
totalNumberOfNewBornsTextField.delegate = self
totalNumberOfNewBornsController?.placeholderText = "Tổng heo con sinh"
allTextFieldControllers.append(totalNumberOfNewBornsController!)
totalNumberOfDeadNewBornsController = MDCTextInputControllerUnderline(textInput: totalNumberOfDeadNewBornsTextField)
totalNumberOfDeadNewBornsTextField.delegate = self
totalNumberOfDeadNewBornsController?.placeholderText = "Tổng heo con chết"
allTextFieldControllers.append(totalNumberOfDeadNewBornsController!)
averageWeightOfNewBornsController = MDCTextInputControllerUnderline(textInput: averageWeightOfNewBornsTextField)
averageWeightOfNewBornsTextField.delegate = self
averageWeightOfNewBornsController?.placeholderText = "Kg trung bình"
allTextFieldControllers.append(averageWeightOfNewBornsController!)
accoucheurNameController = MDCTextInputControllerUnderline(textInput: accoucheurNameTextField)
accoucheurNameTextField.delegate = self
accoucheurNameController?.placeholderText = "Người đỡ đẻ"
allTextFieldControllers.append(accoucheurNameController!)
newBornDeathReason1Controller = MDCTextInputControllerUnderline(textInput: newBornDeathReason1TextField)
newBornDeathReason1TextField.delegate = self
newBornDeathReason1Controller?.placeholderText = "Chết khô"
allTextFieldControllers.append(newBornDeathReason1Controller!)
newBornDeathReason2Controller = MDCTextInputControllerUnderline(textInput: newBornDeathReason2TextField)
newBornDeathReason2TextField.delegate = self
newBornDeathReason2Controller?.placeholderText = "Chết lưu"
allTextFieldControllers.append(newBornDeathReason2Controller!)
newBornDeathReason3Controller = MDCTextInputControllerUnderline(textInput: newBornDeathReason3TextField)
newBornDeathReason3TextField.delegate = self
newBornDeathReason3Controller?.placeholderText = "Chết tươi"
allTextFieldControllers.append(newBornDeathReason3Controller!)
newBornCullReason1Controller = MDCTextInputControllerUnderline(textInput: newBornCullReason1TextField)
newBornCullReason1TextField.delegate = self
newBornCullReason1Controller?.placeholderText = "Loại nhỏ"
allTextFieldControllers.append(newBornCullReason1Controller!)
newBornCullReason2Controller = MDCTextInputControllerUnderline(textInput: newBornCullReason2TextField)
newBornCullReason2TextField.delegate = self
newBornCullReason2Controller?.placeholderText = "Loại yếu"
allTextFieldControllers.append(newBornCullReason2Controller!)
newBornCullReason3Controller = MDCTextInputControllerUnderline(textInput: newBornCullReason3TextField)
newBornCullReason3TextField.delegate = self
newBornCullReason3Controller?.placeholderText = "Loại nhỏ"
allTextFieldControllers.append(newBornCullReason3Controller!)
for controller in allTextFieldControllers {
controller.activeColor = Theme.darkAccent
controller.floatingPlaceholderActiveColor = Theme.darkAccent
}
}
func addGestureRecognizer() {
let tapRecognizer = UITapGestureRecognizer(target: self,
action: #selector(tapDidTouch(sender: )))
self.scrollView.addGestureRecognizer(tapRecognizer)
}
#objc func tapDidTouch(sender: Any) {
self.view.endEditing(true)
}
func registerKeyboardNotifications() {
let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(
self,
selector: #selector(keyboardWillShow(notif:)),
name: .UIKeyboardWillChangeFrame,
object: nil)
notificationCenter.addObserver(
self,
selector: #selector(keyboardWillShow(notif:)),
name: .UIKeyboardWillShow,
object: nil)
notificationCenter.addObserver(
self,
selector: #selector(keyboardWillHide(notif:)),
name: .UIKeyboardWillHide,
object: nil)
}
#objc func keyboardWillShow(notif: Notification) {
guard let frame = notif.userInfo?[UIKeyboardFrameEndUserInfoKey] as? CGRect else {
return
}
scrollView.contentInset = UIEdgeInsets(top: 0.0,
left: 0.0,
bottom: frame.height,
right: 0.0)
}
#objc func keyboardWillHide(notif: Notification) {
scrollView.contentInset = UIEdgeInsets()
}
func toggleFarrowInfoInputsStackView(toggle: Bool) {
if toggle {
sowInfoInputsStackView.isHidden = false
} else {
sowInfoInputsStackView.isHidden = true
}
}
func toggleGiltInputs(toggle: Bool) {
if toggle {
giltInfoInputsStackView.isHidden = false
} else {
giltInfoInputsStackView.isHidden = true
}
}
func toggleOffDutySowInputs(toggle: Bool) {
if toggle {
startOffDutySowDateTextField.isHidden = false
} else {
startOffDutySowDateTextField.isHidden = true
}
}
func toggleMatingInputs(toggle: Bool) {
if toggle {
matingInfoInputsStackView.isHidden = false
} else {
matingInfoInputsStackView.isHidden = true
}
}
func toggleFarrowInputs(toggle: Bool) {
if toggle {
farrowInfoInputsStackView.isHidden = false
} else {
farrowInfoInputsStackView.isHidden = true
}
}
func toggleParityTextField(toggle: Bool) {
if toggle {
parityTextField.isHidden = false
} else {
parityTextField.isHidden = true
}
}
}
extension AddNewDataVC: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return false
}
func textFieldDidEndEditing(_ textField: UITextField) {
if let textField = textField as? PickerTextField {
let text = textField.text?.lowercased()
if !textField.isDatePicker && textField == pigTypeTextField {
if text!.contains("nái") || textField.text! == PIG_TYPES_ENUM.gilt.rawValue {
toggleFarrowInfoInputsStackView(toggle: true)
if textField.text! == PIG_TYPES_ENUM.gilt.rawValue {
toggleGiltInputs(toggle: true)
toggleOffDutySowInputs(toggle: false)
toggleMatingInputs(toggle: false)
toggleFarrowInputs(toggle: false)
} else if textField.text! == PIG_TYPES_ENUM.offDutySow.rawValue {
toggleGiltInputs(toggle: true)
toggleOffDutySowInputs(toggle: true)
toggleMatingInputs(toggle: false)
toggleFarrowInputs(toggle: false)
} else if textField.text! == PIG_TYPES_ENUM.matingSow.rawValue {
toggleGiltInputs(toggle: true)
toggleOffDutySowInputs(toggle: false)
toggleMatingInputs(toggle: true)
toggleFarrowInputs(toggle: false)
} else if textField.text! == PIG_TYPES_ENUM.farrow.rawValue {
toggleGiltInputs(toggle: true)
toggleOffDutySowInputs(toggle: false)
toggleMatingInputs(toggle: true)
toggleFarrowInputs(toggle: true)
}
} else {
toggleFarrowInfoInputsStackView(toggle: false)
toggleGiltInputs(toggle: false)
toggleOffDutySowInputs(toggle: false)
toggleMatingInputs(toggle: false)
toggleFarrowInputs(toggle: false)
if textField.text! == PIG_TYPES_ENUM.boar.rawValue {
genderTextField.text = "Đực"
genderTextField.isUserInteractionEnabled = false
} else {
genderTextField.text = ""
genderTextField.isUserInteractionEnabled = true
}
}
} else if !textField.isDatePicker && textField == genderTextField {
if textField.text == "Cái" {
toggleParityTextField(toggle: true)
} else {
toggleParityTextField(toggle: false)
}
}
}
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField is PickerTextField {
textField.resignFirstResponder()
return false
} else {
return true
}
}
}
extension AddNewDataVC: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return injectedVaccinArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = vaccinTable.dequeueReusableCell(withIdentifier: "injectedVaccinCell", for: indexPath) as? InjectedVaccinCell else {
return UITableViewCell()
}
cell.configureCell(value: injectedVaccinArray[indexPath.row])
return cell
}
}
extension AddNewDataVC: PopupDelegates {
func popupValueSelected(value: [String : Any]) {
self.injectedVaccinArray.append(value)
self.vaccinTable.reloadData()
}
}
There are alot of room for improvement I know but I'm just learned swift so sorry if my code make you itch haha. right now I'm just focusing on make it works and will try to clean it up later down the road.

Related

Update text values of TableViewCell content by using UIButton action inside TableViewCell

I am working on an app in which i am using UITableviewCell to display feed data. In Cell i am using multiple UIButtons to perform actions.
The main issue arise when i perform action through buttons the method is not called for the very first time(TableViewCell content is not updated). But when i press button second time it works fine.
Here is my code
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell_Reels", for: indexPath) as! Cell_Reels
cell.delegate = self
DispatchQueue.main.asyncAfter(deadline: .now()+0.1) { [self] in
UIView.animate(withDuration: 12.0, delay: 1, options: ([.curveLinear, .repeat]), animations: {() -> Void in
cell.marqueeLabel.center = CGPoint.init(x: 35 - cell.marqueeLabel.bounds.size.width / 2, y: cell.marqueeLabel.center.y)
}, completion: { _ in })
cell.likebutton.tag = indexPath.row
cell.FollowButton.tag = indexPath.row
cell.shareBtn.tag = indexPath.row
cell.shareBtn.addTarget(self, action: #selector(buttonShare), for: .touchUpInside)
let VideoStr = self.videos[indexPath.row]["media"].string ?? ""
self.fullVideoUrl = "\(KeyConstant.KBaseImageURL)\(VideoStr)"
//print("======", self.fullVideoUrl)
cell.configureCell( videoUrl: self.fullVideoUrl)
self.pausePlayeVideos()
cell.totalViews.text = "\(self.videos[indexPath.row]["count_view"].string ?? "") Views"
cell.nameLbl.text = self.videos[indexPath.row]["full_name"].string ?? ""
cell.descLbl.text = self.videos[indexPath.row]["title"].string ?? ""
cell.marqueeLabel.text = self.videos[indexPath.row]["title"].string ?? ""
cell.idLbl.text = self.videos[indexPath.row]["id"].string ?? ""
cell.likedLbl.text = self.videos[indexPath.row]["like_status"].string ?? ""
cell.followedLbl.text = self.videos[indexPath.row]["follow_status"].string ?? ""
self.currentLikesStr = self.videos[indexPath.row]["count_like"].string ?? ""
cell.likesCountLabel.text = "\(self.currentLikesStr) Likes"
self.followedStr = self.videos[indexPath.row]["follow_status"].string ?? ""
print("followedStr ppppppppppppppppppppppppp",followedStr, cell.idLbl.text!)
if self.followedStr == "0"
{
cell.FollowButton .setTitle("Follow", for: UIControl.State.normal)
}
else
{
cell.FollowButton .setTitle("Following", for: UIControl.State.normal)
}
self.likedStr = self.videos[indexPath.row]["like_status"].string ?? ""
print("likedStr -=-==-===-=-=-",likedStr, cell.idLbl.text!)
if likedStr == "0"
{
let selectedImage = UIImage(named: "heart_y2_30x30") as UIImage?
cell.likebutton.setImage(selectedImage, for: UIControl.State.normal)
}
else
{
let selectedImage = UIImage(named: "heart_y_30x30") as UIImage?
cell.likebutton.setImage(selectedImage, for: UIControl.State.normal)
}
cell.CommentsCountLabel.text = "Comments"
}
return cell
}
Button method decleration
func addFollowed(cell: Cell_Reels)
{
followedStr = cell.followedLbl.text!
let idstr = cell.idLbl.text
print(userId, idstr ?? "", followedStr)
let VideoidStr = cell.idLbl.text
print("=====", VideoidStr!)
let deviceid = "12345"
//print(videoId)
WebServiceHelper.sharedInstanceAPI.hitPostAPI(urlString: KeyConstant.APIFollow, params: ["user_id":userId, "device_id": deviceid, "device_type" : "iOS", "video_id":VideoidStr!], completionHandler: { (result: [String:Any], err:Error?) in
//print(result)
DispatchQueue.main.async {
//MBProgress().hideIndicator(view: self.view)
}
if(!(err == nil))
{
return
}
let json = JSON(result)
let statusCode = json["status"].string
//print(json)
if(statusCode == "success")
{
DispatchQueue.main.asyncAfter(deadline: .now()+0.1) { [self] in
self.followedStr = json["follow_status"].string ?? ""
cell.followedLbl.text = "\(self.followedStr)"
print(self.followedStr)
print(";;;;;;;;;;;;;;;;;;", self.followedStr)
if self.followedStr == "0"
{
cell.FollowButton .setTitle("Follow", for: UIControl.State.normal)
self.followedStr = "1"
self.arrayTempData[cell.FollowButton.tag] = 1
}
else
{
cell.FollowButton .setTitle("Following", for: UIControl.State.normal)
self.followedStr = "0"
self.arrayTempData[cell.FollowButton.tag] = 0
}
}
}
})
self.tblInstaReels.reloadData()
self.followedStr = ""
}
This i defined in TableViewCell class
protocol TableViewCellDelegate
{
func addTapped(cell: Cell_Reels, Tlikes : String)
func addFollowed(cell: Cell_Reels)
}
class Cell_Reels: UITableViewCell, ASAutoPlayVideoLayerContainer
{
var delegate: TableViewCellDelegate?
#IBOutlet weak var likedLbl : UILabel!
#IBOutlet weak var followedLbl : UILabel!
#IBOutlet weak var idLbl : UILabel!
#IBOutlet weak var nameLbl : UILabel!
#IBOutlet weak var likesCountLabel : UILabel!
#IBOutlet weak var CommentsCountLabel : UILabel!
#IBOutlet weak var marqueeLabel: UILabel!
#IBOutlet weak var imgReels: UIImageView!
#IBOutlet weak var Bkview: UIView!
#IBOutlet weak var PauseBtn: UIButton!
#IBOutlet weak var descLbl: UILabel!
#IBOutlet weak var shareBtn : UIButton!
#IBOutlet weak var likebutton : UIButton!
#IBOutlet weak var FollowButton : UIButton!
#IBOutlet weak var totalViews : UILabel!
var playerController: ASVideoPlayerController?
var videoLayer: AVPlayerLayer = AVPlayerLayer()
var likestr = ""
private(set) var liked = false
private(set) var followed = false
var VideoId = ""
#IBAction func followed(_ sender: Any)
{
delegate?.addFollowed(cell: self)
}
#IBAction func like(_ sender: Any)
{
delegate?.addTapped(cell: self, Tlikes: self.likedLbl.text!)
}
func likeVideo()
{
print("==========", likestr)
}
var videoURL: String?
{
didSet {
if let videoURL = videoURL
{
ASVideoPlayerController.sharedVideoPlayer.setupVideoFor(url: videoURL)
}
videoLayer.isHidden = videoURL == nil
}
}
override func awakeFromNib()
{
super.awakeFromNib()
imgReels.layer.addSublayer(videoLayer)
selectionStyle = .none
}
func configureCell(videoUrl: String?)
{
self.videoURL = videoUrl
}
override func prepareForReuse()
{
imgReels.imageURL = nil
super.prepareForReuse()
}
override func layoutSubviews()
{
super.layoutSubviews()
let horizontalMargin: CGFloat = 20
let width: CGFloat = bounds.size.width - horizontalMargin * 2
let height: CGFloat = (width * 0.9).rounded(.up)
videoLayer.frame = CGRect(x: 0, y: 0, width: imgReels.layer.frame.width, height: imgReels.layer.frame.height)
}
func visibleVideoHeight() -> CGFloat
{
return imgReels.frame.size.height
let videoFrameInParentSuperView: CGRect? = self.superview?.superview?.convert(imgReels.frame, from: imgReels)
guard let videoFrame = videoFrameInParentSuperView,
let superViewFrame = imgReels?.frame else {
return 0
}
let visibleVideoFrame = videoFrame.intersection(superViewFrame)
return visibleVideoFrame.size.height
}
}
in place of calling a separate method, use the addTarget method.
if you update anything in table view then perform all operations in cellForRowAt else after scrolling it reused the cell and it will create ambiguity
reload the table view in the main thread.

Swift NSTiimer not following specified Interval

I am trying to create a quiz app which has a timer for each question when the timer expires (i.e. 10 seconds and I want Timer to have an interval of 1 sec) it resets it self and next question is fetched and Timer again restart from 10... But my issue is the timer doesn't follow a fixed interval when first question is loaded it shows interval of 2 ... i.e. 10,8,6 .. and then for second question it makes jump for 3 secs interval and similarly the interval increases.
import UIKit
class ViewController: UIViewController {
let allQuestions = QuestionsBundle()
var pickedAnswer : Int = 0
var questionCounter = 0
var score : Int = 0
var timer: Timer!
#IBOutlet weak var questionLabel: UILabel!
#IBOutlet weak var countDownLabel: UILabel!
#IBOutlet weak var ansLbl1: UILabel!
#IBOutlet weak var ansLbl2: UILabel!
#IBOutlet weak var ansLbl3: UILabel!
#IBOutlet weak var ansLbl4: UILabel!
#IBOutlet weak var checkBox1: CheckBox!
#IBOutlet weak var checkBox2: CheckBox!
#IBOutlet weak var checkBox3: CheckBox!
#IBOutlet weak var checkBox4: CheckBox!
var checkBoxlist : [CheckBox] = []
#IBAction func correct_Answer_Checbox_Btn(_ sender: AnyObject) {
//print("\(sender.tag) <==> \(String(describing: question?.correctAnswer))")
updateCheckBoxes(sender: sender)
if sender.tag == question?.correctAnswer{
question?.isAnswerCorrect = true
question?.selectedAnswer = sender.tag
//score = score + 1
}
else {
question?.isAnswerCorrect = false
}
}
func updateCheckBoxes(sender: AnyObject){
for checkBoxItem in checkBoxlist{
if checkBoxItem.tag != sender.tag {
checkBoxItem.isChecked = false
}
}
}
#IBOutlet weak var nextButton: UIButton!
#IBAction func nextBtnClicked(_ sender: AnyObject) {
do{
try handleNextQuestion()
}
catch{
moveToResultView()
}
}
func handleNextQuestion() throws {
nextQuestion()
if questionCounter == allQuestions.list.count-1{
finishButton.isHidden = false
nextButton.isHidden = true
//scoreLbl.text = "\(score)"
}
}
var question : Question?
var countTime = 10.0
override func viewDidLoad() {
super.viewDidLoad()
finishButton?.isHidden = true
checkBoxlist = fetchCheckBoxList()
question = fetchQuestion()
setQuizView(question: question!)
// Do any additional setup after loading the view, typically from a nib.
}
// set all questions in a function
#objc func update() {
if(countTime > 0) {
countTime = countTime - 1
self.countDownLabel.text = String(countTime)
}else{
timer.invalidate()
countTime = 10.0
do{
try handleNextQuestion()
}
catch{
moveToResultView()
}
}
}
func startTimer() {
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(ViewController.update), userInfo: nil, repeats: true)
}
func setQuizView(question:Question) {
self.countDownLabel.text = "10"
startTimer()
questionLabel.text = question.questionText
ansLbl1.text = question.answer1
ansLbl2.text = question.answer2
ansLbl3.text = question.answer3
ansLbl4.text = question.answer4
if question.selectedAnswer == Constants.DEFAULT_ANSWER {
for checkBoxItem in checkBoxlist{
checkBoxItem.isChecked = false
}
}
}
#IBOutlet weak var finishButton: UIButton!
// prepare segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == resultScreenIdentifier{
let vc = segue.destination as! ResultViewController
vc.data = sender as! String
}
}
let resultScreenIdentifier = "resultScreenSegue"
func moveToResultView(){
performSegue(withIdentifier: resultScreenIdentifier, sender: score)
}
#IBAction func finishButtonClicked(_ sender: UIButton) {
//perform segue
let score = "\(calculateScore())"
moveToResultView()
}
// calculate the score of quiz using loop
func calculateScore()->Int{
var numOfCorrectAnswers = 0
for question in allQuestions.list{
if question.isAnswerCorrect {
numOfCorrectAnswers = numOfCorrectAnswers + 1
//print(numOfCorrectAnswers)
}
}
return numOfCorrectAnswers
}
func nextQuestion(){
showResultView(isCorrect: (question?.isAnswerCorrect)!)
questionCounter = questionCounter + 1
question = fetchQuestion()
setQuizView(question: question!)
}
func fetchQuestion() -> Question{
return allQuestions.list[questionCounter]
}
func fetchCheckBoxList() -> [CheckBox]{
let arr : [CheckBox] = [checkBox1,checkBox2,checkBox3,checkBox4]
return arr
}
}
Timers are not particularly accurate. They can suffer from significant jitter.
A better approach is to create a Date that represents the expiration time (ie Date(timeIntervalSinceNow:10) and then run a Timer with a much shorter interval (I would suggest around 0.1 second). You can then calculate the time remaining based on the target Date and check if the target date is in the past.

How to fix pass date between 2 ViewControllers

I try to pass imageName string data from ViewController to ImageViewController
which also func sliderImageTapped is sending data to CPImageSlider class
// ViewController.swift
import UIKit
let _AUTO_SCROLL_ENABLED : Bool = false
class ViewController: UIViewController, CPSliderDelegate {
var imagesArray = [String]()
var passDataDelegate: PassImageName?
#IBOutlet weak var slider : CPImageSlider!
#IBOutlet weak var autoSwitch : UISwitch!
#IBOutlet weak var arrowSwitch : UISwitch!
#IBOutlet weak var indicatorSwitch : UISwitch!
#IBOutlet weak var sliderSwitch : UISwitch!
#IBOutlet weak var circularSwitch : UISwitch!
override func viewDidLoad() {
super.viewDidLoad()
imagesArray = ["wallpaper1.jpg","wallpaper2.jpg","wallpaper3.jpg","wallpaper4.jpg"]
slider.images = imagesArray
slider.delegate = self
let zoom : CGFloat = 0.8
autoSwitch.transform = CGAffineTransform(scaleX: zoom, y: zoom)
arrowSwitch.transform = CGAffineTransform(scaleX: zoom, y: zoom)
indicatorSwitch.transform = CGAffineTransform(scaleX: zoom, y: zoom)
sliderSwitch.transform = CGAffineTransform(scaleX: zoom, y: zoom)
circularSwitch.transform = CGAffineTransform(scaleX: zoom, y: zoom)
autoSwitch.isOn = slider.autoSrcollEnabled
arrowSwitch.isOn = slider.enableArrowIndicator
indicatorSwitch.isOn = slider.enablePageIndicator
sliderSwitch.isOn = slider.enableSwipe
circularSwitch.isOn = slider.allowCircular
}
func sliderImageTapped(slider: CPImageSlider, imageName: String, index: Int) {
passDataDelegate?.passData(clickedImageName: imageName)
guard let destinationVC = storyboard?.instantiateViewController(withIdentifier: "ImageViewController") as? ImageViewController else {
return
}
present(destinationVC, animated: true, completion: nil )
print("\(index)")
}
}
// ImageViewController.swift
import UIKit
protocol PassImageName {
func passData(clickedImageName:String)
}
class ImageViewController: UIViewController, PassImageName {
#IBOutlet weak var image: UIImageView!
var imageName:String?
func passData(clickedImageName: String) {
imageName = clickedImageName
}
override func viewDidLoad() {
super.viewDidLoad()
image.image = UIImage(named: imageName ?? "wallpaper1.jpg")
}
#IBAction func dismiss(_ sender: UIButton) {
dismiss(animated: true, completion: nil)
}
}
You must initialize passDataDelegate before call the delegate method.
func sliderImageTapped(slider: CPImageSlider, imageName: String, index: Int) {
guard let destinationVC = storyboard?.instantiateViewController(withIdentifier: "ImageViewController") as? ImageViewController else {
return
}
passDataDelegate = destinationVC
passDataDelegate?.passData(clickedImageName: imageName)
present(destinationVC, animated: true, completion: nil )
print("\(index)")
}
I don't understand the point of your delegate, is there something preventing you to just set the imageName after instantiating the ImageViewController ?
func sliderImageTapped(slider: CPImageSlider, imageName: String, index: Int) {
guard let destinationVC = storyboard?.instantiateViewController(withIdentifier: "ImageViewController") as? ImageViewController else {
return
}
destinationVC.imageName = imageName
present(destinationVC, animated: true, completion: nil )
print("\(index)")
}
And then just set your image inside it :
var imageName:String? {
didSet {
image.image = UIImage(named: imageName ?? "wallpaper1.jpg")
}
}

UIView textFieldShouldReturn not working

I am having some problems with function textFieldShouldReturn as far at i understand it should be called when enter are pressed on the keyboard but it does not. I have tried to search for solution on google and here but have not found a answer that solved the problem because most of the answers here on the webpage i have fund are a 3 years or older and the solutions from those did not help much.
I am using it in a UIView where the delegates for the textField is set in the function awakeFromNib() and i have tried some other delegate function textViewDidChangeSelection that does work so i am at a lost why it is not working.
Here is how the xib file looks
Here is the code that i am using as a popup:
import UIKit
class CuePointPopup: UIView,UITextFieldDelegate,UITextViewDelegate
{
#IBOutlet var labelCueNumberInImage: UILabel!
#IBOutlet var labelCueNumber: UILabel!
#IBOutlet var labelLayerName: UILabel!
#IBOutlet var labelPageNumber: UILabel!
#IBOutlet weak var view: UIImageView!
#IBOutlet var textFieldWhoText: UITextField!
#IBOutlet var textViewWhatText: UITextView!
#IBOutlet var textFieldWhereText: UITextField!
#IBOutlet var textFieldPageNumber: UITextField!
#IBOutlet var textFieldCueText: UITextField!
#IBOutlet var boxArrowLeft: UIImageView!
#IBOutlet var boxArrowRight: UIImageView!
#IBOutlet var boxArrowLeftTopConstraint: NSLayoutConstraint!
#IBOutlet var boxArrowRightTopConstraint: NSLayoutConstraint!
var cuePointObj:CuePoint!
var blockBtnClickedSave:((CuePoint) -> ())!
var blockBtnClickedCancel:((CuePoint) -> ())!
var blockBtnClickedDelete:((CuePoint) -> ())!
var blockTextChangedForPageNumber:((String, CuePoint) -> ())!
#IBOutlet var btnOutletVisibleOnPage: UIButton!
var isVisible = false
class func loadNib() -> CuePointPopup
{
return Bundle.main.loadNibNamed("CuePointPopup", owner: self,options: nil)!.last as! CuePointPopup
}
override func awakeFromNib() {
self.textFieldWhoText.delegate = self
self.textViewWhatText.delegate = self
self.textFieldWhereText.delegate = self
self.textFieldCueText.delegate = self
textViewWhatText.text = "Hello"
}
func setViewData(cueModel:CuePoint) {
self.cuePointObj = cueModel
labelCueNumberInImage.text = cueModel.cueNumber
labelCueNumber.text = "Cue #:" + cueModel.cueNumber
labelLayerName.text = "Layer #:" + cueModel.layerName
labelPageNumber.text = "Page #:" + cueModel.pageNumber
textFieldPageNumber.text = cueModel.pageNumber
textFieldWhoText.text = cueModel.whoString
textViewWhatText.text = cueModel.whatString
textFieldWhereText.text = cueModel.whereString
textFieldCueText.text = cueModel.cueTextString
if cueModel.isVisibleOnPage == true {
btnOutletVisibleOnPage.setImage(UIImage(named: "SelectedBox"), for: [])
btnOutletVisibleOnPage.tag = 1
}else{
btnOutletVisibleOnPage.setImage(UIImage(named: "UnselectedBox"), for: [])
btnOutletVisibleOnPage.tag = 0
}
}
func textFieldDidEndEditing(_ textField: UITextField) {
if textField.text != "" {
if blockTextChangedForPageNumber != nil {
self.blockTextChangedForPageNumber(textField.text!, self.cuePointObj)
}
}
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
//self.view.endEditing(true)
if self.textFieldWhoText.isEditing {
self.textFieldWhoText.endEditing(true)
} else if self.textFieldCueText.isEditing{
self.textFieldCueText.endEditing(true)
} else if self.textFieldWhereText.isEditing {
self.textFieldWhereText.endEditing(true)
} else {
self.textViewWhatText.endEditing(true)
}
//self.view.endEditing(true)
return false
}
}
Here is how i load the XIB
#IBOutlet weak var bookView: UIView!
var objCuePopup:CuePointPopup!
if objCuePopup != nil {
objCuePopup.removeFromSuperview()
}
objCuePopup = CuePointPopup.loadNib()
objCuePopup = CuePointPopup.loadNib()
objCuePopup.frame = CGRect(x:cuePointModal.cueX, y:0, width:465, height:410)
objCuePopup.center = CGPoint(x:objCuePopup.center.x, y:cuePointModal.cueY + 5)
//Set Y value for Popup View
if objCuePopup.frame.origin.y < bookView.frame.origin.y {
objCuePopup.frame.origin.y = bookView.frame.origin.y
}
let popupMaxY = objCuePopup.frame.maxY
let bookViewMaxY = bookView.frame.maxY
if popupMaxY > bookViewMaxY {
objCuePopup.frame.origin.y = bookViewMaxY - objCuePopup.frame.size.height
}
//Set X value for Popup View
if cuePointModal.cueX > 455 {
objCuePopup.frame.origin.x = cuePointModal.cueX - 455
objCuePopup.boxArrowLeft.isHidden = true
objCuePopup.boxArrowRight.isHidden = false
let rightY = cuePointModal.cueY - objCuePopup.frame.origin.y
objCuePopup.boxArrowRightTopConstraint.constant = rightY + 3
}else{
objCuePopup.frame.origin.x = cuePointModal.cueX + 40
objCuePopup.boxArrowLeft.isHidden = false
objCuePopup.boxArrowRight.isHidden = true
let leftY = cuePointModal.cueY - objCuePopup.frame.origin.y
objCuePopup.boxArrowLeftTopConstraint.constant = leftY + 3
}
objCuePopup.setViewData(cueModel: cuePointModal)
objCuePopup.textFieldWhoText.delegate = self
objCuePopup.textFieldWhereText.delegate = self
objCuePopup.textViewWhatText.delegate = self
objCuePopup.textFieldCueText.delegate = self
bookView.addSubview(objCuePopup)
I hope that someone here can help me with this problem.

How to change button title every time checkmark selected within custom cell

I have a viewcontroller that has a tableview and a button at the bottom. Within each cell is a radio button as a tapGesture. I would like to updated the button with the number of cells selected. If my gesture is in the custom cell and my button is in my viewcontroller how can I get the two to work together?
Custom cell:
class SearchTalentCell: UITableViewCell {
#IBOutlet weak var userProfileImage: UIImageView!
#IBOutlet weak var talentUserName: UILabel!
#IBOutlet weak var selectedImg: UIImageView!
#IBOutlet weak var inviteSentImg: UIImageView!
var prospectRef: FIRDatabaseReference!
var currentTalent: UserType!
func setTalent(talent: UserType) {
currentTalent = talent
currentTalent.userKey = talent.userKey
}
override func awakeFromNib() {
super.awakeFromNib()
let tap = UITapGestureRecognizer(target: self, action: #selector(selectTapped))
tap.numberOfTapsRequired = 1
selectedImg.addGestureRecognizer(tap)
selectedImg.isUserInteractionEnabled = true
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func configureCell(user: UserType, img: UIImage? = nil) {
prospectRef = Cast.REF_PRE_PRODUCTION_CASTING_POSITION.child(ProjectDetailVC.currentProject).child(FIRDataCast.prospect.rawValue).child(CastingDetailVC.positionName).child(user.userKey)
setTalent(talent: user)
self.talentUserName.text = "\(user.firstName) \(user.lastName)"
prospectRef.observeSingleEvent(of: .value, with: { (snapshot) in
if let _ = snapshot.value as? NSNull {
self.inviteSentImg.isHidden = true
} else {
self.inviteSentImg.image = UIImage(named: "inviteSent")
self.inviteSentImg.isHidden = false
}
})
if UserType.selectedTalentForSearch.contains(currentTalent.userKey) {
selectedImg.image = UIImage(named: "radioSelected")
} else {
selectedImg.image = UIImage(named: "radioUnselected")
}
//Image Caching
if img != nil {
self.userProfileImage.image = img
} else {
if let imageURL = user.profileImage {
let ref = FIRStorage.storage().reference(forURL: imageURL)
ref.data(withMaxSize: 2 * 1024 * 1024, completion: { (data, error) in
if error != nil {
print("ZACK: Unable to download image from Firebase Storage")
} else {
print("ZACK: Image downloaded from Firebase Storage")
if let imgData = data {
if let img = UIImage(data: imgData) {
self.userProfileImage.image = img
SearchTalentVC.userProfileImageCache.setObject(img, forKey: imageURL as NSString)
}
}
}
})
}
}
}
#objc func selectTapped(sender: UITapGestureRecognizer) {
if UserType.selectedTalentForSearch.contains(currentTalent.userKey) {
selectedImg.image = UIImage(named: "radioUnselected")
UserType.selectedTalentForSearch = UserType.selectedTalentForSearch.filter{$0 != currentTalent.userKey}
print("Keys: \(UserType.selectedTalentForSearch)")
} else {
selectedImg.image = UIImage(named: "radioSelected")
UserType.selectedTalentForSearch.append(currentTalent.userKey)
print("Keys: \(UserType.selectedTalentForSearch)")
}
}
}
ViewController:
class SearchTalentVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var sendInviteButton: UIButton!
var searchingRole = [Cast]()
var unfilteredTalent = [UserType]()
var filteredTalent = [UserType]()
var selectedTalent = [UserType]()
var matchingTalentUserKeys = [String]()
var isFiltered = false
var selectedCounter = [String]()
var prospectRef: FIRDatabaseReference!
static var userProfileImageCache: NSCache<NSString, UIImage> = NSCache()
let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search Talent"
searchController.searchBar.barStyle = .black
navigationItem.searchController = searchController
definesPresentationContext = true
searchController.searchBar.scopeButtonTitles = ["All", "Role Specific"]
searchController.searchBar.tintColor = UIColor.white
searchController.searchBar.delegate = self
searchController.searchResultsUpdater = self
self.sendInviteButton.setTitle("Send Invite to \(UserType.selectedTalentForSearch.count) Prospects", for: .normal)
getTalentProfiles()
}
Thank you for any help!
I'm not sure why you are using the cell selection inside the cell, as opposed to the tableview delegate function func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)?
If you use didSelectRowAt, you could have an array of selected rows and you can include the selectedRows.count into your button text.
Hope that helps!

Resources