ios - 如何在同一个 ViewController 中初始化 NSObject 的两个实例 - Swift

标签 ios swift uiviewcontroller nsobject

请多多包涵。我是编程新手,也是 StackOverflow 的新手。我希望我的问题能给我一个进入编程社区的温暖回应。我信任的一位熟人告诉我在 StackOverflow 上将这封电子邮件发给他。

我该怎么做才能让 NSObject 的两个实例在同一个 ViewController 中工作?我已经初始化了一个名为 SideBar 和 RightSideBar 的 NSObject 子类。它们都来自 NSObject。菜单中的单元格由我以编程方式创建的 TableViewController 创建。我遵循了一个以编程方式完成所有事情的教程,因为我不知道 Storyboard 更适合构建事物。

下面是代码库。

编辑:抱歉啰嗦。我不知道如何让这个更短更完整

============

****注意 SideBar 子类是左侧菜单。 RightSideBar 类具有相同的初始化程序设置并且是右侧菜单。如果可能,我希望能够让它们都出现在同一个 ViewController 的同一个实例中的同一个 ViewController 上。 ****

这是左边的 TableViewController:

import UIKit
//this protocol of the sidebar delegate manages the selection of the item in the row.
protocol SidebarTableViewControllerDelegate {

     func sidebarControlDidSelectRow(indexPath: NSIndexPath)

}

class SidebarTableViewController: UITableViewController {

    //setting up the delegate and array of menu items.
    var delegate:SidebarTableViewControllerDelegate?
    var tableData:Array <String> = []
    var imageData:[UIImage] = []


    // MARK: - Table view data source

    //Setting up the number of sections in the menu
    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {

        return 1
    }
    //Setting up the number of items in the menu
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        return tableData.count
    }

    //Setting up the menu look for the main screen after login.
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var cell:UITableViewCell? = tableView.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCell

        if cell == nil {

            cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
            //configure the cell...

            cell!.backgroundColor = UIColor.clearColor()
            cell!.textLabel?.textColor = UIColor.darkTextColor()

            let selectedView:UIView = UIView(frame: CGRect(x: 0, y: 0, width: cell!.frame.size.width, height: cell!.frame.size.height))
            selectedView.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.3)

            cell!.selectedBackgroundView = selectedView

        }

            cell!.textLabel!.text = tableData[indexPath.row]
            cell!.imageView!.image = imageData[indexPath.row]


            return cell!

    }

    //Setting up the height for each cell of the table
    override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {

        return 45.0

    }

    //Setting up the selection of the item in the cell.
    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

        delegate?.sidebarControlDidSelectRow(indexPath)
    }

    override func viewDidLoad() {

    }

    override func didReceiveMemoryWarning() {

    }

}

这是右表 View Controller :
//setting up the RightSidebarControllerDelegate
protocol RightSidebarTableViewControllerDelegate {

    func rightSidebarControlDidSelectRow(indexPath: NSIndexPath)

}

class RightSidebarTableViewController: UITableViewController {

    //setting up the delegate and array of menu items.
    var delegate:RightSidebarTableViewControllerDelegate?
    var rightTableData:Array <String> = []
    var rightImageData:[UIImage] = []


    // MARK: - Table view data source

    //Setting up the number of sections in the menu
    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {

        return 1
    }
    //Setting up the number of items in the menu
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        return rightTableData.count
    }

    //Setting up the menu look for the main screen after login.
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var cell:UITableViewCell? = tableView.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCell

        if cell == nil {

            cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
            //configure the cell...

            cell!.backgroundColor = UIColor.clearColor()
            cell!.textLabel?.textColor = UIColor.darkTextColor()

            let selectedView:UIView = UIView(frame: CGRect(x: 0, y: 0, width: cell!.frame.size.width, height: cell!.frame.size.height))
            selectedView.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.3)

            cell!.selectedBackgroundView = selectedView

        }

        cell!.textLabel!.text = rightTableData[indexPath.row]
        cell!.imageView!.image = rightImageData[indexPath.row]


        return cell!

    }

    //Setting up the height for each cell of the table
    override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {

        return 45.0

    }

    //Setting up the selection of the item in the cell.
    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

        delegate?.rightSidebarControlDidSelectRow(indexPath)
    }

    override func viewDidLoad() {

    }

    override func didReceiveMemoryWarning() {

    }

}

这是我的问题可能从 SideBar:NSObject 开始的地方。这是要初始化的左侧 SideBar:
import UIKit

