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

时间:2015-07-30 15:47:28

标签: 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() {

    }

}

这是正确的表格视图控制器:

//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。这是要初始化的左侧边栏:

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来破坏菜单时会发生一些事情。菜单甚至无法加载。但是,如果我在SingleMenuViewController中只调用SideBar:NSObject,那么只要我只调用一个菜单,代码就可以工作。在这个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
        }
    }

}

以下是我尝试的内容:

  1. 我尝试改变CGFloats的定位,因为SubViews看起来如此 从左边来。

  2. 我已重命名所有RightSideBar变量和类名 一切都是为了克服实例变量和运行时混淆 班级名称。这包括重命名您在其中看到的初始化程序 NSObject子类和目标视图控制器。

  3. 我尝试在viewDidLoad方法中使用控件流 按钮标记。我拿走了滑动功能来显示菜单和 添加按钮是因为我认为系统正在努力应对 Swipes。

  4. 我已尝试在NSObject的SideBar子类文件中取消初始化。 所有这些让我感到无限循环,导致应用程序崩溃 登录后。

  5. 然后我尝试了ondemand初始化 targetViewController ..... DoubleMenuViewController和 SingleMenuViewController。我回到了带按钮的工作菜单 在SingleMenuViewController中,它仍然不会显示左侧和 DoubleMenuViewController中的右侧菜单。

  6. 最后我尝试在DoubleMenuViewController中取消初始化SideBar(左侧边栏)和RightSideBar。但是,当我将println()函数添加到我的所有部分时,调试器不会为我运行打印功能以获取对象的值,甚至显示类型状态,如&#34;这&#34; 。我添加了打印功能,因为我不确定我是否知道何时进行了初始化和重新初始化。

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

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

    我认为我的初始化程序相互重叠有问题。

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

1 个答案:

答案 0 :(得分:1)

你问:

  

如何在同一视图控制器中初始化NSObject的两个实例?

抛开你为什么要处理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()
        }
    }
}

我不认为这是你真正在做的事情,因为你没有设置委托,你既要实例化SideBar又要调用new(你不应该这样做)从Swift做起,你没有返回一个值等等。

此外,具有由某些计算属性实例化的存储属性的模式具有某个Objective-C je ne sais quoi。我推断你想要一个懒惰的实例化属性。如果是这种情况,我倾向于使用单个lazy存储的属性。然后我会使用闭包来懒洋洋地设置该属性:

我希望像这种模式

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,但是当你这样做时,它将使用该闭包内的代码进行实例化。