ios - 需要帮助在自定义单元格中设置 UISwitch(XIB、Swift 4、Xcode 9)

标签 ios swift xcode uiswitch

迄今为止的成功:我有一个远程数据源。数据被动态拉入 View Controller 。该数据用于命名每个可重用自定义单元格上的 .title 和 .subtitle。此外,每个自定义单元格都有一个 UISwitch,我已经能够使用它来发送推送通知的“订阅”信号(对于由单元格的标题/副标题标识的给定组)和“取消订阅”信号。

我剩下的一个问题:每当用户“重新访问”设置 VC 时,当我的代码“重置”UISwitches 时,它会在 Xcode 9.2 中导致以下警告:

  • UISwitch.on 必须在主线程中使用
  • UISwitch.setOn(_:animated:) 只能在主线程中使用
  • -[UISwitch setOn:animated:notifyingVisualElement:] 必须在主线程中使用

下面的代码“有效”——但是所需的结果发生得相当慢(确实应该“打开”的 UISwitches 需要很长时间才能最终翻转到“打开”)。

更多详细信息: 需要什么:每当 VC 显示或“重新显示”时,如果用户订阅了给定组,我需要将自定义单元格的 UISwitch“重置”为“打开”,如果用户订阅了给定组,则需要“重置”为“关闭”未订阅。理想情况下,每次显示 VC 时,都应该有东西接触 OneSignal 服务器,并使用 OneSignal.getTags() 函数找出每个组的用户“订阅状态”。我有那部分工作。这段代码是在VC中的。但我需要以正确的方式做到这一点,以适应有关线程的正确协议(protocol)。

  • VC 文件“ViewController_13_Settings.swift”包含一个带有可重用自定义单元格的 TableView 。
  • TableView 文件名为“CustomTableViewCell.swift”
  • 自定义单元格称为“customCell”(我知道,我的名字都很有创意)。

自定义单元格(在 XIB 中设计)内部只有三个项目:

  1. 标题 – 要订阅或取消订阅的“组”的显示“友好名称”。从远程数据源设置
  2. 副标题 – 上述组的隐藏“数据库名称”。对用户隐藏。从远程数据源设置。
  3. UISwitch - 名为“switchMinistryGroupList”

如何以编程方式正确设置 UISwitch?

这是 ViewController_13_Settings.swift 中似乎相关的代码:

    public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell  = tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath) as! CustomTableViewCell

    // set cell's title and subtitle
    cell.textLabelMinistryGroupList?.text = MinistryGroupArray[indexPath.row]
    cell.textHiddenUserTagName?.text = OneSignalUserTagArray[indexPath.row]

    // set the custom cell's UISwitch.
    OneSignal.getTags({ tags in
        print("tags - \(tags!)")
        self.OneSignalUserTags = String(describing: tags)
        print("OneSignalUserTags, from within the OneSignal func, = \(self.OneSignalUserTags)")

        if self.OneSignalUserTags.range(of: cell.textHiddenUserTagName.text!) != nil {
            print("The \(cell.textHiddenUserTagName.text!) UserTag exists for this device.")
            cell.switchMinistryGroupList.isOn = true
        } else {
            cell.switchMinistryGroupList.isOn = false
        }
    }, onFailure: { error in
        print("Error getting tags - \(String(describing: error?.localizedDescription))")
        // errorWithDomain - OneSignalError
        // code - HTTP error code from the OneSignal server
        // userInfo - JSON OneSignal responded with
    })
    viewWillAppear(true)
    return cell
    }
    }

在 VC 代码的上面部分中,这部分(下面)是正在运行的部分,但显然没有正确使用线程:

    if OneSignalUserTags.range(of: cell.textHiddenUserTagName.text!) != nil {
        print("The \(cell.textHiddenUserTagName.text!) UserTag exists for this device.")
        cell.switchMinistryGroupList.isOn = true
    } else {
        cell.switchMinistryGroupList.isOn = false
    }

最佳答案

尚不完全清楚您的代码在做什么,但似乎有一些事情需要整理,这将帮助您解决问题。

1) 改进对象的命名。这有助于其他人在提问时了解发生了什么。

不要将您的单元格命名为 CustomTableViewCell - 例如,将其命名为 MinistryCell 或代表其显示数据的名称。而不是 textLabelMinistryGroupListtextHiddenUserTagNameministryGroupuserTagName 等。

2) 让单元格自行填充。将单元格中的 IBOutlets 设置为 private,这样您就无法直接在 View Controller 中分配给它们。这是一个坏习惯!

3) 创建一个与您分配给单元格的数据相对应的对象(例如,Ministry)。将其分配给单元格,并让单元格分配给它的 Outlet。

4) 永远不要调用viewWillAppear,或者类似的东西!这些由系统调用。

你最终会得到这样的结果:

在 View Controller 中

struct Ministry {
    let group: String
    let userTag: String
    var tagExists: Bool?
}

您应该创建一个数组 var ministries: [Ministry] 并在开始时填充它,而不是分别处理 MinistryGroupArrayOneSignalUserTagArray .

在您的牢房中

class MinistryCell: UITableViewCell {

    @IBOutlet private weak var ministryGroup: UILabel!
    @IBOutlet private weak var userTagName: UILabel!
    @IBOutlet private weak var switch: UISwitch!

    var ministry: Ministry? {
        didSet {
            ministryGroup.text = ministry?.group
            userTagName.text = ministry?.userTag
            if let tagExists = ministry?.tagExists {
               switch.isEnabled = false
               switch.isOn = tagExists
            } else {
               // We don't know the current state - disable the switch?
               switch.isEnabled = false
            }
        }
    }
}

然后你的 dataSource 方法将看起来像......

public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell  = tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath) as! MinistryCell

    let ministry = ministries[indexPath.row]
    cell.ministry = ministry

    if ministry.tagExists == nil {
        OneSignal.getTags { tags in

        // Success - so update the corresponding ministry.tagExists
        // then reload the cell at this indexPath

        }, onFailure: { error in
            print("Error")
        })
    }    
    return cell
}

关于ios - 需要帮助在自定义单元格中设置 UISwitch(XIB、Swift 4、Xcode 9),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50036401/

相关文章:

swift - 您如何检查特定的 KVO 观察者当前是否已注册?

ios - scrollToItem UICollectionView 错误 - 索引超出范围

ios - swift 4 : How to create a face map with ios11 vision framework from face landmark points

ios - 在闭包中使用元类型

html - Aptana 插件是否帮助我们在 Eclipse 中进行 iphone 开发?

ios - 在 iOS13 上使用 UINavigationController 作为 UISplitViewController 的子级时不调用 ViewDidLoad 和 WillHideViewController

ios - 在swift中添加任意两个数字元组

ios - UITextField 上的 Swift 扩展不会在 swift 1.2 和 xcode6.3 上编译

iphone - Storyboard自动布局 : "trailing space to container" vs "bottom space to bottom layout"

ios - iAd 横幅出现在底部时将屏幕内容向上推