UISwitch 被用户关闭但仍以编程方式打开

UISwitch switched off by user but is still programatically on

我正在使用 Swift 在 xcode 上试验 UISwitch。我把它放在有几个公司名称及其相应的开关的地方。从上到下,如果用户切换,例如 "Google" Switch on,那么他们就可以查看所选公司的 facebook 和 twitter。如果他们选择另一家公司,一旦他们打开那个开关,例如 "Samsung",Google 开关就会关闭,然后用户就可以看到三星的 facebook 和 twitter 页面。

我的问题是...从上到下,一切正常。我可以看到从 Google 到 samsung 的两个页面。但是如果我从三星回到 Google,google 开关打开但它仍然显示三星的页面。但是,如果我打开 saumsung 开关,关闭然后转到 google,它工作正常。

我的假设是,当另一个开关从下到上打开时,开关在视觉上看起来是关闭的,但它仍然以编程方式打开

我想知道是否有人遇到过类似的问题。如果没有,我希望这对以后遇到类似情况的人有所帮助

这是我的主视图控制器

import UIKit

   class ViewController: UIViewController {

@IBOutlet weak var GoogleSwitch: UISwitch!
@IBOutlet weak var SamsungSwitch: UISwitch!
@IBOutlet weak var FordSwitch: UISwitch!
@IBOutlet weak var ToyotaSwitch: UISwitch!
@IBOutlet weak var SquareEnixSwitch: UISwitch!
@IBOutlet weak var ABCBankSwitch: UISwitch!

var Google: Bool = false
var Samsung: Bool = false
var Ford: Bool = false
var Toyota:Bool = false
var SquareEnix :Bool = false
var ABCBank :Bool = false

override func viewDidLoad() {
    super.viewDidLoad()
 //   ABCBankSwitch.addTarget(self, action: Selector("switchIsChanged:"), forControlEvents: UIControlEvents.ValueChanged)
    // Do any additional setup after loading the view, typically from a nib.
}

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

@IBAction func ActiveGoogle(sender: UISwitch) {

      if sender.on == true
        {
            GoogleSwitch.on = true
            SamsungSwitch.on = false
            ToyotaSwitch.on = false
            SquareEnixSwitch.on = false
            ABCBankSwitch.on = false
            Google = true

   // GoogleSwitch.on = true


    }
  else
   { Google = false
    sender.on = false
    }

   // sender.on  = false
}

@IBAction func ActiveSamsung(sender: UISwitch) {

 if sender.on == true
      {
            GoogleSwitch.on = false
            SamsungSwitch.on = true
            FordSwitch.on = false
            ToyotaSwitch.on = false
            SquareEnixSwitch.on = false
            ABCBankSwitch.on = false
            Samsung = true

    }
   else

    {sender.on = false
        Samsung = false}

}

@IBAction func ActiveFord(sender: UISwitch) {
  if sender.on == true
    {Ford = true
        GoogleSwitch.on = false
        SamsungSwitch.on = false
        FordSwitch.on  = true
        ToyotaSwitch.on = false
        SquareEnixSwitch.on = false
        ABCBankSwitch.on = false
    }
   else
  { if sender.on == false {
    Ford = false}

}
}

@IBAction func ActiveToyota(sender: UISwitch) {
   if sender.on == true
    { Toyota = true
        GoogleSwitch.on = false
        SamsungSwitch.on = false
        FordSwitch.on = false
        ToyotaSwitch.on = true
        SquareEnixSwitch.on = false
        ABCBankSwitch.on = false
    }
    else
    { Toyota = false}
}
@IBAction func ActiveEnix(sender: UISwitch) {
if sender.on == true
    { SquareEnix = true
        GoogleSwitch.on = false
        SamsungSwitch.on = false
        FordSwitch.on = false
        ToyotaSwitch.on = false
        //SquareEnixSwitch.on = true
        ABCBankSwitch.on = false
    }
    else
    { SquareEnix = false
   // sender.on = false
    }
}

@IBAction func ActiveABC(sender: UISwitch) {
  if sender.on == true
    { ABCBank = true
        ABCBankSwitch.setOn(true, animated: true)
        GoogleSwitch.on = false
        SamsungSwitch.on = false
        FordSwitch.on = false
        ToyotaSwitch.on = false
        SquareEnixSwitch.on = false


        }
    }
else
{
    ABCBankSwitch.setOn(false, animated: true)
    ABCBank = false
   // sender.on = false

  }

}

}

