I'm working on a countdown timer that allows the user to select a future trip departure date & time, hit a start button to start the countdown, then hit a reset button to invalidate the timer and allow the user to select a different departure date and time, then start again.
everything works pretty well, except for the reset button. the timer invalidates briefly, but then continues the countdown, and the days, minutes, hours, seconds labels continue to update.
I thought that invalidating the timer would freeze values, or I could set all days, minutes, hours, seconds labels to "", and then start button would begin a new countdown. no such luck. right after selecting a new departure date/time, countdown begins, even if start button isn't pressed.
I'm looking for a way to stop the printTime and runTimer functions. thanks for the help.
here's the code:
import UIKit
class ViewController: UIViewController {
var resetBtnStatus: Bool = false
var timer = Timer()
let userCalendar = Calendar.current
let requestedComponent: Set<Calendar.Component> = [.day,.hour,.minute,.second]
var departureDateTime: Date?
#IBOutlet weak var departureDateTimePicker: UIDatePicker!
#IBAction func departureDateTimePicker(_ sender: Any) {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM/dd/yy H:mm:ss"
departureDateTimePicker.addTarget(self, action: #selector(handler), for: UIControlEvents.valueChanged)
}
#IBOutlet weak var daysLabel: UILabel!
#IBOutlet weak var hoursLabel: UILabel!
#IBOutlet weak var minutesLabel: UILabel!
#IBOutlet weak var secondsLabel: UILabel!
func handler(sender: UIDatePicker) {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM/dd/yy H:mm:ss"
let departureDateTimeString = dateFormatter.string(from: departureDateTimePicker.date)
departureDateTime = dateFormatter.date(from: departureDateTimeString)
}
#IBAction func resetBtnPressed(_ sender: Any) {
if resetBtn.isSelected == true {
resetBtnStatus = true
}
departureDateTimePicker.isHidden = false
startBtn.isHidden = false
// let dateFormatter = DateFormatter()
// dateFormatter.dateFormat = "MM/dd/yy H:mm:ss"
// let startTime = Date()
// let endTime = startTime
// let timeDifference = userCalendar.dateComponents(requestedComponent, from: startTime, to: endTime)
// daysLabel.text = "\(timeDifference.day!) Days"
// hoursLabel.text = "\(timeDifference.hour!) Hours"
// minutesLabel.text = "\(timeDifference.minute!) Minutes"
// secondsLabel.text = "\(timeDifference.second!) Seconds"
}
// #IBAction func resetBtnPressed(_ sender: Any) {
// if resetBtn.isSelected == true {
// resetBtnStatus = true
// }
// departureDateTimePicker.isHidden = false
// startBtn.isHidden = false
// // let dateFormatter = DateFormatter()
// // dateFormatter.dateFormat = "MM/dd/yy H:mm:ss"
// // let startTime = Date()
// // let endTime = startTime
// // let timeDifference = userCalendar.dateComponents(requestedComponent, from: startTime, to: endTime)
// // daysLabel.text = "\(timeDifference.day!) Days"
// // hoursLabel.text = "\(timeDifference.hour!) Hours"
// // minutesLabel.text = "\(timeDifference.minute!) Minutes"
// // secondsLabel.text = "\(timeDifference.second!) Seconds"
// }
func printTime() {
if resetBtnStatus == false {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM/dd/yy H:mm:ss"
let startTime = Date()
let endTime = departureDateTime
let timeDifference = userCalendar.dateComponents(requestedComponent, from: startTime, to: endTime!)
let startTimeDouble: Double = startTime.timeIntervalSinceReferenceDate
var endTimeDouble: Double?
endTimeDouble = (endTime?.timeIntervalSinceReferenceDate)
daysLabel.text = "\(timeDifference.day!) Days"
hoursLabel.text = "\(timeDifference.hour!) Hours"
minutesLabel.text = "\(timeDifference.minute!) Minutes"
secondsLabel.text = "\(timeDifference.second!) Seconds"
if endTimeDouble! > startTimeDouble {
daysLabel.text = "\(timeDifference.day!) Days"
hoursLabel.text = "\(timeDifference.hour!) Hours"
minutesLabel.text = "\(timeDifference.minute!) Minutes"
secondsLabel.text = "\(timeDifference.second!) Seconds"
}
else {
timer.invalidate()
daysLabel.text = ""
hoursLabel.text = ""
minutesLabel.text = ""
secondsLabel.text = ""
}
} else {
timer.invalidate()
daysLabel.text = ""
hoursLabel.text = ""
minutesLabel.text = ""
secondsLabel.text = ""
}
}
func runTimer() {
if resetBtnStatus == false {
let timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(printTime), userInfo: nil, repeats: true)
timer.fire()
}
if resetBtnStatus == true {
timer.invalidate()
}
}
#IBOutlet weak var startBtn: UIButton!
#IBAction func startBtnPressed(_ sender: Any) {
handler(sender: departureDateTimePicker)
printTime()
runTimer()
departureDateTimePicker.isHidden = true
startBtn.isHidden = true
}
#IBOutlet weak var resetBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Related
I have a chat feature within my app. The page loads the existing data as an array called hhmessages. The last message in the conversation was 'Welcome', when I enter new text 'Thank You' and hit enter the table automatically displays 'Welcome' again instead of 'Thank You.' If it exit out of the page and come back it now shows 'Thank You' as the last message. It's working on the backend just the instant update isn't showing the value in the UITableView when entered.
This is for an iPhone app.
UPDATED TO SHOW COMPLETE CODE - Now that reverse has been removed the new entry shows as blank.
import UIKit
import Foundation
extension String {
// Calculeta the hight string Function
func calculateTextFrameRect(
objectsInPlaceHeight: CGFloat,
objectsInPlaceWidth: CGFloat,
fontSize: CGFloat,
fontWeight: CGFloat) -> CGSize
{
let bounding = CGSize(width: UIScreen.main.bounds.width - objectsInPlaceWidth, height: .infinity)
let rect = NSString(string: self).boundingRect(
with: bounding,
options: NSStringDrawingOptions.usesFontLeading.union(NSStringDrawingOptions.usesLineFragmentOrigin),
attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: fontSize, weight: UIFont.Weight(rawValue: fontWeight))],
context: nil)
return CGSize(width: UIScreen.main.bounds.width, height: rect.height + objectsInPlaceHeight )
}
}
// Messages for test
let frame = CGRect(origin: .zero, size: CGSize.init(width: 375, height: 559))
class Message {
let message: String
var incoming: [Int]
let image: UIImage
var avas = UIImage()
init(message: String, image: UIImage, incoming: Int, avas: UIImage) {
self.message = message
self.image = image
self.incoming = [incoming]
self.avas = avas
}
}
class ConversationViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate, UITableViewDelegate, UITableViewDataSource, UITextViewDelegate {
//var user = NSDictionary()
var messages = NSDictionary()
//var guest = NSDictionary()
#IBOutlet var senderLbl: UILabel!
#IBOutlet var senderageLbl: UILabel!
#IBOutlet var senderraceLbl: UILabel!
#IBOutlet var sendergenderLbl: UILabel!
#IBOutlet var sendercityLbl: UILabel!
#IBOutlet var senderstateLbl: UILabel!
// #IBOutlet var tableView: UITableView!
var hhmessages = [AnyObject]()
//var messages: [Message] = []
var pictures = [UIImage]()
var avas = [UIImage]()
var avaURL = [String]()
var isLoading = false
var skip = 0
var limit = 50
var images = [UIImage]()
var incoming: [Int] = []
var comments = [String]()
var ids = [String]()
//var isSent: String = ""
var isPictureSelected = false
//var currentUser_ava = [Any]()
#IBOutlet var pictureImg: UIImageView!
#IBOutlet var avaImg: UIImageView!
#IBOutlet var viewprofile_btn: UIButton!
#IBOutlet var imgprofile_btn: UIButton!
#IBOutlet var replyTxt: UITextView!
//var replyTxt:UITextView!
#IBOutlet var replyTxt_height: NSLayoutConstraint!
#IBOutlet var replyTxt_bottom: NSLayoutConstraint!
#IBOutlet var picSelect: UIButton!
#IBOutlet var replyBtn: UIButton!
var puuid = String()
var imageSelected = false
var coolIndicator: UIActivityIndicatorView!
var commentsTextView_bottom_identity = CGFloat()
#IBOutlet var tableView: UITableView!
// Table View here + basic configuration
override func viewDidLoad() {
//self.tabBarController?.tabBar.isHidden = true
super.viewDidLoad()
tableView.transform = CGAffineTransform(rotationAngle: -(CGFloat)(Double.pi));
// dynamic cell height
tableView.dataSource = self
tableView.delegate = self
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 200
loadPosts()
replyTxt.layer.cornerRadius = replyTxt.bounds.width / 50
replyTxt.backgroundColor = UIColor.clear
replyTxt.layer.borderColor = UIColor.gray.cgColor
replyTxt.layer.borderWidth = 1.0
let username = messages["sender"] as? String
self.navigationItem.title = username
}
// pre last func
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// remove observers of notification when the viewController is left
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
// exec-d once notification is caught -> KeyboardWillShow
#objc func keyboardWillShow(_ notification: Notification) {
// getting the size of the keyboard
if let keyboard_size = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
// increasing the bottom constraint by the keyboard's height
replyTxt_bottom.constant += keyboard_size.height
}
// updating the layout with animation
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
}
// exec-d once notification is caught -> KeyboardWillHide
#objc func keyboardWillHide() {
// updating the layout with animation
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
//replyTxt().resignFirstResponder()
self.view.endEditing(false)
}
// TABLEVIEW
// Number os cells
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return hhmessages.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let colorSmoothGray = UIColor(red: 229/255, green: 229/255, blue: 234/255, alpha: 1)
let colorBrandBlue = UIColor(red: 148 / 255, green: 33 / 255, blue: 147 / 255, alpha: 1)
let pictureURL = hhmessages[indexPath.row]["uploadpath"] as? String
print("test 1", pictureURL)
// no picture in the post
if pictureURL == nil || pictureURL == "" {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! ConversationCell
cell.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi))
// shortcuts
let hhpost = hhmessages[indexPath.row]
let text = hhpost["messagetext"] as? String
cell.messageLbl.text = text
cell.messageLbl.textAlignment = .right
cell.messageLbl.backgroundColor = colorSmoothGray
cell.messageLbl.textColor = .black
cell.messageLbl.font = UIFont.preferredFont(forTextStyle: UIFontTextStyle.body)
cell.messageLbl.font?.withSize(25)
cell.messageLbl.clipsToBounds = true
cell.messageLbl.sizeToFit()
pictures.append(UIImage())
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "PicCell", for: indexPath) as! PicConversationCell
cell.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi))
let smimages = hhmessages[indexPath.row]["path"] as? UIImage
cell.smavaImg.image = smimages
for i in 0 ..< self.incoming.count {
// Confiture the constraints for cell
if self.incoming[indexPath.row] == 1 {
// Text
cell.messageLbl.textAlignment = .left
cell.messageLbl.backgroundColor = colorBrandBlue
cell.messageLbl.textColor = .white
cell.messageLbl.font = UIFont.preferredFont(forTextStyle: UIFontTextStyle.body)
cell.messageLbl.font?.withSize(25)
cell.messageLbl.clipsToBounds = true
// Constraints
cell.lefBubbleConstraint.isActive = true
cell.rightBubbleConstraint.isActive = false
if cell.postpictureImg.image == nil {
cell.postpictureImg.backgroundColor = .black
cell.postpictureImg.clipsToBounds = true
}
else {
cell.postpictureImg.backgroundColor = .black
cell.postpictureImg.clipsToBounds = true
}
}
else if self.incoming[indexPath.row] == 0 {
// Text
cell.messageLbl.textAlignment = .right
cell.messageLbl.backgroundColor = colorSmoothGray
cell.messageLbl.textColor = .black
cell.messageLbl.font = UIFont.preferredFont(forTextStyle: UIFontTextStyle.body)
cell.messageLbl.font?.withSize(25)
cell.messageLbl.clipsToBounds = true
// Constraints
cell.lefBubbleConstraint.isActive = false
cell.rightBubbleConstraint.isActive = true
if cell.postpictureImg.image == nil {
cell.postpictureImg.backgroundColor = .black
cell.postpictureImg.clipsToBounds = true
}
else {
cell.postpictureImg.backgroundColor = .black
cell.postpictureImg.clipsToBounds = true
}
}
if cell.lefBubbleConstraint.isActive == true {
cell.lefImageConstraint.isActive = true
cell.rightImageConstraint.isActive = false
} else {
cell.lefImageConstraint.isActive = false
cell.rightImageConstraint.isActive = true
}
let pictureString = hhmessages[indexPath.row]["uploadpath"] as! String
let pictureURL = URL(string: pictureString)!
// if there are still pictures to be loaded
if hhmessages.count != pictures.count {
URLSession(configuration: .default).dataTask(with: pictureURL) { (data, response, error) in
// downloaded
if let image = UIImage(data: data!) {
self.pictures.append(image)
DispatchQueue.main.async {
cell.postpictureImg.image = image
}
}
}.resume()
// cached picture
} else {
DispatchQueue.main.async {
cell.postpictureImg.image = self.pictures[indexPath.row]
}
}
}
return cell
}
}
// pre load func
override func viewDidAppear(_ animated: Bool) {
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
// func of loading posts from server
#objc func loadPosts() {
//isLoading = true
let me = user!["username"] as! String
let meid = user!["id"] as! String
print(meid)
print(me)
//print(username)
let uuid = messages["uuid"] as! String
print(uuid)
// accessing php file via url path
let url = URL(string: "http://localhost/message.php")!
// pass information to php file
let body = "username=\(me)&uuid=\(uuid)&recipient_id=\(meid)"
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = body.data(using: String.Encoding.utf8)
tableView.transform = CGAffineTransform(rotationAngle: -(CGFloat)(Double.pi));
// launch session
URLSession.shared.dataTask(with: request) { (data, response, error) in
DispatchQueue.main.async {
// no error of accessing php file
// error occured
if error != nil {
Helper().showAlert(title: "Server Error", message: error!.localizedDescription, in: self)
//self.isLoading = false
return
}
do {
// access data - safe mode
guard let data = data else {
Helper().showAlert(title: "Data Error", message: error!.localizedDescription, in: self)
//self.isLoading = false
return
}
// getting content of $returnArray variable of php file
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? NSDictionary
// accessing json data - safe mode
guard let posts = json?["messages"] as? [NSDictionary] else {
//self.isLoading = false
return
}
// assigning all successfully loaded posts to our Class Var - posts (after it got loaded successfully)
self.hhmessages = posts
self.tableView.reloadData()
// scroll to the latest index (latest cell -> bottom)
let indexPath = IndexPath(row: self.hhmessages.count - 1, section: 0)
self.tableView.scrollToRow(at: indexPath, at: .bottom, animated: true)
// self.isLoading = false
} catch {
Helper().showAlert(title: "JSON Error", message: error.localizedDescription, in: self)
//self.isLoading = false
return
}
}
}.resume()
}
#IBAction func viewprofile_clicked(_ sender: Any) {
// performSegue(withIdentifier: "guest2", sender: self.guest)
}
#IBAction func imgprofile_clicked(_ sender: Any) {
// performSegue(withIdentifier: "guest2", sender: self.guest)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "guest" {
if let destination = segue.destination as? GuestViewController {
destination.guest = messages
}
}
}
// function sending requset to PHP to uplaod a file
func uploadPost() {
// validating vars before sending to the server
guard let user_id = user?["id"] as? String, let username = user?["username"] as? String, let avaPath = user?["ava"] else {
// converting url string to the valid URL
if let url = URL(string: user?["ava"] as! String) {
// downloading all data from the URL
guard let data = try? Data(contentsOf: url) else {
return
}
// converting donwloaded data to the image
guard let image = UIImage(data: data) else {
return
}
// assigning image to the global var
let currentUser_ava = image
}
return
}
let user_id_int = Int(user_id)!
let messagetext = replyTxt.text.trimmingCharacters(in: .whitespacesAndNewlines)
hhmessages.insert(messagetext as AnyObject, at: hhmessages.endIndex)
let indexPath = IndexPath(row: hhmessages.count - 1, section: 0)
tableView.beginUpdates()
tableView.insertRows(at: [indexPath], with: .automatic)
tableView.endUpdates()
tableView.transform = CGAffineTransform(rotationAngle: -(CGFloat)(Double.pi));
tableView.scrollToRow(at: indexPath, at: .bottom, animated: true)
replyTxt.text = ""
textViewDidChange(replyTxt)
let recipient = messages["username"] as! String
let rid = String(describing: messages["recipient_id"]!)
let uuid = messages["uuid"] as! String
puuid = UUID().uuidString
// prepare request
let url = URL(string: "http://localhost/messagepost.php")!
let body = "sender_id=\(user_id)&sender=\(username)&text=\(messagetext)&recipient_id=\(rid)&recipient=\(recipient)&uuid=\(uuid)&puuid=\(puuid)"
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = body.data(using: .utf8)
// send request
URLSession.shared.dataTask(with: request) { (data, response, error) in
DispatchQueue.main.async {
// error happened
if error != nil {
Helper().showAlert(title: "Server Error", message: error!.localizedDescription, in: self)
return
}
do {
// converting received data from the server into json format
let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSDictionary
// safe mode of casting json
guard let parsedJSON = json else {
return
}
// if the status of JSON is 200 - success
if parsedJSON["status"] as! String == "200" {
} else {
Helper().showAlert(title: "400", message: parsedJSON["status"] as! String, in: self)
return
}
// json error
} catch {
Helper().showAlert(title: "JSON Error", message: error.localizedDescription, in: self)
return
}
}
}.resume()
}
// exec-d whenever delegated textView has been changed by chars
func textViewDidChange(_ textView: UITextView) {
// declaring new size of the textView. we increase the height
let new_size = textView.sizeThatFits(CGSize.init(width: textView.frame.width, height: CGFloat(MAXFLOAT)))
// assign new size to the textView
textView.frame.size = CGSize.init(width: CGFloat(fmaxf(Float(new_size.width), Float(textView.frame.width))), height: new_size.height)
//UIView.animate(withDuration: 0.2) {
self.view.layoutIfNeeded()
//}
}
#IBAction func picSelect_clicked(_ sender: AnyObject) {
// calling picker for selecting iamge
showActionSheet()
}
// this function launches Action Sheet for the photos
func showActionSheet() {
// declaring action sheet
let sheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
// declaring camera button
let camera = UIAlertAction(title: "Camera", style: .default) { (action) in
// if camera available on device, than show
if UIImagePickerController.isSourceTypeAvailable(.camera) {
self.showPicker(with: .camera)
}
}
// declaring library button
let library = UIAlertAction(title: "Photo Library", style: .default) { (action) in
// checking availability of photo library
if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) {
self.showPicker(with: .photoLibrary)
}
}
// declaring cancel button
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
// adding buttons to the sheet
sheet.addAction(camera)
sheet.addAction(library)
sheet.addAction(cancel)
// present action sheet to the user finally
self.present(sheet, animated: true, completion: nil)
}
// takes us to the PickerController (Controller that allows us to select picture)
func showPicker(with source: UIImagePickerControllerSourceType) {
let picker = UIImagePickerController()
picker.delegate = self
picker.allowsEditing = true
picker.sourceType = source
present(picker, animated: true, completion: nil)
}
// executed whenever the image has been picked via pickerController
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
// accessing selected image
let image = info[UIImagePickerControllerEditedImage] as? UIImage
// assigning selected image to pictureImageView
pictureImg.image = image
// cast boolean as TRUE -> Picture Is Selected
isPictureSelected = true
// remove pickerController
pictureImg.image = info[UIImagePickerControllerEditedImage] as? UIImage
self.dismiss(animated: true, completion: nil)
// cast as a true to save image file in server
if pictureImg.image == info[UIImagePickerControllerEditedImage] as? UIImage {
imageSelected = true
}
dismiss(animated: true, completion: nil)
}
// exec when pictureImageView has been tapped
#IBAction func pictureImageView_tapped(_ sender: Any) {
// declaring action sheet
let sheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
// declaring delete button
let delete = UIAlertAction(title: "Delete", style: .destructive) { (action) in
self.pictureImg.image = UIImage()
}
// declaring cancel button
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
// adding buttons to the sheet
sheet.addAction(delete)
sheet.addAction(cancel)
// present action sheet to the user finally
self.present(sheet, animated: true, completion: nil)
}
// custom body of HTTP request to upload image file
func createBodyWithParams(_ parameters: [String: String]?, filePathKey: String?, imageDataKey: Data, boundary: String) -> Data {
let body = NSMutableData();
if parameters != nil {
for (key, value) in parameters! {
body.appendString("--\(boundary)\r\n")
body.appendString("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
body.appendString("\(value)\r\n")
}
}
// if file is not selected, it will not upload a file to server, because we did not declare a name file
var filename = ""
if imageSelected == true {
filename = "notes-\(puuid).jpg"
}
let mimetype = "image/jpg"
body.appendString("--\(boundary)\r\n")
body.appendString("Content-Disposition: form-data; name=\"\(filePathKey!)\"; filename=\"\(filename)\"\r\n")
body.appendString("Content-Type: \(mimetype)\r\n\r\n")
body.append(imageDataKey)
body.appendString("\r\n")
body.appendString("--\(boundary)--\r\n")
return body as Data
}
#IBAction func replyBtn_clicked(_ sender: Any) {
if replyTxt.text.isEmpty == false && replyTxt.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == false {
uploadPost()
//tableView.reloadData()
}
}
#objc func keyboardWillChange(notification: NSNotification) {
let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt
let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
let deltaY = targetFrame.origin.y - curFrame.origin.y
//print("deltaY",deltaY)
UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {
self.replyTxt.frame.origin.y+=deltaY // Here You Can Change UIView To UITextField
self.tableView.frame.origin.y+=deltaY // Here You Can Change UIView To UITextField
self.replyBtn.frame.origin.y+=deltaY // Here You Can Change UIView To UITextField
self.picSelect.frame.origin.y+=deltaY // Here You Can Change UIView To UITextField
},completion: nil)
}
func textFieldShouldReturn(_ replyTxt: UITextField) -> Bool {
replyTxt.resignFirstResponder()
return true
}
}
the problem is you are inserting the new text at
let indexPath = IndexPath(row: hhmessages.count - 1, section: 0)
which is the last field of the array.
but in your cellForRow: you have
let text = hhmessages.reversed()[indexPath.row]["messagetext"] as! String
which shows the first field of your array in the last cell of tableView.
I think thats your problem.
Like others have told, you are messing up your order in hhmessages.
Imagine you have messages Welcome, Hello, and you are trying to add Thank Your, your code with more comments:
self.hhmessages.insert(messagetext as AnyObject, at: hhmessages.endIndex) // Thank You is inserted to the end of the array at 3rd position (2)
let indexPath = IndexPath(row: hhmessages.count - 1, section: 0) // ok, let's get index of 3rd row (2)
tableView.beginUpdates()
tableView.insertRows(at: [indexPath], with: .automatic) // add new row to the end
tableView.endUpdates()
Then later UIKit asks you to load this new 3rd row at position 2, and you call:
let text = hhmessages.reversed()[indexPath.row]["messagetext"] as! String
The problem is hhmessages.reversed() which reverses your array, and makes Thank you in fact first at position 0, and Welcome the last one at position 2, which will get the text Welcome.
The second problem I see is this line:
let pictureURL = hhmessages[indexPath.row]["uploadpath"] as? String
Here you are getting unreveresed picture url, which at least is very strange.
I need to show data from JSON on label. But my code get error.please help me see on function barcodeReaded. How to loop data when String in label equal string in "testCode" on array JSON file.
This JSON file
{
"episode": [
{
"testCode": "11111111",
"title": "Stomachic mixture 180 ml",
"drug": "AAAAA",
"thumbnailURL": "https://firebasestorage.googleapis.com/v0/b/rxscan-a14ee.appspot.com/o/j01.jpg?alt=media&token=5718797b-fc9c-416e-9394-b544c2880dc9",
"price": "100"
},
{
"testCode": "22222222",
"title": "Parasetamol 200 ml",
"drug": "BBBBB",
"thumbnailURL": "urlImage",
"price": "150"
},
{
"testCode": "33333333",
"title": "Beramol 300 ml",
"drug": "CCCCC",
"thumbnailURL": "urlImage",
"price": "120"
}
]
}
This some code
import UIKit
class barcodeViewController: UIViewController, BarcodeDelegate {
#IBOutlet weak var thumbnailImageView: UIImageView!
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var drugLabel: UILabel!
#IBOutlet weak var priceLabel: UILabel!
#IBOutlet weak var showCodeLabel: UILabel!
var episode: Episode!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
print("Segue!")
let barcodeViewController: barcodeCapViewController = segue.destinationViewController as! barcodeCapViewController
barcodeViewController.delegate = self
}
#IBAction func doneButtonPressed(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil)
}
func barcodeReaded(barcode: String) {
print("Barcode is: \(barcode)")
showCodeLabel.text = barcode
barcode = episode.testCode
if((episode.testCode) != nil)
{
titleLabel.text = episode.title
drugLabel.text = episode.drug
priceLabel.text = episode.price
}
}
}
import Foundation
class Episode
{
var title: String?
var thumbnailURL: NSURL?
var drug: String?
var price: String?
var testCode: String?
init(title: String, thumbnailURL: NSURL, drug: String, price: String, testCode: String)
{
self.title = title
self.thumbnailURL = thumbnailURL
self.drug = drug
self.price = price
self.testCode = testCode
}
typealias EpisodeDictionary = [String : AnyObject]
init(espDictionary: EpisodeDictionary)
{
self.title = espDictionary["title"] as? String
self.thumbnailURL = NSURL(string: espDictionary["thumbnailURL"] as! String)
self.drug = espDictionary["drug"] as? String
self.price = espDictionary["price"] as? String
self.testCode = espDictionary["testCode"] as? String
}
static func downloadAllEpisodes() -> [Episode]
{
var episodes = [Episode]()
let jsonFile = NSBundle.mainBundle().pathForResource("testJson3edit6", ofType: "json")
let jsonData = NSData(contentsOfFile: jsonFile!)
if let jsonDictionary = NetworkService.parseJSONFromData(jsonData) {
let espDictionaries = jsonDictionary["episodes"] as! [EpisodeDictionary]
for dict in espDictionaries {
let episode = Episode(espDictionary: dict)
episodes.append(episode)
}
}
return episodes
}
}
NetworkService.swift
import Foundation
class NetworkService
{
// TODO: Make this class be able to download images from a URL
lazy var configuration: NSURLSessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration()
lazy var session: NSURLSession = NSURLSession(configuration: self.configuration)
let url: NSURL
init(url: NSURL)
{
self.url = url
}
func downloadImage(completion: (NSData -> Void))
{
let request = NSURLRequest(URL: self.url)
let dataTask = session.dataTaskWithRequest(request) { (data, response, error) in
if error == nil {
if let httpResponse = response as? NSHTTPURLResponse {
switch (httpResponse.statusCode) {
case 200:
if let data = data {
completion(data)
}
default:
print(httpResponse.statusCode)
}
}
} else {
print("Error download data: \(error?.localizedDescription)")
}
}
dataTask.resume()
}
}
extension NetworkService
{
static func parseJSONFromData(jsonData: NSData?) -> [String : AnyObject]?
{
if let data = jsonData {
do {
let jsonDictionary = try NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers) as? [String : AnyObject]
return jsonDictionary
} catch let error as NSError {
print("Error processing json data: \(error.localizedDescription)")
}
}
return nil
}
}
This code for get image that use in detailViewController
if episode.thumbnailURL != nil {
if let thumbnailURL = episode.thumbnailURL {
let networkService = NetworkService(url: thumbnailURL)
networkService.downloadImage({ (data) in
//thumbnailImageView.image = episode.thumbnailURL
let image = UIImage(data: data)
dispatch_async(dispatch_get_main_queue(), {
self.thumbnailImageView.image = image
})
})
}
}
You can get detail of your barcode like this from your array of dictionary.
func barcodeReaded(barcode: String) {
print("Barcode is: \(barcode)")
showCodeLabel.text = barcode
let episodes = Episode.downloadAllEpisodes()
var filteredEpisodes = episodes.filter({ $0.testCode == barcode })
if filteredEpisodes.count > 0 {
titleLabel.text = filteredEpisodes[0].title
drugLabel.text = filteredEpisodes[0].drug
priceLabel.text = filteredEpisodes[0].price
}
}
Try it. Hope it may help you.
var resultData = NSDictionary()
var episode = NSArray()
func loadDataFromJSON(){
// put your json to resultData
// Now resultData holds whole json object
// get episode array from resultData
episode = resultData.objectForKey("episode") as! NSArray
}
func traverseThroughEpisode(){
for i in 0..< episode.count {
// retrive testCode like that & set it whatever you want
let testCode = episode.objectAtIndex(i).objectForKey("testCode") as! String
}
}
#IBOutlet weak var enterName: UITextField!
#IBOutlet weak var presentName: UITextView!
#IBOutlet weak var independceStatue: UITextField!
#IBOutlet weak var driverSelection: UITextField!
var entity : [Entity] = []
var nameList : [String] = []
var period1 = ""
var counting = 0
override func viewDidLoad() {
super.viewDidLoad()
let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let request = NSFetchRequest(entityName: "Entity")
var results : [AnyObject]?
do{
results = try context.executeFetchRequest(request)
} catch {
results = nil
}
if results != nil {
self.entity = results as! [Entity]
}
if !entity.isEmpty{
presentName.text = entity.last?.period1Core
}
}
func setValues() {
nameList = [enterName.text!]
}
#IBAction func setName(sender: UIButton) {
setValues()
for item in nameList{
period1 += (item + " ")
}
presentName.text = period1
enterName.text = ""
}
#IBAction func start(sender: UIButton) {
let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let entity = NSEntityDescription.insertNewObjectForEntityForName("Entity", inManagedObjectContext: context) as! Entity
entity.period1Core = presentName.text
do {
try context.save()
print("Item Saved")
} catch _ {
print("Saved Failed")
}
**Problem ->** let randomIndex = Int(arc4random_uniform(UInt32(nameList.count)))
driverSelection.text! = nameList[randomIndex]
print(randomIndex)
}
I was trying to randomly pick an element out from the array name nameList, but when I run the program and print the randomIndex, after first time I press the button it will always return last element in the array.
If I exit the simulator and run it again, when I press the button it will return me fatal error Array Index is out of range. Is there somethings wrong with my code, why am I not able to make it randomly select an element from my array?
Your setValues() function always replaces the entire array with the last name entered. That's why it seems to return the last value.
you probably meant to use nameList.append(enterName.text!) in it.
The crash upon starting may occur because nameList has not yet received a name and arc4random_uniform is being called with a parameter value of zero
I Am Querying a set of PFUsers from Parses backend datebase. I then want to place those users into a TableView, although for some reason it is only loading this first user of the query for some reason. Can somebody help, code:
struct UserMatches {
var finalMatchesName : String
var finalMatchesAge : Int
var finalMatchesLocation : PFGeoPoint
var finalMatchesImage : NSData
}
class Matches: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate, UISearchDisplayDelegate {
var user = PFUser.currentUser()
var tableView = UITableView()
var userMatches = [UserMatches]()
override func viewDidLoad() {
super.viewDidLoad()
matchedUsers()
createTableView()
}
func createTableView() {
tableView.frame = CGRectMake(0, 10, self.view.frame.width, self.view.frame.height - 10)
tableView.dataSource = self
tableView.delegate = self
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.userMatches.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell
let userDetails = self.userMatches[indexPath.row]
//Name
var nameLabel = UILabel(frame: CGRectMake(15, 3, cell.frame.width / 1.2, cell.frame.height / 2))
nameLabel.font = UIFont(name: Font.FuturaBlack, size: 20)
nameLabel.numberOfLines = 1
nameLabel.text = userDetails.finalMatchesName
nameLabel.adjustsFontSizeToFitWidth = true
nameLabel.textAlignment = NSTextAlignment.Left
//Distance
var distanceLabel = UILabel(frame: CGRectMake(15, nameLabel.frame.height + 3, cell.frame.width / 1.2, cell.frame.height / 3))
distanceLabel.font = UIFont(name: Font.FuturaMedium, size: 16)
distanceLabel.numberOfLines = 1
distanceLabel.text = "0.25 Miles Away"
distanceLabel.adjustsFontSizeToFitWidth = true
distanceLabel.textAlignment = NSTextAlignment.Left
//image
var imageView = UIImageView(frame: CGRectMake(cell.frame.origin.x + cell.frame.width - cell.frame.height - 5, 5, cell.frame.height - 10, cell.frame.height - 10))
let image = UIImage(named: "hot.png")
var images = UIImage(data: userDetails.finalMatchesImage)
imageView.image = images
imageView.layer.cornerRadius = imageView.frame.size.width / 2
imageView.clipsToBounds = true
imageView.contentMode = .ScaleAspectFill
cell.addSubview(imageView)
cell.addSubview(distanceLabel)
cell.addSubview(nameLabel)
return cell
}
func matchedUsers() {
//Query Matches
var matchesIdQuery = PFUser.query()
matchesIdQuery.whereKey("objectId", equalTo: user.objectId)
if var result = matchesIdQuery.getFirstObject() {
let matchesId = result["matches"] as [String]
let matchesQuery = PFUser.query()
matchesQuery.whereKey("objectId", containedIn: matchesId)
let finalResult = matchesQuery.findObjects()
if finalResult.count > 0 {
for finalMatches in finalResult {
let matchesImageFile = finalMatches["image"] as PFFile
if let finalMatchesImageFile = matchesImageFile.getData() {
println(finalMatches.count) //Prints 2
self.userMatches = [UserMatches(finalMatchesName: finalMatches.username, finalMatchesAge: finalMatches["age"] as Int, finalMatchesLocation: finalMatches["location"] as PFGeoPoint, finalMatchesImage: finalMatchesImageFile)]
println(self.userMatches.count) //Prints 1
self.tableView.reloadData()
}
}
}
}
}
}
The problem is coming where I am trying to load the UserMatches inside the matchedUsers function, although it is only loading one user, not all of the users I have queried.
It looks like you're assigning a single value to your array in your loop (in matchedUsers()) instead of appending to it.
Try replacing:
self.userMatches = [UserMatches(finalMatchesName: finalMatches.username, finalMatchesAge: finalMatches["age"] as Int, finalMatchesLocation: finalMatches["location"] as PFGeoPoint, finalMatchesImage: finalMatchesImageFile)]
with:
self.userMatches.append(UserMatches(finalMatchesName: finalMatches.username, finalMatchesAge: finalMatches["age"] as Int, finalMatchesLocation: finalMatches["location"] as PFGeoPoint, finalMatchesImage: finalMatchesImageFile))
Here is my code to do that:
import UIKit
import Photos //Photos.h del framework Photos
import MediaPlayer
import AssetsLibrary
let reuseIdentifier = "PhotoCell"
let albumName = "My App"
class PhotosViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var assetCollection:PHAssetCollection!
var photoAsset:PHFetchResult!
var imageManager = PHImageManager.defaultManager()
var albumFound:Bool = false
#IBOutlet weak var collectionView: UICollectionView!
#IBAction func creaFilmato(sender: AnyObject) {
println("Crea il tuo filmato")
/* With a static array works perfectly
let img1:UIImage = UIImage(named: "image1.jpg")!
let img2:UIImage = UIImage(named: "image2.jpg")!
let img3:UIImage = UIImage(named: "image3.jpg")!
var array:Array<UIImage> = [img1,img2,img3]*/
let img1:UIImage = UIImage(named: "image1.jpg")!
let settings:NSDictionary = CEMovieMaker.videoSettingsWithCodec(AVVideoCodecH264, withWidth: img1.size.width, andHeight: img1.size.height)
let prova = CEMovieMaker(settings: settings)
prova.createMovieFromImages([self.photoAsset.copy()], withCompletion: {(success:Bool, fileURL:NSURL!) in
if(success){
self.viewMovieAtURL(fileURL)
/*// Salvo il filmato in cameraRoll
let library:ALAssetsLibrary = ALAssetsLibrary()
library.writeVideoAtPathToSavedPhotosAlbum(fileURL, completionBlock: {(assetURL:NSURL!, error) in
if((error) != nil) {
println("Errore nel salvataggio del filmato %#",error)
}
})*/
}
})
println("Esportato!")
}
func viewMovieAtURL(fileURL:NSURL!)->Void {
let playerController:MPMoviePlayerViewController = MPMoviePlayerViewController(contentURL: fileURL!)
playerController.view.frame = self.view.bounds
self.presentMoviePlayerViewControllerAnimated(playerController)
playerController.moviePlayer.prepareToPlay()
playerController.moviePlayer.play()
self.view.addSubview(playerController.view)
}
In my opinion the wrong code is [self.photoAsset.copy()] because photoAsset return PHFetchResult and not an Array of UIImage. What is the code to obtain an array of images starting from a PHFetchResult in Swift?
var images = [UIImage]()
let targetSize: CGSize = // your target size
let contentMode: PHImageContentMode = // your content mode
// photoAsset is an object of type PHFetchResult
photoAsset.enumerateObjectsUsingBlock {
object, index, stop in
let options = PHImageRequestOptions()
options.synchronous = true
options.deliveryMode = .HighQualityFormat
PHImageManager.defaultManager().requestImageForAsset(object as PHAsset, targetSize: targetSize, contentMode: contentMode, options: options) {
image, info in
images.append(image)
}
}
This is how I do it with Swift 4.2
let fetchOptions = PHFetchOptions()
let allPhotos = PHAsset.fetchAssets(with: .image, options: fetchOptions)
let targetSize = CGSize(width: 100, height: 100) // your target size
allPhotos.enumerateObjects {
object, index, stop in
var thumbnail = UIImage()
let options = PHImageRequestOptions()
options.isSynchronous = true
options.deliveryMode = .highQualityFormat
PHImageManager.default().requestImage(for: object, targetSize: targetSize, contentMode: .aspectFill, options: options, resultHandler: { image, _ in
thumbnail = image!
})
}
Hope this help!