Realm init for storyboard tableview - ios

I'm having a problem implementing a synced realm with a storyboard ViewController.
Specifically I'm unsure how to provide the initializers.
If I create the ViewController programmatically I can use the following and everything works fine. However, I'm working with a storyboard. This code is provided by the realm tutorial.
import UIKit
import RealmSwift
class ItemsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let realm: Realm
let items: Results<Item>
let refresh = UIRefreshControl()
let tableView = UITableView()
var notificationToken: NotificationToken?
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
let syncConfig = SyncConfiguration(user: SyncUser.current!, realmURL: Constants.REALM_URL)
self.realm = try! Realm(configuration: Realm.Configuration(syncConfiguration: syncConfig, objectTypes:[Item.self]))
self.items = realm.objects(Item.self).sorted(byKeyPath: "body", ascending: true)
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
notificationToken?.invalidate()
}
override func viewDidLoad() {
super.viewDidLoad()
title = "Items to Get Done"
tableView.dataSource = self
tableView.delegate = self
view.addSubview(tableView)
tableView.frame = self.view.frame
....
This does not work for a storyboard ViewConroller since (as I understand) the storyboard is configuring and initializing the ViewConroller.
My question then is, how and where do I write the init?

You can write realm loading in your ViewDidLoad.
import UIKit
import RealmSwift
class ItemTableViewController: UITableViewController {
var realm!
var items: Results<Item>?
override func viewDidLoad() {
super.viewDidLoad()
self.loadItems()
}
//Readcategory:
func loadItems() {
let syncConfig = SyncConfiguration(user: SyncUser.current!, realmURL: Constants.REALM_URL)
self.realm = try! Realm(configuration: Realm.Configuration(syncConfiguration: syncConfig, objectTypes:[Item.self]))
self.items = realm.objects(Item.self).sorted(byKeyPath: "body", ascending: true)
self.tableView?.reloadData()
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.items?.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = super.tableView(tableView, cellForRowAt: indexPath) as! SwipeCell
if let item = self.items?[indexPath.row] {
cell.textLabel?.text = item.title
}
return cell
}
}

Related

Not able to use Custom Cell with UITableView

I am trying to populate uitableview with custom but getting the following error:
Fatal error: Use of unimplemented initializer 'init(style:reuseIdentifier:)' for class 'Appname.PostCellView'
Code:
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! PostCellView
return cell
}
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(PostCellView.self, forCellReuseIdentifier: "Cell")
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
Post View Cell: (this class is loaded in the File's Owner of the view)
import UIKit
protocol PostCellViewDelegate: class {
}
class PostCellView: UITableViewCell {
weak var delegate: PostCellViewDelegate?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let _ = commonInitialization()
}
func customise(imageName : String , color : UIColor, logoLabelValue : String, websiteValue: String)
{
}
func commonInitialization() -> UIView
{
let bundle = Bundle.init(for: type(of: self))
let nib = UINib(nibName: "PostCellView", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
view.frame = bounds
view.autoresizingMask = [UIViewAutoresizing.flexibleWidth, UIViewAutoresizing.flexibleHeight]
addSubview(view)
return view
}
}
Please help me finding what's wrong with my code and how I should rectify the same.
Override init(style:reuseIdentifier:)
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
// Code
}
Please check this tutorial
Please shift the call to commonInitialization() from initWithCoder to method awakeFromNib. Also remove the initWithCoder method
In your PostCellView code add this method and remove the initWithCoder.
override func awakeFromNib() {
super.awakeFromNib()
let _ = commonInitialization()
}

can we pass data from table cell to table view where both are xib files?

