how to append something to array correctly? - arrays

I'm going to make a custom cell, already have some labels on it, then I create a cell object and array, try to append that object to array then show on table, but after append, there's no content in my array's properties
I've tried to find out solutions but likely no one has these problems
//tableview implement
var recordCell : [RecordCell] = []
let note = RecordCell()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.recordCell.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "recordCell",for: indexPath) as! RecordCell
let indexPath = indexPath.row
cell.recordFileName?.text = self.recordCell[indexPath].recordFileName?.text
cell.recordDate?.text = self.recordCell[indexPath].recordDate?.text
cell.delegate = self
cell.playBtn.tag = indexPath
return cell
}
//append to array
let alertController = UIAlertController(title: "請輸入錄音名稱", message: "錄音名稱", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default) { (_) in
var name : String = ""
if(alertController.textFields![0].text == ""){
name = "record"
}else{
name = alertController.textFields![0].text!
}
guard self.audioRecorder == nil else{return}
self.recordNumber += 1
self.record.isEnabled = false
self.pause.isEnabled = true
self.stop.isEnabled = true
let destinationUrl = self.getFileURL().appendingPathComponent("\(name).m4a")
let settings = [AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
AVSampleRateKey: 44100,
AVNumberOfChannelsKey: 2,
AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
]
do {
self.audioRecorder = try AVAudioRecorder(url: destinationUrl, settings: settings)
self.audioRecorder.record()
self.note.recordFileName?.text = name
self.note.recordDate?.text = self.getDate()
self.recordCell.append(self.note)
} catch {
print("Record error:", error.localizedDescription)
}
}
let cancelAction = UIAlertAction(title: "取消", style: .cancel) { (_) in
self.dismiss(animated: true, completion: {
self.audioRecorder.stop()
})
}
alertController.addTextField { (textField) in
textField.placeholder = "輸入名稱"
textField.keyboardType = .default
}
alertController.addAction(okAction)
alertController.addAction(cancelAction)
self.present(alertController,animated: true,completion: nil)
}
I expect when I append something, there's something in array

After appending a new value to the array, call insertRows method like this
self.recordCell.append(self.note)
self.tableView.insertRows(at: [IndexPath(row: recordCell.count-1, section: 0)], with: .automatic)

I didnt see anything wrong.
Are you sure your code is called? Try giving a print() right before adding and see if it's called.
Maybe it's not called because of guard self.audioRecorder == nil else{return}

Related

Issue building proper array from tableview selections

Essentially I am adding or removing the cell values to an array that is built up based on which cells are selected/deselected.
I need my array to look like this:
[{"value":"One","id":"1"},{"value":"two","id":"4"}]
Currently it looks like this:
["One", "two"]
Currently the array does not include the struct titles (id and value) and does not include the curly brackets. The values for the id and values are coming from the array populating the tableview. How can this be done?
My code so far:
var structure = [Struct]()
var selectionArray: [String] = []
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
cell!.accessoryType = .checkmark
let item = structure[indexPath.row]
let cellvalue = item.value
selectionArray.append(cellvalue)
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
cell!.accessoryType = .none
let item = structure[indexPath.row]
let cellvalue = item.value
if let index = selectionArray.index(of: cellvalue) {
selectionArray.remove(at: index)
}
}
struct Struct: Decodable {
let id: Int
let value: String
}
You don't need to store the selectionArray array as a property at all. You can use indexPathsForSelectedRows to get all the selected rows. So you can generate the array whenever you need it.
let selectedIndexPaths = tableView.indexPathsForSelectedRows ?? []
// this contains the selected structs
let selectedStructs = selectedIndexPaths.map { structure[$0.row] }
Now you can encode it to JSON:
// remember to conform Struct to Codable!
let encoder = JSONEncoder()
do {
let jsonData = try encoder.encode(selectedStructs)
// if you want to see the encoded JSON string:
print(String(data: jsonData, encoding: .utf8)!)
} catch {
print(error)
}

Search bar in Table view sends wrong data to another Table View

