I'm using uikit tableview in swiftui. I get data from WebSocket and I want to update my tableview live. I successfully get data from network and update it in viewModel and pass it to QuotesTableView. The problem is occur in here. TableView not update correctly my data, i.e tableViewData's first value is Symbol1 but it shows Symbol1 data in first indexpath. I debug it in cellForRowAt function and see I get correct data, but not show correct item in cell :( it randomly changes order of data in tableview. but tableviewData order not change.
@StateObject private var viewModel = QuotesViewModel()
var body: some View {
ZStack {
Color.init(hex: "#293c54").edgesIgnoringSafeArea(.all)
QuotesTableView(tableViewData: $viewModel.list)
.background(Color.clear)
}
}
}
import Combine
class QuotesViewModel: ObservableObject {
var cancellables = Set<AnyCancellable>()
// MARK: - Input
var selectedSymbols: String
/// Symbols list
@Published var list: [SymbolsInDataModel] = .init()
// MARK: - Output
// MARK: - Init
init() {
socket = SocketManager.shared
observeSocketValues()
bindView()
}
// MARK: - Business Logic
let socket: SocketManager
// MARK: - Config
}
// MARK: - Bind View
extension QuotesViewModel {
/// observe view actions in here...
func bindView() {
}
}
// MARK: - Observation Socket Data
extension QuotesViewModel {
func observeSocketValues() {
socket.$symbolsList.sink(receiveValue: { newSymbols in
self.list = newSymbols
})
.store(in: &cancellables)
socket.$symbolsList
.filter { !$0.isEmpty }
.first { _ in
self.list = self.socket.symbolsList
return true
}
.sink(receiveValue: {_ in})
.store(in: &cancellables)
}
}
struct QuotesTableView: UIViewRepresentable {
// The data source for the table view
@Binding var tableViewData: [SymbolsInDataModel]
var selectClicked: ((_ item: SymbolsInDataModel) -> Void)?
func makeUIView(context: Context) -> UITableView {
let tableView = UITableView()
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.backgroundColor = .clear
tableView.dataSource = context.coordinator
tableView.showsVerticalScrollIndicator = false
tableView.delegate = context.coordinator
tableView.register(HostingCell.self, forCellReuseIdentifier: "Cell")
return tableView
}
func updateUIView(_ uiView: UITableView, context: Context) {
// Reload the table view data whenever the data changes
uiView.reloadData()
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
}
// MARK: - CompetitionsTableView -> Coordinator
extension QuotesTableView {
class Coordinator: NSObject, UITableViewDataSource, UITableViewDelegate {
var parent: QuotesTableView
init(_ tableView: QuotesTableView) {
parent = tableView
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
parent.tableViewData.count
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let tableViewCell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! HostingCell
tableViewCell.backgroundColor = .clear
print("indexpath: \(indexPath.row) item: \(parent.tableViewData[indexPath.row])")
// Set the root view of the hosting controller to the view for this cell
let row = parent.tableViewData[indexPath.row]
let hostingController = UIHostingController(
rootView: AnyView(
QuotesCellView(item: row, selectAction: self.parent.selectClicked)
)
)
hostingController.view.backgroundColor = .clear
// create & setup hosting controller only once
if tableViewCell.host == nil {
tableViewCell.host = hostingController
let tableCellViewContent = hostingController.view!
tableCellViewContent.translatesAutoresizingMaskIntoConstraints = false
tableViewCell.contentView.addSubview(tableCellViewContent)
tableCellViewContent.topAnchor.constraint(equalTo: tableViewCell.contentView.topAnchor).isActive = true
tableCellViewContent.leftAnchor.constraint(equalTo: tableViewCell.contentView.leftAnchor).isActive = true
tableCellViewContent.bottomAnchor.constraint(equalTo: tableViewCell.contentView.bottomAnchor).isActive = true
tableCellViewContent.rightAnchor.constraint(equalTo: tableViewCell.contentView.rightAnchor).isActive = true
} else {
// reused cell, so just set other SwiftUI root view
tableViewCell.host = hostingController
}
tableViewCell.setNeedsLayout()
return tableViewCell
}
}
}
Post
Replies
Boosts
Views
Activity
Hello developers, I'm currently working on an iOS application that requires trading chart functionality, and I'm looking for a solution that I can easily integrate into my app.
I've heard about TradingView's charting and technical analysis tools, but I'm not sure if they offer a library that I can use. Can anyone recommend a charting tool that is easy to integrate into an iOS app?
Ideally, the tool should offer real-time data streaming, support for multiple chart types, and customizable indicators and drawing tools. Any suggestions or recommendations would be greatly appreciated.
Thank you!
Hi. How can we set structure complex in ui. For example, if we imagine have app's main content contains some ui - different collection views, another sections and end of all we have comments which is shows another page's bottom area.
I think I'll solve it with creating different viewcontrollers - one for collection views, another for comment section... and with addchild i'll add all of that to Main controller.
Is this way is well ?
CommentController which is gets comments and adding that section to some controller what i want. is this right ?
I have 2 apps, I use HMAC for signature between apps. First App's minimum deployment target is 11.2 and it uses CryptoSwift for sending data to the second app while signing documents. But the Second app uses Apple's CryptoKit, and I get a signing error. Can I use different packages for HMAC Sha256 process?
Hi, I'm adding steps:
First launch I set LoginAndRegisterContainerView with navigationcontroller
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
let contentView = LoginAndRegisterContainerView()
//
let window = UIWindow(windowScene: windowScene)
let navigationView = UINavigationController(rootViewController: UIHostingController(rootView: contentView))
window.rootViewController = navigationView
self.window = window
window.makeKeyAndVisible()
}
Later in MyView I want to change rootViewController
DispatchQueue.main.async {
let vc = UIHostingController(rootView: Home())
let sceneDelegate = UIApplication.shared.connectedScenes.first?.delegate as! SceneDelegate
let window = sceneDelegate.window
window?.rootViewController = vc
UIView.transition(with: window!, duration: 0.4, options: .transitionFlipFromRight, animations: {}, completion:
{ completed in
// maybe do something on completion here
})
}
is it the right way?( at the end my view hierarchy looks like this:
I want to pick an image with PHPickerViewController. But this causes to memory link. Can anyone help me with this issue?(
I created ImagePickerManager and I'm using it on ViewController below.
P.s: I didn't get a leak when writing the same code with UIImagePickerViewController.
import Foundation
import Photos
import PhotosUI
class ImagePickerManager: NSObject {
// MARK: Variables
var accessType: PHAccessLevel = .addOnly
var pickerViewController = PHPickerViewController(configuration: PHPickerConfiguration())
//var viewController: UIViewController?
var pickImageCallback : ((UIImage) -> ())?;
// MARK: Init
override init() {
super.init()
setupPhotoPicker()
setupPhotoLibrary(accessType)
}
// convenience init(
// viewController: UIViewController,
// accessType: PHAccessLevel = .addOnly) {
// self.init()
//
// self.viewController = viewController
// setupPhotoLibrary(accessType)
// setupPhotoPicker()
// }
// MARK: Setup
private func setupPhotoLibrary(_ accessType: PHAccessLevel) {
self.checkAuthorizationStatusForPhotoLibrary()
self.accessType = accessType
}
private func setupPhotoPicker() {
pickerViewController.delegate = self
}
// MARK: Present PickerController
func presentPHPicker(_ viewContr: UIViewController,_ callback: @escaping ((UIImage) -> ())) {
pickImageCallback = callback
// self.viewController = viewContr
viewContr.present(pickerViewController, animated: true)
}
// MARK: Checking status of Photo library access
func checkAuthorizationStatusForPhotoLibrary() {
switch PHPhotoLibrary.authorizationStatus(for: accessType) {
case .authorized: break
case .notDetermined:
self.requestAuthorizationForPhotoLibrary()
case .denied:
self.showAccessDeniedMessage()
default: return
}
}
// MARK: Request to Access Photo Library
func requestAuthorizationForPhotoLibrary () {
PHPhotoLibrary.requestAuthorization(for: accessType) { status in
switch status {
case .authorized:
print("Access granted")
case .denied: break
case .notDetermined: break
default: return
}
}
}
// MARK: Access Denied to do action
private func showAccessDeniedMessage() {
print("\n ShowAccessDeniedMessage \n")
}
}
// MARK: - PHPickerViewControllerDelegate
extension ImagePickerManager: PHPickerViewControllerDelegate, UINavigationControllerDelegate {
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true, completion: nil)
for result in results {
result.itemProvider.loadObject(ofClass: UIImage.self, completionHandler: { (object, error) in
if let image = object as? UIImage {
// DispatchQueue.main.async {
// Use UIImage
self.pickImageCallback?(image)
// }
}
})
}
}
}
/// -------- ViewController
let imageManager = ImagePickerManager()
@objc func pressedButton() {
imageManager.presentPHPicker(self) { image in
print("something...")
}
}
I'm trying to show multiple cells and their own data models in the same tableView. I added segment control for this and I delete all tableview current data and removed the current data sources and binding new data and its cell. But I am getting the below error message :( If you have any offers please help me :(
P.s: Each segment's cells and sections design is different than each other.
Error: Thread 1: "attempt to insert section 0 but there are only 0 sections after the update"
In View Model:
private func bindSelectedSegmentIndex() {
/// reset pagination and limit for new request
selectedSegmentIndex
.observe(on: MainScheduler.instance)
.do(onNext: { _ in
/// remove all old api data in tableviews
self.transactionsAndDepositsTableViewData.accept([])
self.contractsTableViewData.accept([])
self.pagination = Pagination()
self.updateTableViewDataSource.accept(())
})
.subscribe(onNext: { [weak self] _ in
guard let self = self else {return}
switch self.selectedSegmentIndex.value {
case 0,1:
self.callUserTransactionsAndDeposits()
case 2:
self.getContracts()
default:
return
}
})
.disposed(by: disposeBag)
}
In ViewController:
@IBAction func segmentControlChanged(_ sender: UISegmentedControl) {
self.hapticImpactMedium()
let selectedIndex = sender.selectedSegmentIndex
self.viewModel.selectedSegmentIndex.accept(selectedIndex)
}
fileprivate func setupTransactionsAndDepositsDataSource() {
transactionsTableViewDataSource = TableViewSectionedAnimatedDataSourceWithRx(cell: WithdrawAndDepositCell.self,
data: WithdrawAndDepositSection.self)
transactionsTableViewDataSource?.handleCell = { cell ,item in
cell.item = item
}
transactionsTableViewDataSource?.dataSource.titleForHeaderInSection = { dataSource, index in
return dataSource.sectionModels[index].header
}
}
fileprivate func setupContractsDataSource() {
contractsTableViewDataSource = TableViewSectionedAnimatedDataSourceWithRx(cell: ContractTableViewCell.self,
data: ContractTableSection.self)
contractsTableViewDataSource?.handleCell = { cell ,item in
cell.item = item
}
contractsTableViewDataSource?.dataSource.titleForHeaderInSection = { dataSource, index in
return dataSource.sectionModels[index].header
}
}
private func setDataSources(with index: Int) {
/// remove old dataSource and update new one
tableView.dataSource = nil
tableView.delegate = nil
switch index {
case 0,1 :
setupTransactionsAndDepositsDataSource()
/// Bind tableViewData to the tableView items for transactionsTableViewDataSource
viewModel.transactionsAndDepositsTableViewData.asDriver()
.drive(tableView.rx.items(dataSource: transactionsTableViewDataSource.dataSource))
.disposed(by: disposeBag)
case 2:
setupContractsDataSource()
/// Bind tableViewData to the tableView items for clientsTableViewDataSource
viewModel.contractsTableViewData.asDriver()
.drive(tableView.rx.items(dataSource: contractsTableViewDataSource.dataSource))
.disposed(by: disposeBag)
default : break
}
}
Hi. Can I set a time and run any code at a specific time? For example after 2 days. But the application will not run or be in background mode. I've read about Background Tasks. But everyone runs their code in background mode (in-app run). I want to make that special time :) Thanks in advance
Hi everyone. I want to bind the URLSessionDelegate protocol with the custom protocol that it confirmed from URLSessionDelegate. But I can't catch its functions on the protocol. Can you tell me where I went wrong?
Hi.
I am adding AppTrackingTransparency to my application.
I have added all requirements from documentation and regularly alert shows when the app launches. The problem is related to real devices. I achieve to display privacy alert on the simulator but can't do this on the real phone. How can fix this issue, please help me?
P.s
ios version: 15
Xcode version: 13
Guideline 5.1.2 - Legal - Privacy - Data Use and Sharing
The app privacy information you provided in App Store Connect indicates you collect data in order to track the user, including Crash Data. However, you do not use App Tracking Transparency to request the user's permission before tracking their activity.
Starting with iOS 14.5, apps on the App Store need to receive the user’s permission through the AppTrackingTransparency framework before collecting data used to track them. This requirement protects the privacy of App Store users.
I am getting this rejected message from apple. But I added AppTrackingTransparency to my project and alerts when the app launches. What must I do for the next step?
P.s I am using Firebase's Crashlytics.
struct AppDelegateHelper {
static func askAppTrackingTransparency() {
// Request user authorization to access app-related data for tracking the user or the device.
if #available(iOS 14, *) {
ATTrackingManager.requestTrackingAuthorization { status in
switch status {
case .authorized:
print("Allowed to AppTrackingTransparency")
break
case .denied: break
case .notDetermined: break
case .restricted: break
}
}
} else {
// Fallback on earlier versions
print("Can't ask AppTrackingTransparency")
}
}
}
I want to connect to my own Asterisk server. I'm using CallKit. Is this possible with CallKit? Or if you know another way, please let me know
Hey everyone. I have created a new framework, may I create a new bundle for my assets, xib... can I keep it inside itself?
I'm trying reload all cells when variable was changed.
Problem was appearing only in bottom cell of tableView. TableView scrolling unexpected way (it was scrolling top and bottom)
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let cell = tableView.cellForRow(at: indexPath) as? ConverterTableViewCell,
let code = cell.currency.text
else { return }
cell.priceText.text = "0"
convertCurrencyForCode(with: code)
cell.priceText.delegate = self
cell.priceText.addTarget(self, action: #selector(textChanged(_:)), for: .editingChanged)
cell.priceText.addTarget(self, action: #selector(onTextFieldTap), for: .touchDown)
writedNumber = 0
tableView.reloadData()
cell.priceText.becomeFirstResponder()
selected = indexPath.row
}
@IBAction func textChanged(_ textField: UITextField) {
if let text = textField.text {
writedNumber = Double(textField.text!)
tableView.reloadData()
}
}
I'm trying to add a settings navigation controller to my tabBar. The problem is tab bar has navigation items when opening the page. And. I want to add settings controller their navigation items (title, right button). When I trying to add it, setting was coming under the tabBar's navigation. How I fix it?
class TabFirst: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(identifier: "SettingsViewController")
present(vc, animated: true, completion: nil)
}
}