Xcode is sending me the error "fatal error: init(coder:) has not been implemented error" despite being implemented. I don't know where the problem is.
final class newTableViewController: UITableViewController {
#IBOutlet var inputFormTableView: UITableView!
let form: Form
let note = Note(name: "")
init(form: Form) {
self.form = form
super.init(style: .grouped)
}
convenience init(note: Note) {
let form = Form(sections: [
FormSection(items: [
TextInputFormItem(text: note.name,
placeholder: "Add title",
didChange: { _ in print("hello")})
])
])
self.init(form: form)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
inputFormTableView.rowHeight = 44
inputFormTableView.register(TextInputTableViewCell.self, forCellReuseIdentifier: ReuseIdentifiers.textInput.rawValue)
let new = newTableViewController(note: note)
print(new.note.name)
}
private enum ReuseIdentifiers: String {
case textInput
}
// MARK: - Table view data source
private func model(at indexPath: IndexPath) -> FormItem {
return form.sections[indexPath.section].items[indexPath.item]
}
override func numberOfSections(in tableView: UITableView) -> Int {
return form.sections.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return form.sections[section].items.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let object = model(at: indexPath)
if let textRow = object as? TextInputFormItem {
let cell = tableView.dequeueReusableCell(withIdentifier: ReuseIdentifiers.textInput.rawValue, for: indexPath) as! TextInputTableViewCell
cell.configure(for: textRow)
return cell
}
else {
fatalError("Unknown model \(object).")
}
}
}
I am trying to make UITableView act like an input form. For doing this, I am following this tutoriel : https://augmentedcode.io/2018/11/04/text-input-in-uitableview/. Everything works in the sample project but not mine.
You haven't implemented it, you are just throwing a fatalError, when running from stroy-board this init is getting executed, replace the following code:
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
With this:
required init?(coder: NSCoder) {
form = Form()
super.init(coder: coder)
}
Related
I'm building an app that works with GEODb Rapid API. It should decode country names and put them in TableView Cells.
Working with MVVM pattern and getting the result of api in my modelView.
My modelView looks as below:
class HomePageViewModel {
var color = UIColor.white
var apiResult: APIResult?
init() {
getAPIResult()
}
private func getAPIResult() {
APIHandler.urlRequest { results in
print(results)
self.apiResult = results
}
}
}
I do get the data. Printing the result is shown as below on terminal.
2021-11-27 19:01:07.687230+0300 Countries[32016:2991279] [boringssl] boringssl_metrics_log_metric_block_invoke(144) Failed to log metrics
APIResult(data: [Countries.APIResultKeys(name: "Vatican City"), Countries.APIResultKeys(name: "Ethiopia"), Countries.APIResultKeys(name: "Montenegro"), Countries.APIResultKeys(name: "Namibia"), Countries.APIResultKeys(name: "Ghana")])
2021-11-27 19:03:28.937963+0300 Countries[32016:2991
I'm aware of boringss1 issue but will handle it later for now.
My main class is as below. I am initializing the class with the viewModel. So I'm getting the data from the main model.
class HomePageViewController: UIViewController {
deinit {
print("HomePageViewController Deinit")
}
//MARK: - Computed Properties
private lazy var countriesTableView: UITableView = {
let temp = UITableView()
temp.translatesAutoresizingMaskIntoConstraints = false
temp.delegate = self
temp.dataSource = self
temp.register(CountriesTableViewCell.self, forCellReuseIdentifier: CountriesTableViewCell.identifier) //Registering Cell
temp.separatorStyle = .none // Removing lines out of tableView
return temp
}()
private var viewModel: HomePageViewModel?
//MARK: - LifeCycle
init(with viewModel: HomePageViewModel) {
self.viewModel = viewModel
super.init(nibName: nil, bundle: nil)
setupViews()
setupConstraintsForViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
I'm trying to change the text label of the cell inside my main class and via the UITableView stubs as below. But the labels are not changing. I tried to reload the table view in cellForRowAt function but when I do that my table view just disappears.
So what am I doing wrong?
Excuse me if I'm not explaining properly.
extension HomePageViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: CountriesTableViewCell.identifier, for: indexPath) as? CountriesTableViewCell else { return UITableViewCell() }
cell.countryLabel.text = viewModel?.apiResult?.data[indexPath.row].name
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
Playground Code is below.
Question I have is for the following line:
let recentItemsVC = ItemsViewController(items: recentItems, cellDescriptor: {$0.cellDescriptor })
I know ItemsViewController takes a closure for cellDescriptor, but can't wrap my head around what {$0.cellDescriptor} by itself means. There is no filter, map, compactMap, filter, etc. called here.
Two questions:
1. Playground shows (4 times). What does that mean?
2. What does passing { $0.cellDescriptor } by itself mean?
Code:
import UIKit
import PlaygroundSupport
struct Album {
var title: String
}
struct Artist {
var name: String
}
struct CellDescriptor {
let cellClass: UITableViewCell.Type
let reuseIdentifier: String
let configure: (UITableViewCell) -> ()
init<Cell: UITableViewCell>(reuseIdentifier: String, configure: #escaping (Cell) -> ()) {
self.cellClass = Cell.self
self.reuseIdentifier = reuseIdentifier
self.configure = { cell in
configure(cell as! Cell)
}
}
}
final class ItemsViewController<Item>: UITableViewController {
var items: [Item] = []
let cellDescriptor: (Item) -> CellDescriptor
var didSelect: (Item) -> () = { _ in }
var reuseIdentifiers: Set<String> = []
init(items: [Item], cellDescriptor: #escaping (Item) -> CellDescriptor) {
self.cellDescriptor = cellDescriptor
super.init(style: .plain)
self.items = items
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let item = items[indexPath.row]
didSelect(item)
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let item = items[indexPath.row]
let descriptor = cellDescriptor(item)
if !reuseIdentifiers.contains(descriptor.reuseIdentifier) {
tableView.register(descriptor.cellClass, forCellReuseIdentifier: descriptor.reuseIdentifier)
reuseIdentifiers.insert(descriptor.reuseIdentifier)
}
let cell = tableView.dequeueReusableCell(withIdentifier: descriptor.reuseIdentifier, for: indexPath)
descriptor.configure(cell)
return cell
}
}
final class ArtistCell: UITableViewCell {
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: .value1, reuseIdentifier: reuseIdentifier)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
final class AlbumCell: UITableViewCell {
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: .value2, reuseIdentifier: reuseIdentifier)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
let artists: [Artist] = [
Artist(name: "Prince"),
Artist(name: "Glen Hansard"),
Artist(name: "I Am Oak")
]
let albums: [Album] = [
Album(title: "Blue Lines"),
Album(title: "Oasem"),
Album(title: "Bon Iver")
]
enum RecentItem {
case artist(Artist)
case album(Album)
}
let recentItems: [RecentItem] = [
.artist(artists[0]),
.artist(artists[1]),
.album(albums[1])
]
extension Artist {
func configureCell(_ cell: ArtistCell) {
cell.textLabel?.text = name
}
}
extension Album {
func configureCell(_ cell: AlbumCell) {
cell.textLabel?.text = title
}
}
extension RecentItem {
var cellDescriptor: CellDescriptor {
switch self {
case .artist(let artist):
return CellDescriptor(reuseIdentifier: "artist", configure: artist.configureCell)
case .album(let album):
return CellDescriptor(reuseIdentifier: "album", configure: album.configureCell)
}
}
}
let recentItemsVC = ItemsViewController(items: recentItems, cellDescriptor: {$0.cellDescriptor })
let nc = UINavigationController(rootViewController: recentItemsVC)
nc.view.frame = CGRect(x: 0, y: 0, width: 200, height: 300)
PlaygroundPage.current.liveView = nc.view
AFAIK 4 times is the count of recentItems + 1
{$0.cellDescriptor} is a closure. Its signature is #escaping (Item) -> CellDescriptor. that means that it takes a generic type Item and returns a CellDescriptor. In this case, for each element of recentItems it will return that element's cellDescriptor. Whether it's an artist or an album, cellDescriptor is defined by this part of the code:
extension RecentItem {
var cellDescriptor: CellDescriptor {
switch self {
case .artist(let artist):
return CellDescriptor(reuseIdentifier: "artist", configure: artist.configureCell)
case .album(let album):
return CellDescriptor(reuseIdentifier: "album", configure: album.configureCell)
}
}
}
Which sets the reuseIdentifier and configures the cell by setting textLabel?.text to be either the artist's name or the title of the album.
it's that line of code:
init(items: [Item], cellDescriptor: #escaping (Item) -> CellDescriptor) {
You initialize the ItemsViewController with an array of Item and a callback method. The callback methods accepts an Item as parameter. And Item has a property named cellDescriptor
the cell is very simple, just a textLabel. i want to tap the cell and then print some words. this is a test . but the didSelectRowAtIndexPath is not work. Please tell me why, thank you !
import UIKit
import SnapKit
class ListTableViewController : UITableViewController{
var itemData: ListTableModel!
var header: UIView!
override init(style: UITableViewStyle){
super.init(style: style)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
itemData = ListTableModel()
self.tableView.dataSource = self
self.tableView.delegate = self
}
....
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("mCell", forIndexPath: indexPath)
cell.textLabel?.userInteractionEnabled = false
let listCell = cell as! ListTableViewCell
if let item = itemData.getItemData(indexPath.row) {
listCell.textLabel!.text = item.valueForKey("title") as? String
}
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("indexPathS")
}
}
Please check if self.tableView.allowsSelection = NO is not written anywhere. And in the storyboard, check if single selection is checked under Selection tab.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let text:NSString = myArray .objectAtIndex(indexPath.row) as! NSString
delegate?.myMethod(text as String)
self.navigationController?.popToRootViewControllerAnimated(true)
}
you can try this.
When I wireframe it, the cell is nested above the TableView. My project structure is that I have a main view controller and a subclass of a TableView that's also using a TableViewCell that I subclassed. Everything is in place, I have no idea why it's not showing.
import UIKit
class ViewController: UIViewController{
#IBOutlet weak var tv: TaskTableView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
My subclass of UITableView.
import UIKit
class TaskTableView: UITableView, UITableViewDelegate, UITableViewDataSource {
var title: String = ""
var detail: String = ""
var time: NSDate = NSDate()
var data = ["asdf","asdf","sadf"]
init(frame: CGRect, title: String, detail: String, time: NSDate)
{
self.title = title
self.detail = detail
self.time = time
super.init(frame: frame, style: UITableViewStyle.Plain)
}
required init?(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return data.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
tableView.registerNib(UINib(nibName: "NewTVCell", bundle: nil), forCellReuseIdentifier: "toDoCell")
let cell = tableView.dequeueReusableCellWithIdentifier("toDoCell", forIndexPath: indexPath) as! NewTVCell
cell.title.text = data[indexPath.row]
return cell
}
I'm trying to implement a refresh button in navigationBar, so when the button is clicked I need to reload the tableView, I have this code, but its not working, for sure the func is called because I put a println inside, Im also declare the reload on ViewDidAppear, but nothing happens :
import UIKit
class CommentsTableViewController: PFQueryTableViewController {
#IBOutlet var tabletView: UITableView!
var object : PFObject?
// Initialise the PFQueryTable tableview
override init(style: UITableViewStyle, className: String!) {
super.init(style: style, className: className)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
// Define the query that will provide the data for the table view
override func queryForTable() -> PFQuery {
var query = PFQuery(className: "gameScore")
query.orderByDescending("createdAt")
query.whereKey("ObjectId", equalTo: "XDP1rc8Rmq")
return query
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(animated: Bool) {
// Refresh the table to ensure any data changes are displayed
self.tabletView.reloadData()
println("Reloading")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFTableViewCell? {
var cell = tableView.dequeueReusableCellWithIdentifier("CommentCellIdentifier") as! CommentsCell!
if cell == nil {
cell = CommentsCell(style: UITableViewCellStyle.Default, reuseIdentifier: "CommentCellIdentifier")
}
if let object = object?["user"] as? String {
cell?.username?.text = object
}
return cell
}
func buttonIconAction(sender:UIButton!)
{
println("Reloading")
self.tableView.reloadData()
}
}
Any suggestions?
Thanks.
Instead of calling tableView.reloadData(), it looks like PFQueryTableViewController has a method called loadObjects(). Try calling that instead.