@objc protocol SideBarDelegate {

    func sideBarDidSelectButtonAtIndex (index: Int)
    optional func sideBarWillClose()
    optional func sideBarWillOpen()
    optional func sideBarWillDeinitialize()

}

//this class sets up the actual sidebar.
class SideBar: NSObject, SidebarTableViewControllerDelegate {

    //width of the bar, tableview setup, and views for the sidebar
    let barWidth:CGFloat = 175.0
    let sideBarTableViewTopInset:CGFloat = 25.0
    let sideBarContainerView:UIView = UIView()
    let sideBarTableViewController:SidebarTableViewController = SidebarTableViewController()
    var originView:UIView!

    //var for dynamic effect and controlling the sidebar
    var animator:UIDynamicAnimator!
    var delegate:SideBarDelegate?
    var isSideBarOpen:Bool = false


    //initializer for the "SideBar" class.
    override init() {
        super.init()

    }

    //initializer for the tableView of menu items.
    init(sourceView: UIView, menuItems: Array<String>, menuImages: [UIImage]){
        super.init()

        //initializing the views and animation for the menu.
        originView = sourceView
        sideBarTableViewController.tableData = menuItems
        sideBarTableViewController.imageData = menuImages
        setupSideBar()
        animator = UIDynamicAnimator(referenceView: originView)

    }

    //function for setting up the sidebar.
    func setupSideBar () {

        //setting up the frame/outline of the side bar.
        sideBarContainerView.frame = CGRectMake(-barWidth, originView.frame.origin.y + 45, barWidth, originView.frame.size.height)

        //setting up the color of the sidebar.
        sideBarContainerView.backgroundColor = UIColor.clearColor()

        //disables subviews from being confined to the sidebar.
        sideBarContainerView.clipsToBounds = false

        //placing the sidebar in the UIView
        originView.addSubview(sideBarContainerView)

        //adding blur to the menu.
        let blurView:UIVisualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.Light))
        blurView.frame = sideBarContainerView.bounds
        sideBarContainerView.addSubview(blurView)


        //setting up controls for the sidebar
        sideBarTableViewController.delegate = self
        sideBarTableViewController.tableView.frame = sideBarContainerView.bounds
        sideBarTableViewController.tableView.clipsToBounds = false

        //disabling the scroll feature. Delete to keep the scroll feature.
        sideBarTableViewController.tableView.scrollsToTop = false

        //This will remove separators in the UITableCell. Delete to keep separators.
        sideBarTableViewController.tableView.separatorStyle = UITableViewCellSeparatorStyle.None

        //This sets the background color of the sidebar and creates the inset.
        sideBarTableViewController.tableView.backgroundColor = UIColor.clearColor()
        sideBarTableViewController.tableView.contentInset = UIEdgeInsets(top: sideBarTableViewTopInset, left: 0, bottom: 0, right: 0)

        //reloads the sidebar and adds the container view to the sideBarTableViewController.
        sideBarTableViewController.tableView.reloadData()
        sideBarContainerView.addSubview(sideBarTableViewController.tableView)
    }

    func showSideBar(shouldOpen: Bool){
        animator.removeAllBehaviors()
        isSideBarOpen = shouldOpen

        //simple if and else statements to define the direction of animation and intensity of animation
        let gravityX:CGFloat = (shouldOpen) ? 0.5 : -0.5
        let magnitude:CGFloat = (shouldOpen) ? 20 : -20
        let boundaryX:CGFloat = (shouldOpen) ? barWidth : -barWidth

        //controls the behavior of the animation.
        let gravityBehavior: UIGravityBehavior = UIGravityBehavior(items: [sideBarContainerView])
        gravityBehavior.gravityDirection = CGVectorMake(gravityX, 0)
        animator.addBehavior(gravityBehavior)

        let collisionBehavior: UICollisionBehavior = UICollisionBehavior(items: [sideBarContainerView])
        collisionBehavior.addBoundaryWithIdentifier("sideBarBoundary", fromPoint: CGPointMake(boundaryX, 20), toPoint: CGPointMake(boundaryX, originView.frame.size.height))
        animator.addBehavior(collisionBehavior)

        let pushBehavior:UIPushBehavior = UIPushBehavior(items: [sideBarContainerView], mode: UIPushBehaviorMode.Instantaneous)
        pushBehavior.magnitude = magnitude
        animator.addBehavior(pushBehavior)

        let sideBarBehavior:UIDynamicItemBehavior = UIDynamicItemBehavior(items: [sideBarContainerView])
        sideBarBehavior.elasticity = 0.3
        animator.addBehavior(sideBarBehavior)
    }
    func sidebarControlDidSelectRow(indexPath: NSIndexPath) {
        delegate?.sideBarDidSelectButtonAtIndex(indexPath.row)
    }

}