这是我的 FacebookViewController。 (没有打开推特,因为它几乎与 Facebook 相同)

 import UIKit

 class FacebookViewController: UIViewController{
  var webAddress: String = ""

@IBOutlet weak var CompanyFB: UIWebView!

override func viewWillAppear(animated: Bool) {
    let myCompany: ViewController = self.tabBarController!.viewControllers![0] as! ViewController

    let showGoogle: Bool = myCompany.Google
    let showSamsung: Bool = myCompany.Samsung
    let showFord: Bool = myCompany.Ford
    let showToyota: Bool = myCompany.Toyota
    let showEnix: Bool = myCompany.SquareEnix
    let showBank:Bool = myCompany.ABCBank


    if showGoogle  {
        webAddress = "https://www.facebook.com/Google/"
        //myCompany.GoogleSwitch.on = false  had this to test. either way is still doesnt work

      //  CompanyFB.loadRequest(NSURLRequest(URL: NSURL(string: webAddress)!))
    }

    if showSamsung  {
        webAddress = "https://www.facebook.com/SamsungUSA"
       // myCompany.SamsungSwitch.on = false

      //  CompanyFB.loadRequest(NSURLRequest(URL: NSURL(string: webAddress)!))
    }

     if showFord  {
        webAddress = "https://www.facebook.com/ford/"

      //  CompanyFB.loadRequest(NSURLRequest(URL: NSURL(string: webAddress)!))
    }

    if showToyota {
        webAddress = "https://www.facebook.com/toyota"


       // CompanyFB.loadRequest(NSURLRequest(URL: NSURL(string: webAddress)!))
    }
   if  showEnix  {
       webAddress = "https://www.facebook.com/SquareEnix"

    }

 if showBank  {
        webAddress = "https://www.facebook.com/ABC-Bank-132047286857188/"


    }

 CompanyFB.loadRequest(NSURLRequest(URL: NSURL(string: webAddress)!))


}


override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
}

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

}

你的问题是你没有让你的独立布尔值与你的开关保持同步。考虑这段代码:

@IBAction func ActiveGoogle(sender: UISwitch) {    
    if sender.on == true {
        GoogleSwitch.on = true
        SamsungSwitch.on = false
        ToyotaSwitch.on = false
        SquareEnixSwitch.on = false
        ABCBankSwitch.on = false
        Google = true
    }
    else { 
        Google = false
        sender.on = false
    }
}

如果我更改 "Google" 开关,那么 Google 变量将相应地设置为 true/false。此代码还关闭所有其他开关,但它不会更改布尔关联变量。所以,如果在 selecting Google 之后我然后 select "Samsung",Google 开关将被关闭,但 Google 变量仍然是是的。

您可以使用计算的 属性 而不是单独的布尔值:

var Google: Bool {
    return self.GoogleSwitch.on
}

等等。

另外,按照惯例,变量和函数应该以小写字母开头,所以应该是 var googlefunc activateGoogle

我假设您的 IBAction 已连接到 ValueChanged 事件,并且您希望它们在两种情况下触发:当您通过触摸它来更改开关时;或者当您更改 on 属性.

的值时

如果是这样,问题是事件不会在第二种情况下触发,只会在第一种情况下触发。因此,一旦 Google 设置为 true,将其设置回 false 的唯一方法是将开关关闭。

由于您的模型只希望打开一个开关,因此您可以使用一个包含应该打开的开关的变量。当您触摸一个开关时,只需更新那个变量并重新显示所有变量。对此变量使用 enum 会很有帮助。沿着:

    enum Switches {
        case None
        case Google
        case Samsung
    }

    var onSwitch = Switches.None

然后按照以下行在每个 IBAction 中编写代码:

@IBAction func ActiveGoogle(sender: UISwitch) {
      if sender.on == true {
          onSwitch = Switches.Google
          updateSwitches()
      }
}

updateSwitches 看起来像:

func updateSwitches() {
    GoogleSwitch.on = (onSwitch == Switches.Google)
    SamsungSwitch.on = (onSwitch == Switches.Samsung)
}

这里发生了一些事情,有些与您的问题无关,但我也会对它们进行评论,以便您作为编码员可以改进。

1) Swift 的约定要求您命名变量和方法以小写字母开头。所以 GoogleSwitch 应该是 googleSwitch 等。另外,尝试使用名称进行描述。在您的 FacebookViewController 中,您有一个变量 myCompany 用于 ViewController class。首先,class 应该被称为 MyCompanyViewController 这样的名字,这样你就知道它是哪个视图控制器了。然后 myCompany 变量可以被称为 myCompanyViewControllerCompanyFB 应该类似于 companyFBWebView.

