【发布时间】:2015-07-30 15:47:27
【问题描述】:
请多多包涵。我是编程新手,也是 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 开始的地方。这是要初始化的左侧 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 子类和目标视图控制器。
我尝试在 viewDidLoad 方法中使用控制流 按钮标签。我取消了滑动功能以显示菜单和 添加按钮,因为我认为系统正在努力处理 滑动。
我尝试在 NSObject 的 SideBar 子类文件中取消初始化。 让我失望的只是一个导致应用程序崩溃的无限循环 登录后。
然后我尝试了按需初始化 targetViewController .....DoubleMenuViewController 和 单菜单视图控制器。我返回到带有按钮的工作菜单 在 SingleMenuViewController 但它仍然不会显示左侧和 DoubleMenuViewController 中的右侧菜单。
最后我尝试在 DoubleMenuViewController 中取消初始化 SideBar(左侧 SideBar)和 RightSideBar。但是,当我将 println() 函数添加到我的所有部分时,调试器不会为我运行打印函数来获取对象的值,甚至不会显示像 "This" 这样的类型化状态。我添加了打印功能,因为我不确定是否会知道取消初始化和重新初始化发生的时间。
看来我的菜单是从 SideBar: NSObject 文件和 RightSideBar:NSObject 文件初始化的。我的意思是我的菜单是在我点击目标视图控制器之前创建的。这对我来说不是问题,只要我可以让编译器在同一个 View Controller 中初始化 SideBar 和 RightSideBar,但它不会这样做。
我只需要能够通过滑动或点击按钮来控制这两个菜单。
我认为我的初始化程序相互覆盖有问题。
但是,我不知道如何解决这个问题。我已经阅读了 Swift 手册并阅读了互联网上的文章。我也搜索过 StackOverflow。
【问题讨论】:
-
这是一个很难回答的问题,因为它同时过于冗长(无意冒犯),但也没有足够的信息来重现问题(例如,我看不到这些菜单添加到视图层次结构)。您必须更简洁并提供MCVE。它也有错误的代码 sn-ps,但很难判断这些是原始代码中的问题(不可能,因为我看不到它可能如何编译)还是在创建问题。
-
你在哪里引用
ondemandSideBar和ondemandRightSideBar,它们懒惰地实例化那些SideBar和RightSideBar对象?是什么触发了这些对象的实例化?你看到他们被召唤了吗? -
很可能与手头的问题无关: 1. 顺便说一句,不要在 Swift 中调用
new方法。 2. 你的委托对象在这里有很强的引用循环。 3.如果左右这些菜单有自己的视图控制器,则需要在将它们的视图添加到视图层次结构之前实现自定义容器视图控制器调用(例如addChildViewController等)(否则视图层次结构和视图控制器层次结构是会失去同步。 -
Rob,我认为我的代码没有按照代码中的 cmets 所说的那样做。忽略代码中的 cmets。
Sidebar和RightSidebar的内容在DoubleMenuViewController中实现。我认为我输入初始化值的sideBar = SideBar(//values here)是初始化SideBar的原因。 OP 说,当我尝试打印在DoubleMenuViewController中创建变量的位置时,甚至在使用标签的按钮函数内部显示没有任何注册。我不明白您第三条评论中的第二点和第三点。 -
是的,
SideBar(...)是您实例化它所需的全部内容(丢失new())。但是您在计算属性中调用它,因此如果您从不引用该属性,则不会实例化条形图。关于第 3 点,请参阅custom view controller containers 上的 WWDC 视频。
标签: ios swift uiviewcontroller nsobject