I want to pass table cell data (xib file) to table view (also a xib file). I have tried passing the data using the following piece of code but did not get an appropriate result.
PropertyCell.swift
import UIKit
class PropertyCell: UITableViewCell {
#IBOutlet weak var propertyCodeLbl: UILabel!
#IBOutlet weak var addressLbl: UILabel!
}
I have attached the screenshot for PropertyCell below -
PropertyCell.xib
PropertyCell.xib file
PropertyTableVC.swift
import UIKit
import Alamofire
class PropertyTableVC: UITableViewController {
#IBOutlet var propertyTabel: UITableView!
let URL_Landlord_Property_List = "http://127.0.0.1/source/api/LandlordPropertyList.php"
var count: Int = 0
var landlordPropertyArray: [PropertyList]? = []
override func viewDidLoad() {
super.viewDidLoad()
fetchData()
propertyTabel.dataSource = self
propertyTabel.delegate = self
let nibName = UINib(nibName: "PropertyCell", bundle:nil)
self.propertyTabel.register(nibName, forCellReuseIdentifier: "Cell")
}
func fetchData(){
let urlRequest = URLRequest(url: URL(string: URL_Landlord_Property_List)!)
let task = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
if error != nil{
print(error!)
return
}
print(data!)
self.landlordPropertyArray = [PropertyList]()
self.count = (self.landlordPropertyArray?.count)!
do{
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String: AnyObject]
if let datafromjson = json["landlords_property_list"] as? [[String: AnyObject]] {
print(datafromjson)
for data in datafromjson{
var property = PropertyList()
if let id = data["ID"] as? Int,let code = data["Code"] as? String, let address1 = data["Address"] as? String
{
property.id = id
property.code = code
property.address1 = address1
}
self.landlordPropertyArray?.append(property)
}
print(self.landlordPropertyArray)
}
DispatchQueue.main.async {
self.propertyTabel.reloadData()
}
}catch let error {
print(error)
}
}
task.resume()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (landlordPropertyArray?.count)!
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Configure the cell...
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! PropertyCell
cell.propertyCodeLbl.text = self.landlordPropertyArray?[indexPath.item].code
cell.addressLbl.text = self.landlordPropertyArray?[indexPath.item].address1
return cell
}
}
Attached the screenshot for Property Table below -
PropertyTableVC.xib
PropertyTableVC.xib file
Your TableViewCell :
import UIKit
protocol yourProtocolName { //add protocol here
func getDataFromTableViewCellToViewController (sender : self) //* as you need to pass the table view cell, so pass it as self
}
class PropertyCell: UITableViewCell {
#IBOutlet weak var propertyCodeLbl: UILabel!
#IBOutlet weak var addressLbl: UILabel!
var delegate : yourProtocolName? //set a delegate
override func awakeFromNib() {
super.awakeFromNib()
if delegate != nil {
delegate.getDataFromTableViewCellToViewController(sender :self) *
}
}
}
And your ViewController :
import UIKit
import Alamofire
class PropertyTableVC: UITableViewController,yourProtocolName { //conform to the protocol you created in tableViewCell
#IBOutlet var propertyTabel: UITableView!
let URL_Landlord_Property_List = "http://127.0.0.1/source/api/LandlordPropertyList.php"
var count: Int = 0
var landlordPropertyArray: [PropertyList]? = []
override func viewDidLoad() {
super.viewDidLoad()
fetchData()
propertyTabel.dataSource = self
propertyTabel.delegate = self
let nibName = UINib(nibName: "PropertyCell", bundle:nil)
self.propertyTabel.register(nibName, forCellReuseIdentifier: "Cell")
}
func fetchData(){
let urlRequest = URLRequest(url: URL(string: URL_Landlord_Property_List)!)
let task = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
if error != nil{
print(error!)
return
}
print(data!)
self.landlordPropertyArray = [PropertyList]()
self.count = (self.landlordPropertyArray?.count)!
do{
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String: AnyObject]
if let datafromjson = json["landlords_property_list"] as? [[String: AnyObject]] {
print(datafromjson)
for data in datafromjson{
var property = PropertyList()
if let id = data["ID"] as? Int,let code = data["Code"] as? String, let address1 = data["Address"] as? String
{
property.id = id
property.code = code
property.address1 = address1
}
self.landlordPropertyArray?.append(property)
}
print(self.landlordPropertyArray)
}
DispatchQueue.main.async {
self.propertyTabel.reloadData()
}
}catch let error {
print(error)
}
}
task.resume()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (landlordPropertyArray?.count)!
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Configure the cell...
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! PropertyCell
cell.propertyCodeLbl.text = self.landlordPropertyArray?[indexPath.item].code
cell.addressLbl.text = self.landlordPropertyArray?[indexPath.item].address1
return cell
}
func getDataFromTableViewCellToViewController(sender :UITableViewCell) {
//make a callback here
}
}
(*) Marked fields are updated code
Call fetchData() function after tableview delegate and datasource assigning
propertyTabel.dataSource = self
propertyTabel.delegate = self
Updated answer is
Create Cell Class like this
import UIKit
class YourTableViewCell: UITableViewCell {
#IBOutlet weak var profileImageView: UIImageView!
#IBOutlet weak var userNameLabel: UILabel!
#IBOutlet weak var timeDateLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
self.backgroundColor = UIColor.tableViewBackgroundColor()
self.selectionStyle = .none
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
class func cellForTableView(tableView: UITableView, atIndexPath indexPath: IndexPath) -> YourTableViewCell {
let kYourTableViewCell = "YourTableViewCellIdentifier"
tableView.register(UINib(nibName:"RRLoadQuestionsTableViewCell", bundle: Bundle.main), forCellReuseIdentifier: kYourTableViewCell)
let cell = tableView.dequeueReusableCell(withIdentifier: kYourTableViewCell, for: indexPath) as! YourTableViewCell
return cell
}
}
Then create UIViewController Class and place UITableView on it and link with outlet
class YourViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UITextViewDelegate {
#IBOutlet weak var tableView: UITableView!
var dataSource = [LoadYourData]()
// MARK: - Init & Deinit
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: "YourViewController", bundle: Bundle.main)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
NotificationCenter.default.removeObserver(self)
}
override func viewDidLoad() {
super.viewDidLoad()
setupViewControllerUI()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
}
// MARK: - UIViewController Helper Methods
func setupViewControllerUI() {
tableView.estimatedRowHeight = 44.0
tableView.rowHeight = UITableViewAutomaticDimension
tableView.delegate = self
tableView.dataSource = self
loadData()
}
func loadData() {
// Write here your API and reload tableview once you get response
}
// MARK: - UITableView Data Source
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataSource.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = YourTableViewCell.cellForTableView(tableView: tableView, atIndexPath: indexPath)
// assign here cell.name etc from dataSource
return cell
}

