HI, so this is my vc for a view where I save info about a plane (the type and rego). It saves the plane and deletes and you can close the app and come back and it saves it there in the core data model but I have a weird problem. After you make a plane and it shows in the table view and add a few more planes (table view cell which has info) then the labels which display the info start to overlap with what should be deleted information. The pictures bellow show what I mean. Any help would be greatly appreciated.
var context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var typeField: UITextField?
var regoField: UITextField?
@IBAction func addPlaneButton(_ sender: Any) {
let alertController = UIAlertController(title: "New Plane", message: "Please Input The Type And Registration", preferredStyle: .alert)
alertController.addTextField(configurationHandler: typeField)
alertController.addTextField(configurationHandler: regoField)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
let saveAction = UIAlertAction(title: "Save", style: .default, handler: self.savePlane)
alertController.addAction(cancelAction)
alertController.addAction(saveAction)
self.present(alertController, animated: true)
print("Add Plane Pressed")
}
func typeField(textField: UITextField!) {
typeField = textField
typeField?.placeholder = "Aircraft Type"
}
func regoField(textField: UITextField!) {
regoField = textField
regoField?.placeholder = "Aircraft Registration"
}
@IBOutlet weak var tableView: UITableView!
var timer = Timer()
let utcItem = UIBarButtonItem()
let utcLbl = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
//Table View
tableView.delegate = self
tableView.dataSource = self
self.tableView.rowHeight = 88
setupView()
}
//////Functions////
func setupView() {
//UTC Time Formatter
let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
dateFormatter.dateFormat = "HH:mm"
_ = Timer.scheduledTimer(timeInterval: 0.05, target: self, selector: #selector(updateTime), userInfo: nil, repeats: true)
//UTC Time
utcLbl.frame = CGRect(x: 0, y: 0, width: 100, height: 20)
utcLbl.text = "\(dateFormatter.string(from: Date())) UTC"
utcItem.customView = utcLbl
utcLbl.backgroundColor = UIColor.init(fromHexCode: "4FB7F1")
utcLbl.layer.cornerRadius = 10
utcLbl.textAlignment = .center
utcLbl.layer.masksToBounds = true // Or utcLbl.clipsToBounds = true
self.navigationItem.setLeftBarButtonItems([utcItem], animated: true)
// Large Title
self.title = "Planes"
self.navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedString.Key.font: UIFont(name: "Avenir-Black", size: 35)!]
self.navigationController?.navigationBar.prefersLargeTitles = true
let customBlue = UIColor(red:0.08, green:0.38, blue:0.75, alpha:1.0)
navigationController?.navigationBar.barTintColor = customBlue
}
//Constant UTC Time Lbl
@objc func updateTime() {
let formatter = DateFormatter()
formatter.timeZone = TimeZone(abbreviation: "UTC")
formatter.dateFormat = "HH:mm"
utcLbl.text = formatter.string(from: Date()) + " UTC"
}
//Save the Plane Info
func savePlane(alert: UIAlertAction) {
if typeField?.text != "" || regoField?.text != "" {
let newLog = NSEntityDescription.insertNewObject(forEntityName: "Planes", into: context)
newLog.setValue(self.typeField?.text, forKey: "type")
newLog.setValue(self.regoField?.text, forKey: "rego")
do{
try context.save()
}
catch {
print(error)
}
//Making the table update itself when user logs the plane
self.fetchData()
self.tableView.reloadData()
}
print("Plane Saved")
}
func fetchData() {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
do{
planeArray = try context.fetch(Planes.fetchRequest())
}
catch{
print(error)
}
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
if editingStyle == .delete {
let save = planeArray[indexPath.row]
context.delete(save)
(UIApplication.shared.delegate as! AppDelegate).saveContext()
do {
planeArray = try context.fetch(Planes.fetchRequest())
}
catch {
print(error)
}
tableView.reloadData()
}
}
//Table View Functions
public func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (planeArray.count)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
//Plane Pic
let planeView = UIImageView()
planeView.frame = CGRect(x: 0, y: 0, width: 69, height: 67)
//planeView.center = CGPoint(x: cell.center.x - 150, y: cell.center.y)
planeView.center = CGPoint(x: cell.center.x - 145, y: cell.center.y)
let planeImage: UIImage = UIImage(named: "plane")!
planeView.image = planeImage
cell.addSubview(planeView)
//Type Label
let type = UILabel()
type.frame = CGRect(x: 0, y: 0, width: 45, height: 21)
type.center = CGPoint(x: cell.center.x - 80, y: cell.center.y - 22.5)
type.text = "Type:"
type.font = UIFont(name: "Montserrat-Medium", size: 17)
cell.addSubview(type)
//Type Answer
let typeAnswer = UILabel()
typeAnswer.frame = CGRect(x: 0, y: 0, width: 220, height: 21)
typeAnswer.center = CGPoint(x: cell.center.x + 62.5, y: cell.center.y - 22.5)
typeAnswer.text = ""
typeAnswer.font = UIFont(name: "Montserrat-Light", size: 17)
typeAnswer.textAlignment = .right
cell.addSubview(typeAnswer)
//Rego Label
let rego = UILabel()
rego.frame = CGRect(x: 0, y: 0, width: 110, height: 21)
rego.center = CGPoint(x: cell.center.x - 47.5, y: cell.center.y + 18.5)
rego.text = "Registration:"
rego.font = UIFont(name: "Montserrat-Medium", size: 17)
cell.addSubview(rego)
//rego answer
let regoAnswer = UILabel()
regoAnswer.frame = CGRect(x: 0, y: 0, width: 160, height: 21)
regoAnswer.center = CGPoint(x: cell.center.x + 92.5, y: cell.center.y + 18.5)
regoAnswer.text = ""
regoAnswer.font = UIFont(name: "Montserrat-Light", size: 17)
regoAnswer.textAlignment = .right
cell.addSubview(regoAnswer)
let save = planeArray[indexPath.row]
typeAnswer.text = save.type
regoAnswer.text = save.rego
return cell
}
override func viewWillAppear(_ animated: Bool) {
//Making the table update itself when user logs the plane
fetchData()
tableView.reloadData()
}
}
UITableView
reuses the cells. In your case, when the cells are created the first time, you add a UILabel
to it. The next time this cell is loaded, UITableView
reuses the existing cell and cellForRowAt
adds another UILabel
to this cell. The proper implementation is to create a custom UITableViewCell
and reset the value of all the attributes in cellForRowAt
method.
You can try something like below (please note that this is just a rough implementation and it is assumed that you know the basics of ios programming. If that is not the case, I'd recommend researching it a bit):
Add a custom tableview cell
class CustomTableViewCell: UITableViewCell {
@IBOutlet weak var imgViewPlane: UIImageView!
@IBOutlet weak var lblType: UILabel!
@IBOutlet weak var lblTypeAnswer: UILabel!
@IBOutlet weak var lblRego: UILabel!
@IBOutlet weak var lblRegoAnswer: UILabel!
}
Create a dynamic prototype cell in storyboard tableview and link the IBOutlet
s. Then in your cellForRowAt
, do something like this
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomTableViewCell
cell.imgViewPlane.image = planeImage
cell.lblType.text = "Type:"
cell.lblTypeAnswer.text = planeArray[indexPath.row].type
cell.lblRego.text = "Registration:"
cell.lblRegoAnswer.text = planeArray[indexPath.row].rego
return cell
}