I have one tableview containing data that is fed from an Array with 14 entries. I have added a search bar where I can filter this data and this works fine, but when I try to send the filtered data to a second table view, the data that is sent is the count of my filtered data. So if I search something starting with G(13th and 14th place in my array), that brings back two results which is fine but when I choose the first entry off my filtered data(the two results), the data that is passed to the second Table View is the [0] entry(A) of my initial TVC and not the 13th(G12).So depending on the filtered data I always get the first few entries of my initial array.
struct ImageForManuf {
let image: UIImage
let name: String
init(nameInit: String) {
self.name = nameInit
image = UIImage(named: nameInit)!
}
}
struct SecondTable {
var secondTitle : [String]
var pic : [UIImage?]
}
//for search bar
#IBOutlet weak var searchBar: UISearchBar!
var filteredData: [ImageForManuf]!
var searching = false
var firstArray = [ImageForManuf]()
//we are adding elements on the SecondTable structure
var secondArray = [SecondTable]()
override func viewDidLoad() {
super.viewDidLoad()
//for search bar
searchBar.delegate = self
filteredData = firstArray
firstArray = [ "A","A2","B3","B4","B5","C6","C7","D8","E9","F10","F11","G12","G13","H14",
].map(ImageForManuf.init(nameInit:))
filteredData = firstArray
secondArray = [SecondTable(secondTitle: ["A1"],
pic: [UIImage(named: "A1")]),
SecondTable(secondTitle: ["B1","B2","B3"],
pic: [UIImage(named: "B1"),UIImage(named: "B2"),UIImage(named: "B3")]),
SecondTable(secondTitle: ["C1","C2"],
pic: [UIImage(named: "C1"),pic: [UIImage(named: "C2")]),
SecondTable(secondTitle: ["D1"],
pic: [UIImage(named: "D1"),
SecondTable(secondTitle: ["E1"],
pic: [UIImage(named: "E1"),
SecondTable(secondTitle: ["F1","F2"],
pic: [UIImage(named: "F1"),pic: [UIImage(named: "F2")]),
SecondTable(secondTitle: ["G1","G2"],
pic: [UIImage(named: "G1"),pic: [UIImage(named: "G2")]),
SecondTable(secondTitle: ["H1"],
pic: [UIImage(named: "H1")
]
This is my TV configuration
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
if searching
{
return filteredData.count
}else{
return firstArray.count
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let Cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TableTableViewCell
Cell.textLabel?.textColor = .systemBlue
Cell.textLabel?.font = .boldSystemFont(ofSize: 20)
if searching
{
Cell.textLabel?.text = filteredData[indexPath.row].name
Cell.imageManuf?.image = filteredData[indexPath.row].image
}else{
Cell.textLabel?.text = firstArray[indexPath.row].name
Cell.imageManuf?.image = filteredData[indexPath.row].image
}
return Cell
}
//we need to create a variable that can hold the destination view controller
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if searching {
let row = self.tableView?.indexPathForSelectedRow?.row ?? 0
let destViewController = segue.destination as! SecondTableViewController var secondTableArray : SecondTable
secondTableArray = secondArray[row]
destViewController.secondTableVcArray = secondTableArray.secondTitle
destViewController.detailVcArray = thirdArray[row]
}else{
let row = self.tableView?.indexPathForSelectedRow?.row ?? 0
let destViewController = segue.destination as! SecondTableViewController
var secondTableArray : SecondTable
secondTableArray = secondArray[row]
secondTableArray created in SecondTableViewController
destViewController.secondTableVcArray = secondTableArray.secondTitle
destViewController.detailVcArray = thirdArray[row]
}
}
Lastly this is my searchBar configuration
//Mark: Search Bar config
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filteredData = firstArray.filter({$0.name.lowercased().prefix(searchText.count) == searchText.lowercased()})
searching = true
//to reload the data
self.tableView.reloadData()
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searching = false
searchBar.text = ""
tableView.reloadData()
}
This is the second TVC:
class SecondTableViewController: UITableViewController {
//we are loading the secondArray via the secondTableVcArray
var secondTableVcArray = [String]()
//we are loading the thirdArray via the detailVcArray
var detailVcArray : [DetailView]?
override func viewDidLoad() {
super.viewDidLoad()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return secondTableVcArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "secondCell", for: indexPath) as! SecondTableViewCell
cell.textLabel?.textColor = .white
cell.textLabel?.font = .boldSystemFont(ofSize: 20)
//we load the data of the secondTableVcArray to our cell
cell.textLabel?.text = secondTableVcArray[indexPath.row]
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let row = self.tableView?.indexPathForSelectedRow?.row else {
print("Error: problem with second table view or selection")
return
}
guard let dest = segue.destination as? DetailsViewController else {
print("Error: couldn't find expected DetailsViewController")
return
}
guard let details = detailVcArray else {
print("Error: data not set for SecondTableViewController")
return
}
dest.displayDetail = details[row]
}
}
Can somebody help with the row element of my prepareforSeque method and advice the syntax on how to get the indexPath of my firstArray as #vadian suggested? The second condition works fine(not searching) but I don't seem to be able to pull the right item from my DataSource in the searching condition.

How to pull out Data Array from CoreData TableView array, put it into a new Array and export it as csv?

I have an app that takes user inputs in an alertController, and then this values will be stored in CoreData which is then displayed in a tableview. I concatenated all the strings to gather with a comma as separator to make it easier for me to export a csv. However, when I print out the CoreData entity, I get an array that is quite complicated. The array looks like this:
[ (entity: AlarmItems; id: 0xc2bccd37cb753acb ; data: {
alarmAttributes = "Example Name, 24/11/2019, 1500, True, NIL";
}), (entity: AlarmItems; id: 0xc2bccd37cb653acb ; data: {
alarmAttributes = "Example , 12/12/2019, 24/11/2019, True, NIL";
})]
I would like to pull out just that parts after alarmAttributes to be exported into a CSV for further use.
I looked at NSEntityMapping but that did not help me. I'm quite stuck right now. I do not know how to approach the problem. Is my approach even correct in the first place? Is it even possible to export a csv using a an array that I create? The idea is to have the csv be stored in the iOS Device which can then be emailed elsewhere.
My ViewController:
class ViewController: UITableViewController {
var alarmItems: [NSManagedObject] = []
let cellId = "cellId"
override func viewDidLoad() {
super.viewDidLoad()
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "AlarmItems")
do {
alarmItems = try managedContext.fetch(fetchRequest)
} catch let err as NSError {
print("Failed to fetch items", err)
}
}
#objc func addAlarmItem(_ sender: AnyObject) {
print("this works")
let alertController = UIAlertController(title: "Add New Item", message: "Please fill in the blanks", preferredStyle: .alert)
let saveAction = UIAlertAction(title: "Save", style: .default) { [unowned self] action in
//combined string of attributes
let myStrings: [String] = alertController.textFields!.compactMap { $0.text }
let myText = myStrings.joined(separator: ", ")
self.save(myText)
self.tableView.reloadData()
}
let cancelAction = UIAlertAction(title: "Cancel", style: .destructive, handler: nil)
alertController.addTextField { (textField) in
textField.placeholder = "Enter Name of Engineer"
}
alertController.addTextField { (textField) in
textField.placeholder = "Enter Date of Alarm in DD/MM/YYYY"
}
alertController.addTextField { (textField) in
textField.placeholder = "Enter Time of Alarm in 24h (eg: 2300)"
}
alertController.addTextField { (textField) in
textField.placeholder = "Please indicate True/False (type True or False)"
}
alertController.addTextField { (textField) in
textField.placeholder = "Insert comments (if any), or NIL"
}
alertController.addAction(saveAction)
alertController.addAction(cancelAction)
present(alertController, animated: true, completion: nil)
}
func save(_ itemName: String) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "AlarmItems", in: managedContext)!
let item = NSManagedObject(entity: entity, insertInto: managedContext)
item.setValue(itemName, forKey: "alarmAttributes")
do {
try managedContext.save()
alarmItems.append(item)
} catch let err as NSError {
print("Failed to save an item", err)
}
}
#objc func exportCSV(_ sender: AnyObject) {
//will work on exporting csv in the future
return
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return alarmItems.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
let alarmItem = alarmItems[indexPath.row]
cell.textLabel?.text = alarmItem.value(forKeyPath: "alarmAttributes") as? String
return cell
}
}

How to bold first word of array?

var userComment = ["Time these make me.jenny is ","I can't she did it.", "Hey! what a great play made by brad", "I can't she .", "Time like make is a badass", "I can't it.", "She is a mean chose to place","Time me a badass", "Wow! I am just like jenny.I would shit", "I can't did it."]
first word of array in capital ex [TIME,I,HEY,WOW] other is same as written
var attributeCommentArray:[NSAttributedString] = []
override func viewDidLoad() {
super.viewDidLoad()
for comment in userComment {
if comment.contains("") {
let firstCharacter = comment.components(separatedBy: "").first ?? ""
let myString:NSMutableAttributedString = NSMutableAttributedString.init(string:comment)
myString.addAttribute(NSAttributedString.Key.font,
value: UIFont(
name: "HelveticaNeue-Bold",
size: 18.0)!,
range: NSRange(
location:0,
length:firstCharacter.count))
attributeCommentArray.append(myString)
} else {
attributeCommentArray.append(NSMutableAttributedString.init(string:comment))
}
}
// self.navTitleWithImageAndText(titleText: "oneTwoThree", imageName: "")
self.navigationController?.navigationBar.isHidden = false
// chatView.makeCornerRadius(self.chatView.layer.bounds.height / 2)
chatView.layer.borderWidth = 1
chatView.setCorner(borderWidth: 1, borderColor: UIColor.darkGray.cgColor, cornerRadius: 25, clip: true)
self.tblView.rowHeight = UITableView.automaticDimension
self.tblView.estimatedRowHeight = 60
tblView.delegate = self
tblView.dataSource = self
self.loadXib()
}
private func loadXib() {
tblView.loadXibForCellResuse(LiveCell.identifier)
}
}
extension LiveChatVC:UITableViewDelegate,UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.userName.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tblView.dequeueReusableCell(withIdentifier: "LiveCell", for: indexPath) as! LiveCell
// cell.userName.text = self.userComment[indexPath.row]
// cell.userName.attributedText = myMutableString
cell.userName.attributedText = attributeCommentArray[indexPath.row]
return cell
}
}
[This is the implementation of code which is given by you please help it will not working in my controller it will print exactly the same text which is on the label,This is the implementation of code which is given by you please help it will not working in my controller it will print exactly the same text which is on the label]
Try the following code
var userComment = ["Time these make me.jenny is ","I can't she did it.", "Hey! what a great play made by brad", "I can't she .", "Time like make is a badass", "I can't it.", "She is a mean chose to place","Time me a badass", "Wow! I am just like jenny.I would shit", "I can't did it."]
var attributeCommentArray:[NSAttributedString] = []
for comment in userComment
{
if comment.contains(" ")
{
let firstWord = comment.components(separatedBy: " ").first ?? ""
let myString:NSMutableAttributedString = NSMutableAttributedString.init(string: comment)
myString.addAttribute(NSAttributedString.Key.font,
value: UIFont(
name: "HelveticaNeue-Bold",
size: 18.0)!,
range: NSRange(
location:0,
length:firstWord.count))
attributeCommentArray.append(myString)
}
else
{
attributeCommentArray.append(NSAttributedString.init(string: comment))
}
}
Create Attrinbuted String array and use that array in uitableview cell label
cellForRowMethod
lable.attributedText = attributeCommentArray[indexPath.row];