2) 你真的可以在这里简化你的代码。对所有开关使用单个 IBAction。一个常见的问题(在这里可能是一个问题)是,当您在 Interface Builder 中复制和粘贴控件时,它有时也会复制分配的操作,然后您添加另一个,因此每次切换时它都会调用两个方法。通过使用单一方法,您可以节省大量重复代码并避免此问题。

你的整个第一个ViewControllerclass可以浓缩成这个(然后把你所有的开关都连接到同一个IBOutletswitchToggled::

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var googleSwitch: UISwitch!
    @IBOutlet weak var samsungSwitch: UISwitch!
    @IBOutlet weak var fordSwitch: UISwitch!
    @IBOutlet weak var toyotaSwitch: UISwitch!
    @IBOutlet weak var squareEnixSwitch: UISwitch!
    @IBOutlet weak var abcBankSwitch: UISwitch!

    @IBAction func switchToggled(sender: UISwitch) {
        // Remember the state of the triggered switch because we're about to turn it off
        let newState: Bool = sender.on

        googleSwitch.on = false
        samsungSwitch.on = false
        fordSwitch.on = false
        toyotaSwitch.on = false
        squareEnixSwitch.on = false
        abcBankSwitch.on = false

        // Restore the state of the switch
        sender.on = newState
    }
}

3) 避免对同一事物使用重复变量,Google 等的 Bool 应该与开关相同,因此只需使用 switch.on 值。编辑:(或如 Paulw11 所述,使用计算的 属性)。

4) 当使用 if 来测试一个变量状态,或者像您在 FacebookViewController class 中所做的那样测试多个变量状态时,只有一种可能的情况应该发生, 使用 else if 而不是多个 if。在你的情况下,你一次触发两个或多个案例(由于你的其他错误)。如果您使用 else if 子句,您只会触发一个子句,并且您可能会更早地缩小其他错误的范围。

    if showGoogle {
        webAddress = "https://www.facebook.com/Google/"
    }
    else if showSamsung {
        webAddress = "https://www.facebook.com/SamsungUSA/"
    }
    ...

5) 扩展 #4,您可以更改它以利用 Swift 强大的 enum 功能。

import UIKit

class FacebookViewController: UIViewController {

    enum Company: String {
        case Google = "https://www.facebook.com/Google/"
        case Samsung = "https://www.facebook.com/SamsungUSA/"
        case Ford = "https://www.facebook.com/ford/"
        case Toyota = "https://www.facebook.com/toyota/"
        case SquareEnix = "https://www.facebook.com/SquareEnix/"
        case ABCBank = "https://www.facebook.com/ABC-Bank-132047286857188/"
    }

    var company: Company = .Google // Default to Google

    @IBOutlet weak var companyFBWebView: UIWebView!

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)

        let myCompanyViewController: ViewController = self.tabBarController!.viewControllers![0] as! ViewController

        if myCompanyViewController.googleSwitch.on {
            company = .Google
        }
        else if myCompanyViewController.samsungSwitch.on {
            company = .Samsung
        }
        else if myCompanyViewController.fordSwitch.on {
            company = .Ford
        }
        else if myCompanyViewController.toyotaSwitch.on {
            company = .Toyota
        }
        else if myCompanyViewController.squareEnixSwitch.on {
            company = .SquareEnix
        }
        else if myCompanyViewController.abcBankSwitch.on {
            company = .ABCBank
        }

        if let url = NSURLRequest(URL: NSURL(string: company.rawValue)) {
            companyFBWebView.loadRequest(url)
        }
    }
}

6) 在Swift中,避免像瘟疫一样使用!。理想情况下,您只会将它用于 IBOutlet 和您确定存在某个值的其他情况。 let myCompanyViewController: ViewController = self.tabBarController!.viewControllers![0] as! ViewController 行在某些情况下可能会崩溃。可能是由于时间问题,或者您可能会在以后对代码进行其他更改。使用 if let 检查选项并优雅地处理错误更安全。

7) 我刚刚在校对时注意到另一个问题。任何时候*你 override 来自超级 class 的方法,确保你也调用了超级的版本。所以你的 viewWillAppear(animated:) 等调用需要调用超级版本,否则你会变得非常奇怪,很难追踪错误。

  • 我在 #7 中的 Anytime 上加了一个星号,因为在某些情况下你故意不想调用 super 方法,但这种情况很少见,到时候你就会知道了。