这是正确的 SideBar:NSObject,最终将初始化正确的菜单。
import UIKit
@objc protocol RightSideBarDelegate {

    func rightSideBarDidSelectButtonAtIndex (index: Int)
    optional func sideBarWillClose()
    optional func sideBarWillOpen()

}

class RightSideBar: NSObject, RightSidebarTableViewControllerDelegate {

    //width of the bar, tableview setup, and views for the sidebar
    let barWidth:CGFloat = 175.0
    let rightSideBarTableViewTopInset:CGFloat = 25.0
    let rightSideBarContainerView:UIView = UIView()
    let rightSideBarTableViewController:RightSidebarTableViewController = RightSidebarTableViewController()
    var rightOriginView:UIView!

    //var for dynamic effect and controlling the sidebar
    var animator:UIDynamicAnimator!
    var delegate:RightSideBarDelegate?
    var isSideBarOpen:Bool = false


    //initializer for the "SideBar" class.
    override init() {
        super.init()

    }

    //initializer for the tableView of menu items.
    init(rightSourceView: UIView, rightMenuItems: Array<String>, rightMenuImages: [UIImage]){
        super.init()

        //initializing the views and animation for the menu.
        rightOriginView = rightSourceView
        rightSideBarTableViewController.rightTableData = rightMenuItems
        rightSideBarTableViewController.rightImageData = rightMenuImages
        setupSideBar()
        animator = UIDynamicAnimator(referenceView: rightOriginView)

    }

    //function for setting up the sidebar.
    func setupSideBar () {

        //setting up the frame/outline of the side bar.
        rightSideBarContainerView.frame = CGRectMake(rightOriginView.frame.size.width + barWidth , rightOriginView.frame.origin.y + 45, barWidth, rightOriginView.frame.size.height)

        //setting up the color of the sidebar.
        rightSideBarContainerView.backgroundColor = UIColor.clearColor()

        //disables subviews from being confined to the sidebar.
        rightSideBarContainerView.clipsToBounds = false

        //placing the sidebar in the UIView
        rightOriginView.addSubview(rightSideBarContainerView)

        //adding blur to the menu.
        let blurView:UIVisualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.Light))
        blurView.frame = rightSideBarContainerView.bounds
        rightSideBarContainerView.addSubview(blurView)


        //setting up controls for the sidebar
        rightSideBarTableViewController.delegate = self
        rightSideBarTableViewController.tableView.frame = rightSideBarContainerView.bounds
        rightSideBarTableViewController.tableView.clipsToBounds = false

        //disabling the scroll feature. Delete to keep the scroll feature.
        rightSideBarTableViewController.tableView.scrollsToTop = false

        //This will remove separators in the UITableCell. Delete to keep separators.
        rightSideBarTableViewController.tableView.separatorStyle = UITableViewCellSeparatorStyle.None

        //This sets the background color of the sidebar and creates the inset.
        rightSideBarTableViewController.tableView.backgroundColor = UIColor.clearColor()
        rightSideBarTableViewController.tableView.contentInset = UIEdgeInsets(top: rightSideBarTableViewTopInset, left: 0, bottom: 0, right: 0)

        //reloads the sidebar and adds the container view to the rightSideBarTableViewController.
        rightSideBarTableViewController.tableView.reloadData()
        rightSideBarContainerView.addSubview(rightSideBarTableViewController.tableView)

    }

    func showSideBar(shouldOpen: Bool){
        animator.removeAllBehaviors()
        isSideBarOpen = shouldOpen

        //simple if and else statements to define the direction of animation and intensity of animation
        let gravityX:CGFloat = (shouldOpen) ? -0.5 : 0.5
        let magnitude:CGFloat = (shouldOpen) ? -20 : 20
        let boundaryX:CGFloat = (shouldOpen) ? -barWidth : barWidth

        //controls the behavior of the animation.
        let gravityBehavior: UIGravityBehavior = UIGravityBehavior(items: [rightSideBarContainerView])
        gravityBehavior.gravityDirection = CGVectorMake(gravityX, 0)
        animator.addBehavior(gravityBehavior)

        let collisionBehavior: UICollisionBehavior = UICollisionBehavior(items: [rightSideBarContainerView])
        collisionBehavior.addBoundaryWithIdentifier("sideBarBoundary", fromPoint: CGPointMake(boundaryX, 20), toPoint: CGPointMake(boundaryX, rightOriginView.frame.size.height))
        animator.addBehavior(collisionBehavior)

        let pushBehavior:UIPushBehavior = UIPushBehavior(items: [rightSideBarContainerView], mode: UIPushBehaviorMode.Instantaneous)
        pushBehavior.magnitude = magnitude
        animator.addBehavior(pushBehavior)

        let sideBarBehavior:UIDynamicItemBehavior = UIDynamicItemBehavior(items: [rightSideBarContainerView])
        sideBarBehavior.elasticity = 0.3
        animator.addBehavior(sideBarBehavior)


    }
    func rightSidebarControlDidSelectRow(indexPath: NSIndexPath) {
        delegate?.rightSideBarDidSelectButtonAtIndex(indexPath.row)
    }

}

