I am trying to figure out how to update my xib labels when a button is pressed on another view controller
Currently I have a xib swift file that contains all my labels
var habit: Habit? {
didSet {
self.updateUI()
}
}
func updateUI() {
habitXibName?.text = habit?.title
totalProgress?.text = habit?.totalCount
progressBarXib?.progress = habit?.progress ?? 0.0
userProgress?.text = String(habit?.userCount ?? 0)
}
In another view controller I have the following code
do {
try realm.write {
if selectedHabit!.userCount == (Int(selectedHabit!.totalCount )! - 1) {
selectedHabit!.userCount += 1
habitcell.habitXibName?.text = String(selectedHabit?.userCount ?? 0)
view.addSubview(confettiView)
confettiView.startConfetti()
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
self.confettiView.stopConfetti()
}
} else {
selectedHabit!.userCount += 1
}
}
} catch {
print(error)
}
what I want to happen is to update my xib label to the selectedHabit?.userCount
habitcell.habitXibName?.text = String(selectedHabit?.userCount ?? 0)
However, my habitcell.habitXibName returns nil and I'm not sure why. Thanks for everything!
Related
#objc func contextDidSave(_ notification: Notification) {
DispatchQueue.main.async { [weak self] in
guard let me = self else { return }
let fileCount = CoreDataService.instance.getUploadedFilesCount(jobId: nil)
if me.totalFiles == 0 || (fileCount > me.totalFiles) {
me.totalFiles = fileCount
}
// For increase the progress lebel we need the range between 0.1(min) to 1.0(max)
// So converting all values to float so that we can get decimal value within the range
let progress = (Float(me.totalFiles) - Float(fileCount)) / Float(me.totalFiles)
me.progressBarView.setProgress(progress, animated: true)
if fileCount == 0 {
me.progressView.isHidden = true
} else {
me.uploadFiles.text = "\("Uploading: ".localized() + (fileCount.description) + " Files left".localized())"
me.progressView.isHidden = false
}
}
}
ProgressView is UIView
UploadFile is UILabel
This function is reusable in Two Different ViewController
I am currently working as a 5 month junior ios developer.
The project I'm working on is an application that shows the prices of 70 cryptocurrencies realtime with websocket connection.
we used websocket connection, UItableview, UITableViewDiffableDataSource, NSDiffableDataSourceSnapshot while developing the application.
But right now there are problems such as slowdown scrolling or not stop scroling and UI locking while scrolling in the tableview because too much data is processed at the same time.
after i check cpu performance with timer profiler I came to the conclusion that updateDataSource and updateUI functions exhausting the main thread.
func updateDataSource(model: [PairModel]) {
var snapshot = DiffableDataSourceSnapshot()
let diff = model.difference(from: snapshot.itemIdentifiers)
let currentIdentifiers = snapshot.itemIdentifiers
guard let newIdentifiers = currentIdentifiers.applying(diff) else {
return
}
snapshot.appendSections([.first])
snapshot.deleteItems(currentIdentifiers)
snapshot.appendItems(newIdentifiers)
dataSource?.apply(snapshot, animatingDifferences: false, completion: nil)
}
func updateUI(data: SocketData) {
guard let newData = data.data else { return }
guard let current = data.data?.price else { return }
guard let closed = data.data?.lastDayClosePrice else { return }
let dailyChange = ((current - closed)/closed)*100
DispatchQueue.main.async { [self] in
if model.filter({ $0.symbol == newData.pairSymbol }).first != nil {
let index = model.enumerated().first(where: { $0.element.symbol == newData.pairSymbol})
guard let location = index?.offset else { return }
model[location].price = current
model[location].dailyPercent = dailyChange
if calculateLastSignalTime(alertDate: model[location].alertDate) > 0 {
//Do Nothing
} else {
model[location].alertDate = ""
model[location].alertType = ""
}
if let text = allSymbolsView.searchTextField.text {
if text != "" {
filteredModel = model.filter({ $0.name.contains(text) || $0.symbol.contains(text) })
updateDataSource(model: filteredModel)
} else {
filteredModel = model
updateDataSource(model: filteredModel)
}
}
}
delegate?.pricesChange(data: self.model)
}
}
Regards.
ALL of your code is running on the main thread. You have to wrap your entire updateUI function inside a DispatchQueue.global(qos:), and then wrap your dataSource.apply(snapshot) line inside a DispatchQueue.main.async. the dataSource.apply(snapshot) line is the only UI work you're doing in all that code you posted.
After reload tableview, Inside Textfield keyboard is not showing properly .How can i fix That keyboard properly.
This is My code,
Here, I am Getting Firebase Images
let queue = OperationQueue()
queue.addOperation {
if let urlString = nammaApartmentVisitor.getprofilePhoto() {
NAFirebase().downloadImageFromServerURL(urlString: urlString,imageView: cell.image_View)
}
}
queue.waitUntilAllOperationsAreFinished()
if isActivityIndicatorRunning == false {
cell.activityIndicator.startAnimating()
} else if (isActivityIndicatorRunning == true) {
cell.activityIndicator.stopAnimating()
cell.activityIndicator.isHidden = true
}
I am using pagination on UITableView, after the first load when the next items is about to come or as I reload the tableView it flashes for a second and then comes to it's last position. But it does not happen every time having a hard time solving this out. Anyone can help me please?
Here is the code I am using to reload the data in the tableView
func handleWSSuccessResponse(_ arrRestaurant:[Restaurant],filterBy:filteringByValues){
let offSet = self.IBtblUserFeed.contentOffset
print(arrRestaurant.count)
if (self.arrRestaurants.count > 0) {
if arrRestaurant.count > 0 && arrRestaurant.count <= 10 {
if arrRestaurant.count % 10 != 0 {
isDataLoading = false
actInd.stopAnimating()
}
if !(self.isFromRefresh) {
self.arrRestaurants = self.arrRestaurants + arrRestaurant
}
DispatchQueue.main.async {
if (self.isFromRefresh) {
self.IBtblUserFeed.reloadData()
} else {
UIView.setAnimationsEnabled(false)
self.IBtblUserFeed.reloadData()
UIView.setAnimationsEnabled(true)
self.IBtblUserFeed.layoutIfNeeded()
self.IBtblUserFeed.setContentOffset(offSet, animated: false)
}
}
} else {
isDataLoading = false
DispatchQueue.main.async {
if (self.isFromRefresh) {
self.IBtblUserFeed.reloadData()
} else {
UIView.setAnimationsEnabled(false)
self.IBtblUserFeed.reloadData()
self.IBtblUserFeed.layoutIfNeeded()
self.IBtblUserFeed.setContentOffset(offSet, animated: false)
UIView.setAnimationsEnabled(true)
}
}
}
} else {
self.arrRestaurants = arrRestaurant
if arrRestaurant.count % 10 != 0 {
isDataLoading = false
actInd.stopAnimating()
}
if self.arrRestaurants.count == 0 {
self.IBtblUserFeed.tableHeaderView = nil
self.IBtblUserFeed.tableHeaderView?.isHidden = true
} else {
if filterBy.isFiltering{
} else {
self.IBtblUserFeed.tableHeaderView = self.header()
}
self.IBtblUserFeed.tableHeaderView?.isHidden = false
}
if filterBy.isFiltering{
self.reloadTableView()
// tejas changes
// filterRestaurant(filterBy: filterBy)
}else{
self.reloadTableView()
}
}
}
Your example code is too cluttered with unrelated things to give a solid answer; however, I think that the problem is related to the use of reloadData; you should instead use insertRows(at:with:) to get smoothly appended rows.
So whenever you append restaurant model objects to your array (from the code it looks like you never apply other changes like modifications or removals), generate the index paths of the new rows ...
let indexPaths = (countBeforeAdding..<countAfterAdding).map { IndexPath.init(row: $0, section: 0) }
... and insert them into the table view:
tableView.beginUpdates()
tableView.insertRows(at: indexPaths, with: .automatic)
tableView.endUpdates()
I have an entity called Settings with an attribute called backgroundColor of type Int, if it is 1 then the view controller will have a background of white if 0 then a background of dark grey.
But I am getting the following error when trying to open the view controller;
fatal error: Array Index out of range
For the following line in my function
if settingsArray.count == 1 {
setting = settingsArray[1]
} else if settingsArray.count <= 0 {
println("No settings in array")
}
View Controller
var settingsArray: [Settings]!
var setting: Settings!
var backgroundSetting: Bool = true
override func viewWillAppear(animated: Bool) {
backgroundSettings()
}
override func viewDidLoad() {
super.viewDidLoad()
backgroundSettings()
}
// Function to fetch settings and change background
func backgroundSettings() {
var error: NSError?
let request = NSFetchRequest(entityName: "Settings")
self.settingsArray = moc?.executeFetchRequest(request, error: &error) as! [Settings]
if settingsArray.count == 1 {
setting = settingsArray[1]
} else if settingsArray.count <= 0 {
println("No settings in array")
}
if setting != nil {
if setting.backgroundColor == 1 {
backgroundSetting = true
} else if setting.backgroundColor == 0{
backgroundSetting = false
}
}
if backgroundSetting == true {
self.view.backgroundColor = UIColor.whiteColor()
} else if backgroundSetting == false {
self.view.backgroundColor = UIColor.darkGrayColor()
}
}
//Button to change the color and settings
#IBAction func backgroundColor(sender: AnyObject) {
if setting != nil {
if setting.backgroundColor == 1 {
setting.backgroundColor = 0
} else {
setting.backgroundColor = 1
}
var error: NSError?
moc?.save(&error)
} else {
println("No settings available")
var settings = NSEntityDescription.insertNewObjectForEntityForName("Settings", inManagedObjectContext: moc!) as! Settings
settings.backgroundColor = 1
var error: NSError?
moc?.save(&error)
}
backgroundSettings()
}
Any ideas where I may be going wrong ?
In Swift (as in Objective C and many other languages), the indexes of arrays start at 0. (See this wikipedia article for a list on this.)
This means when you check if settingsArray.count == 1, there will be only (exactly) one item in your list. Since indexes start at 0, this item will be at index 0, hence the Error.
So either you check if settingsArray.count == 2 and leave setting = settingsArray[1], or you change to setting = settingsArray[0].
ETA:
I have been having another think about this. I have left my old answer below so that the previous comments make sense.
In if let thisSetting = settingsArray?[0] … if settingsArray is nil then the right side is potentially effectively nil[0]. Therefore I believe that this may eliminate the crash:
// ...
if !settingsArray.isEmpty {
if let thisSetting = settingsArray?[0] {
setting = thisSetting
}
}
settingsArray[0] being nil would I think then be a separate issue. Which I think would relate to the lifecycle.
Previous answer follows:
I believe that the problem may be being caused by you calling func backgroundSettings() from viewDidLoad() - i.e. too early in the View Controller lifecycle - and before the values have been initialized.