Error while trying to download Image URL from Firebase database using Swift3

Would you please help me to find the error in my code? I have an image URL in my database and I'm trying to download it and display it in a TableView, but it shows nil value.
This is my Class:
class Post : NSObject {
var Posts : String!
var Image : String!
}
and this is My TableView.
import UIKit
import FirebaseDatabase
import SDWebImage
class ViewController: UIViewController , UITableViewDataSource , UITableViewDelegate {
#IBOutlet weak var MyImageView: UIImageView!
#IBOutlet weak var tableView: UITableView!
var Ref:FIRDatabaseReference?
var Handle:FIRDatabaseHandle?
var myarray = [Post]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tableView.delegate = self
tableView.dataSource = self
}
override func viewDidAppear(_ animated: Bool) {
Ref=FIRDatabase.database().reference()
Handle = Ref?.child("Posts").observe(.childAdded ,with: { (snapshot) in
let post = snapshot.value as? Post
self.myarray.append(post!)
self.tableView.reloadData()
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return myarray.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell") as? TableViewCell {
// cell?.textLabel?.text = PostData[indexPath.row]
let url = URL(string : self.myarray [(indexPath as NSIndexPath).row].Image!)
cell.MyImage.sd_setImage(with: url)
return cell
}else{
let cell = TableViewCell()
let url = URL(string : self.myarray [(indexPath as NSIndexPath).row].Image!)
cell.MyImage.sd_setImage(with: url)
return cell
}
}
}

Class has no initializers: Swift Error