Append Array with UserDefaults input text

I have an Array of strings which is populating a collection view and that works well. The issue is I want to append that array with Strings that is saved in user defaults from user input textfield. I am getting the UserDefault data, The issue is it is not showing up in seperate collection view cell. it is getting attached at the end of each string in the current cells. Thanks in advance, any help would be appreciated.
This is what I tried so far:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
let defaults = UserDefaults.standard
let value = defaults.string(forKey: "Gratitude")
print(value!)
//Array that I am trying to append with userdefault data
gratitudeArray.append(value!)
// Configure the cell
cell.cellLabel.text = gratitudeArray[indexPath.row]
return cell
}
// I am geeting user input from alert and saving in userdefaults like this:
func presentAlert() {
let alertController = UIAlertController(title: "", message: "Create your own Gratitude:", preferredStyle: .alert)
let confirmAction = UIAlertAction(title: "Save", style: .default) { (_) in
if let field = alertController.textFields?[0] {
// store data
UserDefaults.standard.set(field.text, forKey: "Gratitude")
UserDefaults.standard.synchronize()
} else {
print()
}
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (_) in }
alertController.addTextField { (textField) in
//print(textField.text!)
//textField.placeholder = ""
}
alertController.addAction(confirmAction)
alertController.addAction(cancelAction)
self.present(alertController, animated: true, completion: nil)
}
Store String in ViewDidLoad() like below:
var strValue: String = ""
override func viewDidLoad() {
super.viewDidLoad()
let defaults = UserDefaults.standard
strValue= defaults.string(forKey: "Gratitude")
}
and display in cellForItemAt like this:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
cell.cellLabel.text = gratitudeArray[indexPath.row] + " " + strValue
return cell
}
If I understand your problem correctly, you want number of cells to increase by one (the value you extract out of UserDefaults). For that, you should append it some place which is outside collection view's data source methods (like viewDidLoad()) and then reload your collection view.
override func viewDidLoad() {
super.viewDidLoad()
let defaults = UserDefaults.standard
strValue = defaults.string(forKey: "Gratitude")
gratitudeArray.append(strValue)
self.collectionView.reloadData()
}
I solved the issue by creating an array in my alert controller to hold user input and then save that array to user defaults.
func presentAlert() {
let alertController = UIAlertController(title: "", message: "Create your own Gratitude:", preferredStyle: .alert)
let confirmAction = UIAlertAction(title: "Save", style: .default) { (_) in
if let field = alertController.textFields {
let textFieldArray = field as [UITextField]
let text = textFieldArray[0].text
let key = "Gratitude"
var myArray = UserDefaults.standard.array(forKey: key) ?? []
myArray.append(String(describing: text!))
UserDefaults.standard.set(myArray, forKey: key)
print(myArray)
} else {
print()
}
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (_) in }
alertController.addTextField { (textField) in
}
alertController.addAction(confirmAction)
alertController.addAction(cancelAction)
self.present(alertController, animated: true, completion: nil)
}

Resources