最后,这是我当前的 DoubleMenuViewController 代码。当我继续使用 DoubleMenuViewController 来打破菜单时会发生一些事情。菜单甚至不会加载。但是,如果我在一个只调用 SideBar:NSObject 的 SingleMenuViewController 中,那么只要我只调用一个菜单,代码就可以工作。在这个 DoubleMenuViewController 中,我将 RightSideBar 类的初始化部分注释掉了,因为我正在研究解决方案。我知道这个 ViewController 的代码是乱码。我正在尝试我能想到的一切。在代码之后查看我的评论以了解我尝试过的内容:
import UIKit

class DoubleMenuViewController: UIViewController, SideBarDelegate,       RightSideBarDelegate {

    var sideBar:SideBar?
    var ondemandSideBar:SideBar {

        get {

            if sideBar == nil {

            //setting up the menu items for the sidebar.
            sideBar = SideBar(sourceView: self.view, menuItems: ["Home", "Share", "About", "Help"], menuImages: [homeImage!, shareImage!, aboutImage!, helpImage!])
            sideBar!.delegate = self
            SideBar.new()

            }

            return sideBar!
        }
    }

    //initializes the "RightSideBar"
    var rightSideBar:RightSideBar?
    var ondemandRightSideBar:RightSideBar {

        get {

            if rightSideBar == nil {

            rightSideBar = RightSideBar(rightSourceView: self.view, rightMenuItems: [//Other items], rightMenuImages: [//Other Items])
            rightSideBar!.delegate = self
            RightSideBar.new()

            }

            return rightSideBar!
        }
    }


    var homeImage = UIImage(named: "Home")
    var shareImage = UIImage(named: "Share")
    var aboutImage = UIImage(named: "About")
    var helpImage = UIImage(named: "Help")

    @IBOutlet weak var currentMenuControl: UIBarButtonItem!

    @IBAction func currentMenuDisplay(sender: AnyObject) {

        if currentMenuControl.tag == 1 {

            ondemandSideBar.showSideBar(true)
            currentMenuControl.tag = 0

        } else {

            ondemandSideBar.showSideBar(false)
            currentMenuControl.tag = 1

        }

    }

    @IBOutlet weak var progressionMenuControl: UIBarButtonItem!

    @IBAction func progressionMenuDisplay(sender: AnyObject) {

        if progressionMenuControl.tag == 1 {

            ondemandRightSideBar.showSideBar(true)
            progressionMenuControl.tag = 0

        } else {

            ondemandRightSideBar.showSideBar(false)
            progressionMenuControl.tag = 1
        }
    }


    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.


    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func sideBarDidSelectButtonAtIndex(index: Int) {

        switch index {

         //segues
        }
    }

    func rightSideBarDidSelectButtonAtIndex(index: Int) {

        switch index {

         //segues
        }
    }

}

这是我尝试过的:
  • 我已经尝试改变 CGFloats 的定位,因为 SubViews 似乎
    从左边来。
  • 我重命名了所有 RightSideBar 变量和类名
    一切克服实例变量中的运行时混淆和
    类名。这包括重命名您在
    NSObject 子类和目标 View Controller 。
  • 我尝试在 viewDidLoad 方法中使用控制流
    按钮标签。我取消了滑动功能以显示菜单和
    添加按钮是因为我认为系统难以处理
    刷卡。
  • 我已经尝试在 NSObject 的 SideBar 子类文件中取消初始化。
    让我陷入困境的只是一个导致应用程序崩溃的无限循环
    登录后。
  • 然后我尝试在
    targetViewController.....DoubleMenuViewController 和
    单菜单 View Controller 。我回到了带有按钮的工作菜单
    在 SingleMenuViewController 中,但它仍然不会显示左侧和
    DoubleMenuViewController 中的右侧菜单。
  • 最后,我尝试取消初始化 DoubleMenuViewController 中的 SideBar(左侧 SideBar)和 RightSideBar。但是,当我将 println() 函数添加到我的所有部分时,调试器不会为我运行打印函数来获取对象的值,甚至不会显示类似 的类型状态。 “这个” .我添加了打印功能,因为我不确定我是否会知道何时发生取消初始化和重新初始化。

  • 似乎我的菜单是从 SideBar: NSObject 文件和 RightSideBar:NSObject 文件初始化的。我的意思是我的菜单是在我点击目标 View Controller 之前创建的。只要我能让编译器在同一个 View Controller 中初始化 SideBar 和 RightSideBar,这对我来说就不是问题,但它不会这样做。

    我只需要能够通过滑动或点击按钮来控制两个菜单。

    我想我的初始化程序相互覆盖有问题。

    但是,我不知道如何解决这个问题。我已经通读了 Swift 手册并阅读了互联网上的文章。我也搜索过 StackOverflow。

    最佳答案

    你问:

    How do I Initialize two instances of NSObject in the same view controller?



    撇开你为什么要处理 NSObject根本上(在 Objective-C 中,所有类都必须从 NSObject 子类化,最终在 Swift 中不再如此),如果你想实例化两个对象,你只需要为每个对象拥有一个属性。

    如果这些被延迟实例化,正如您的代码片段所暗示的那样,那么您必须确定引用该延迟实例化的属性的位置(例如,您可能会从“从边缘滑动”手势中触发它)或您有什么。在引用延迟实例化属性的代码中设置一个断点,并确保您完全到达那里。

    ——

    我对您的代码片段之一进行了一些观察。你说你正在像这样实例化你的侧边栏:
    var sideBar : SideBar?
    var ondemandSideBar : SideBar {
        get {
            if sideBar == nil {
                sideBar = SideBar(sourceView, menuItems, menuImage etc.)
                sideBar!.delegate
                SideBar.new()
            }
        }
    }
    

    我认为这不是你真正在做的,因为你没有设置委托(delegate),你们都在实例化 SideBar以及调用 new (您不应该在 Swift 中这样做),您没有返回值等。

    此外,具有由某些计算属性实例化的存储属性的模式具有特定的 Objective-C je ne sais quoi。我推断您想要一个延迟实例化的属性。如果是这样,我倾向于使用单个 lazy存储的属性(property)。然后我会使用闭包懒惰地设置该属性:

    我期待这样的模式
    protocol SideBarDelegate : class {                         // specify class so we can use `weak` reference
        func didChooseMenuItem(sender: SideBar, item: Int)
    }
    
    class SideBar {
        weak var delegate: SideBarDelegate?                    // make sure this is weak to avoid strong reference cycle
    }
    
    class ViewController: UIViewController, SideBarDelegate {
    
        lazy var sideBar: SideBar = {
            let _sideBar = SideBar(sourceView, menuItems, menuImage, etc.)
            _sideBar.delegate = self
            return _sideBar
        }()
    
        func didChooseMenuItem(sender: SideBar, item: Int) {
            // handle it here
        }
    
        // etc.
    }
    

    这样,sideBar在您引用 sideBar 之前不会被实例化在您的代码中的某个地方,但是当您这样做时,它将使用该闭包内的代码进行实例化。

    关于ios - 如何在同一个 ViewController 中初始化 NSObject 的两个实例 - Swift,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31728420/

    相关文章:

    ios - 如何从IOS中UiPickerView行的顶部和底部删除白色透明色

    ios - 如果注释标注与另一个注释重叠,则无法点击它?

    ios - 绘制前如何清除 subview 的内容

    ios - 通过滑动导航在 xib/nib 文件之间移动

    ios - 如何使用来自另一个 View Controller 的用户输入快速创建带有 TableView 单元格的列表

    ios - 如何创建取消按钮?

    ios - 如何快速比较颜色

    ios - UITableViewController 与 UIViewController

    SWIFT - 从第二个 ViewController 返回时变量重置

    swift - 带有参数 gestureRecognizer 的选择器