I have a problem with my ViewController.
My code has an error about initializers and I can't understand why.
Please, take a moment to look at my code:
import UIKit
class ViewController: UIViewController, UITableViewDataSource {
let sectionsTableIdentifier = "SectionsTableIdentifier"
var names: [String: [String]]!
var keys: [String]!
#IBOutlet weak var tableView: UITableView!
var searchController: UISearchController
//methods
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: sectionsTableIdentifier)
let path = NSBundle.mainBundle().pathForResource("sortednames", ofType: "plist")
let namesDict = NSDictionary(contentsOfFile: path!)
names = namesDict as! [String: [String]]
keys = namesDict!.allKeys as! [String]
keys = keys.sort()
let resultsController = SearchResultsController()
resultsController.names = names
resultsController.keys = keys
searchController = UISearchController(searchResultsController: resultsController)
let searchBar = searchController.searchBar
searchBar.scopeButtonTitles = ["All", "Short", "Long"]
searchBar.placeholder = "Enter a search term"
searchBar.sizeToFit()
tableView.tableHeaderView = searchBar
searchController.searchResultsUpdater = resultsController
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return keys.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let key = keys[section]
let nameSection = names[key]!
return nameSection.count
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return keys[section]
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(sectionsTableIdentifier, forIndexPath: indexPath) as UITableViewCell
let key = keys[indexPath.section]
let nameSection = names[key]!
cell.textLabel!.text = nameSection[indexPath.row]
return cell
}
func sectionIndexTitlesForTableView(tableView: UITableView) -> [String]? {
return keys
}
}
What is the problem?
The error is that the class has no initializer. I have no variables with no value.
Problematic line is
var searchController: UISearchController
Change it to
var searchController: UISearchController!
or if you are not initializing it in view life cycles, use optional to avoid crashes:
var searchController: UISearchController?
Your line which catch the error is:
var searchController: UISearchController
because you never init searchController in a LifeCycle init function from your UIViewController. I advice you not to force unwrap the var (like Sahil said above) but to properly init it into an init func like this:
override init(frame: CGRect) {
super.init(frame: frame)
setUp()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setUp()
}
func setUp() {
searchController = UISearchController() //Or any init you can use to perform some custom initialization
}
In Swift, you always should avoid force unwrap Object like above, to avoid crash in your app, or use if-Let/Guard-Let template
Cheers from France

create a UITableViewController programmatically in Swift

I'm trying to, as the title say, set up a UITableViewController programmatically. After a few hours of trying I hope someone can help me. And, yes, I hve checked out other posts on this matter:
import UIKit
class MainViewController: UITableViewController {
init(style: UITableViewStyle) {
super.init(style: style)
// Custom initialization
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// #pragma mark - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView?) -> Int {
return 1
}
override func tableView(tableView: UITableView?, numberOfRowsInSection section: Int) -> Int {
return 5
}
override func tableView(tableView: UITableView?, cellForRowAtIndexPath indexPath: NSIndexPath?) -> UITableViewCell? {
var cell = tableView?.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCell
if !cell {
cell = UITableViewCell(style: UITableViewCellStyle.Value1, reuseIdentifier: "Cell")
}
cell!.textLabel.text = "test"
return cell
}
}
and the appDelegate looks like this:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let mainViewController: UITableViewController = MainViewController(style: UITableViewStyle.Plain)
let navigationController: UINavigationController = UINavigationController()
navigationController.pushViewController(mainViewController, animated: false)
self.window!.rootViewController = navigationController
self.window!.backgroundColor = UIColor.whiteColor()
self.window!.makeKeyAndVisible()
return true
}
The program run, but as soon as it does, I get the following error:
fatal error: use of unimplemented initializer 'init(nibName:bundle:)' for class 'HelloWorld.MainViewController'
I then changes the MainViewController(style: UITableViewStyle.Plain) to MainViewController(nibName: nil, bundle: nil) but then I get the following syntax error: Extra argument 'bundle' in call
Any help would be much appreciated
I'm using a subclass of UITableViewController with no issues, using the (nibName:bundle:) form, but I've overridden that in my subclass. I tried replacing my subclass with a standard UITableViewController, and it still worked fine. Are you possibly overriding an init(...) method in your subclass?
In the AppDelegate or wherever you call the TableViewController:
func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
window = UIWindow(frame: UIScreen.mainScreen().bounds)
if let window = window {
window.backgroundColor = UIColor.whiteColor()
var mainTableViewController = MainTableTableViewController(style: .Plain)
window.rootViewController = UINavigationController(rootViewController: mainTableViewController)
window.makeKeyAndVisible()
}
return true
}
In the UITableViewController (assuming no custom TableViewCell implementation):
import UIKit
class MainTableTableViewController: UITableViewController {
override init(style: UITableViewStyle){
super.init(style: style)
}
override init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!){
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
// MARK: - Tableview Data Source
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return [*YOUR_DATA_ARRAY].count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel!.text = [*YOUR_DATA_ARRAY][indexPath.row]
}
For an full example: visit: https://github.com/ericcgu/EGStormTracker
I just removing
init(style: UITableViewStyle) {
super.init(style: style)
}
and then init like this:
let mainViewController: UITableViewController = MainViewController()

Resources