Swift: If Let with Multiple Cell Classes - ios

I have a UITableView with 2 prototype cells: CourseCell and BllCell. These cells contain a UISlider and an IBAction is in place on the main ViewController.
After the slider has finished moving the following action is triggered:
#IBAction func sliderFinishedMoving(_ sender: Any) {
if let slider = sender as? gradeSlider {
if let superview = slider.superview {
if let cell = superview.superview as? CourseCell {
let selectedSemester = cell.activeSemester
let selectedIndexPath = courseTable.indexPath(for: cell)!
let selectedCourse = courseTypes[selectedIndexPath.section].courses[selectedIndexPath.row]
if selectedCourse.examType == "" && selectedCourse.examCourse == true {
print("please select the exam type before entering grades")
slider.value = 0.0
cell.gradeSliderLabel.frame.origin.x = slider.thumbCenterX - (cell.gradeSliderLabel.frame.width/2)
cell.gradeSliderLabel.text = "0"
return
}
print(selectedIndexPath.section, selectedIndexPath.row)
slider.value = round(slider.value)
cell.gradeSliderLabel.frame.origin.x = slider.thumbCenterX - (cell.gradeSliderLabel.frame.width/2)
switch(selectedSemester) {
case 1:
selectedCourse.semester1Grade = Int(slider.value)
break
case 2:
selectedCourse.semester2Grade = Int(slider.value)
break
case 3:
selectedCourse.semester3Grade = Int(slider.value)
break
case 4:
selectedCourse.semester4Grade = Int(slider.value)
break
case 5:
selectedCourse.examGrade = Int(slider.value)
break
case 6:
selectedCourse.oralGrade = Int(slider.value)
break
default:
break
}
courseTable.reloadData()
}
if let cell = superview.superview as? BllCell {
let selectedSemester = cell.activeSemester
let selectedIndexPath = courseTable.indexPath(for: cell)!
let selectedCourse = courseTypes[selectedIndexPath.section].courses[selectedIndexPath.row]
if selectedCourse.examType == "" && selectedCourse.examCourse == true {
print("please select the exam type before entering grades")
slider.value = 0.0
cell.gradeSliderLabel.frame.origin.x = slider.thumbCenterX - (cell.gradeSliderLabel.frame.width/2)
cell.gradeSliderLabel.text = "0"
return
}
print(selectedIndexPath.section, selectedIndexPath.row)
slider.value = round(slider.value)
cell.gradeSliderLabel.frame.origin.x = slider.thumbCenterX - (cell.gradeSliderLabel.frame.width/2)
switch(selectedSemester) {
case 1:
selectedCourse.semester1Grade = Int(slider.value)
break
case 2:
selectedCourse.semester2Grade = Int(slider.value)
break
case 3:
selectedCourse.semester3Grade = Int(slider.value)
break
case 4:
selectedCourse.semester4Grade = Int(slider.value)
break
case 5:
selectedCourse.examGrade = Int(slider.value)
break
case 6:
selectedCourse.oralGrade = Int(slider.value)
break
default:
break
}
courseTable.reloadData()
}
}
}
}
As you can see, there is duplicate code. Is it possible to fire if let cell ... with both CourseCell and BllCell in order to access the cell.activeSemester variable in both without having to duplicate the function?

You have to make a common parent for both BllCell CourseCell if you are performing the same instruction.

There are numerous issues with this code but the immediate answer to your specific question is to use a protocol:
protocol GradeSliderCell: class {
var activeSemester: Int { get }
var gradeSliderLabel: UILabel! { get }
}
Both CourseCell and BllCell should conform to this protocol.
That cuts the duplicated code in half:
#IBAction func sliderFinishedMoving(_ sender: Any) {
guard let slider = sender as? gradeSlider else { return }
guard let superview = slider.superview else { return }
if let cell = superview.superview as? GradeSliderCell {
let selectedSemester = cell.activeSemester
let selectedIndexPath = courseTable.indexPath(for: cell as! UITableViewCell)!
let selectedCourse = courseTypes[selectedIndexPath.section].courses[selectedIndexPath.row]
if selectedCourse.examType == "" && selectedCourse.examCourse == true {
print("please select the exam type before entering grades")
slider.value = 0.0
cell.gradeSliderLabel.frame.origin.x = slider.thumbCenterX - (cell.gradeSliderLabel.frame.width/2)
cell.gradeSliderLabel.text = "0"
return
}
print(selectedIndexPath.section, selectedIndexPath.row)
slider.value = round(slider.value)
cell.gradeSliderLabel.frame.origin.x = slider.thumbCenterX - (cell.gradeSliderLabel.frame.width/2)
switch(selectedSemester) {
case 1:
selectedCourse.semester1Grade = Int(slider.value)
case 2:
selectedCourse.semester2Grade = Int(slider.value)
case 3:
selectedCourse.semester3Grade = Int(slider.value)
case 4:
selectedCourse.semester4Grade = Int(slider.value)
case 5:
selectedCourse.examGrade = Int(slider.value)
case 6:
selectedCourse.oralGrade = Int(slider.value)
default:
break
}
courseTable.reloadData()
}
}

Related

Swift considerable jump in tableview with just one query in cellforrow

I have the following code in my willDisplay:
func tableView(_: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
guard case let cell as L_LocCell = cell else {
return
}
let subC = subContractors[indexPath.row]
cell.backgroundColor = .clear
cell.locName = subC.companyname
cell.locCode = subC.region
/*if let sType = Helper_Types.getType(subC.type)
{
cell.add = sType.name
}
else {
cell.add = ""
}*/
switch subC.status {
case 3:
cell.catColor = UIColor(rgba: Palette.class_bad)
cell.catName = "Declined"
break
case 2:
cell.catColor = UIColor(rgba: Palette.class_good)
cell.catName = "Approved"
break
case 1:
cell.catColor = UIColor(rgba: Palette.class_warn)
cell.catName = "Pending"
break
case 4:
cell.catColor = UIColor(rgba: Palette.ok)
cell.catName = "Approved with Exception"
break
default:
cell.catColor = companyMed
cell.catName = "Unknown"
break
}
if subConPicDir != nil {
let filename = subConPicDir!.appendingPathComponent(subC.subcontractorId.description+".jpg")
cell.thumbImg.kf.setImage(
with: filename,
placeholder: UIImage(named: "ic_supplier")!,
options: [.transition(.fade(1)), .cacheOriginalImage],
progressBlock: { receivedSize, totalSize in
},
completionHandler: { result in
print(result)
})
}
else{
cell.thumbImg.image = UIImage(named: "ic_supplier")
}
}
There is a considerable difference in the smoothness of the scrolling when i put back in the commented out portion.
This is just a query to retrieve some info, i didn't have directly in my tableview's data source. How can I optimise this?
public static func getType(_ tid: Int) -> Types?
{
do {
var realm : Realm? = try Realm()
let predicate = NSPredicate(format: "_id = %d", tid);
let types = realm!.objects(STD_type.self).filter(predicate);
realm = nil
if types.count > 0
{
return Types(st : types.first!)
} else {
return nil;
}
} catch let error as NSError {
print("error realm \(error.localizedDescription)")
return nil
}
}
A Realm lookup is usually quite fast but it is still an async task which takes time and may even run on another thread.
Rather than doing this every time you attempt to render a cell I would suggest that you fetch all Types (maybe in viewDidLoad) and then just filter in cellForRow
Then you can just do something like
cell.add = types.first { $0.id == subC.type } ?? ""
Which is not aysnc and will be much faster and more responsive
If for some reason you can't fetch all types, I would at least cache the results as you get them.

ios-charts combined chart: bars going past right axis of chart

I'm trying to make something similar to this
Im going to have 4 BarChartDataSets grouped, and 2 LineChartDataSets, each data set has 7 data points, the user can add or remove these datasets at will
The bars seem to be grouping fine, and the line chart shows all 7 points
but as I add more BarChartDataSets to the chart, the bars go off the right side of the chart, the line chart stays the same, here is an image sequence of me starting with a single LineChartDataSet, then adding BarChartDataSets one by one, some of the bars have a value of 0, so its hard to see the group, look for the 0 label at the bottom
How can i stop the bars from going off the right of the chart?
Here is the code:
//get data and values from DataMOs in the activeFeeds
var lineChartDataSets = [LineChartDataSet]()
var barChartDataSets = [BarChartDataSet]()
for (key, dayValuesArray) in valuesByFeed {
var barChartDataEntries = [BarChartDataEntry]()
var lineChartDataEntries = [ChartDataEntry]()
var lineChartDataSet: LineChartDataSet!
var barChartDataSet: BarChartDataSet!
var dataEntry: ChartDataEntry
for (index, value) in (dayValuesArray?.enumerated())! {
//create line chart for Demand and Prod feeds
//create bar chart for every other feed
if key == "Demand" || key == "Prod"{
dataEntry = ChartDataEntry(x: Double(self.activeFeeds.count * index), y: Double(value)!)
lineChartDataEntries.append(dataEntry)
} else {
dataEntry = BarChartDataEntry(x: Double(self.activeFeeds.count * index), y: Double(value)!)
barChartDataEntries.append(dataEntry as! BarChartDataEntry)
}
}
//create line chart data set for Demand and Prod feeds
//create bar chart data set for every other feed
if key == "Demand" || key == "Prod"{
lineChartDataSet = LineChartDataSet(values: lineChartDataEntries, label: key)
lineChartDataSet.drawCirclesEnabled = false
} else {
barChartDataSet = BarChartDataSet(values: barChartDataEntries, label: key)
}
switch key {
case "Solar":
barChartDataSet.setColors(UIColor.orange.withAlphaComponent(1.0))
barChartDataSet.valueTextColor = UIColor.white
break
case "Wind":
barChartDataSet.setColors(UIColor.blue.withAlphaComponent(1.0))
barChartDataSet.valueTextColor = UIColor.white
break
case "Battery":
barChartDataSet.setColors(UIColor.green.withAlphaComponent(1.0))
barChartDataSet.valueTextColor = UIColor.white
break
case "Gen":
barChartDataSet.setColors(UIColor.red.withAlphaComponent(1.0))
barChartDataSet.valueTextColor = UIColor.white
break
case "Demand":
lineChartDataSet.setColors(UIColor.purple.withAlphaComponent(1.0))
lineChartDataSet.valueTextColor = UIColor.white
lineChartDataSet.drawFilledEnabled = true
lineChartDataSet.fillColor = UIColor.purple.withAlphaComponent(0.8)
break
case "Prod":
lineChartDataSet.setColors(UIColor.magenta.withAlphaComponent(1.0))
lineChartDataSet.valueTextColor = UIColor.white
lineChartDataSet.drawFilledEnabled = true
lineChartDataSet.fillColor = UIColor.magenta.withAlphaComponent(0.8)
break
default:
break
}
//append to correct data set array
if key == "Demand" || key == "Prod"{
lineChartDataSets.append(lineChartDataSet)
} else {
barChartDataSets.append(barChartDataSet)
}
}
//set chart data
let chartData = CombinedChartData()
chartData.barData = BarChartData(dataSets: barChartDataSets)
chartData.lineData = LineChartData(dataSets: lineChartDataSets)
let activeFeedsCount = self.activeFeeds.count
if activeFeedsCount > 0 {
self.combinedChartView.data = chartData
if chartData.barData.dataSetCount > 1 {
self.combinedChartView.barData?.groupBars(fromX: 0, groupSpace: 1.0, barSpace: 0.5)
self.combinedChartView.notifyDataSetChanged()
}
} else {
self.combinedChartView.data = CombinedChartData()
self.combinedChartView.noDataText = "No Feeds To Show"
}
I was not able to reproduce the problem with the 0 label, but it is possible to use combinedChart.xAxis.axisMaximum to make sure you can see all the bars to the right.
let activeFeeds = 6
func dataSet() {
combinedChart.isUserInteractionEnabled = true
combinedChart.scaleXEnabled = false
combinedChart.scaleYEnabled = false
combinedChart.dragEnabled = true
//combinedChart.xAxis.axisMinimum = 0.0
combinedChart.xAxis.axisMaximum = 100.0
//get data and values from DataMOs in the activeFeeds
var lineChartDataSets = [LineChartDataSet]()
var barChartDataSets = [BarChartDataSet]()
combinedChart.setVisibleXRange(minXRange: 0.0, maxXRange: 26.0)
let arr1 = [17000,16500,16800,16700,17900,17100,18000]
let arr2 = [17000,17500,16900,16800,17200,17105,17000]
let valuesByFeed = ["Solar":arr1, "Wind": arr2, "Battery": arr1, "Gen":arr1, "Demand":arr1, "Prod":arr1]
for (key, dayValuesArray) in valuesByFeed {
var barChartDataEntries = [BarChartDataEntry]()
var lineChartDataEntries = [ChartDataEntry]()
var lineChartDataSet: LineChartDataSet!
var barChartDataSet: BarChartDataSet!
var dataEntry: ChartDataEntry
for (index, value) in (dayValuesArray.enumerated()) {
//create line chart for Demand and Prod feeds
//create bar chart for every other feed
if key == "Demand" || key == "Prod"{
dataEntry = ChartDataEntry(x: Double(self.activeFeeds * index), y: Double(value))
lineChartDataEntries.append(dataEntry)
} else {
dataEntry = BarChartDataEntry(x: Double(self.activeFeeds * index), y: Double(value))
barChartDataEntries.append(dataEntry as! BarChartDataEntry)
}
}
//create line chart data set for Demand and Prod feeds
//create bar chart data set for every other feed
if key == "Demand" || key == "Prod"{
lineChartDataSet = LineChartDataSet(values: lineChartDataEntries, label: key)
lineChartDataSet.drawCirclesEnabled = false
} else {
barChartDataSet = BarChartDataSet(values: barChartDataEntries, label: key)
}
switch key {
case "Solar":
print("case solar")
barChartDataSet.setColors(UIColor.orange.withAlphaComponent(1.0))
barChartDataSet.valueTextColor = UIColor.white
break
case "Wind":
print("case wind")
barChartDataSet.setColors(UIColor.blue.withAlphaComponent(1.0))
barChartDataSet.valueTextColor = UIColor.white
break
case "Battery":
print("case battery")
barChartDataSet.setColors(UIColor.green.withAlphaComponent(1.0))
barChartDataSet.valueTextColor = UIColor.white
break
case "Gen":
print("case gen")
barChartDataSet.setColors(UIColor.red.withAlphaComponent(1.0))
barChartDataSet.valueTextColor = UIColor.white
break
case "Gen2":
print("case gen")
barChartDataSet.setColors(UIColor.red.withAlphaComponent(1.0))
barChartDataSet.valueTextColor = UIColor.white
break
case "Gen3":
print("case gen")
barChartDataSet.setColors(UIColor.red.withAlphaComponent(1.0))
barChartDataSet.valueTextColor = UIColor.white
break
case "Gen4":
print("case gen")
barChartDataSet.setColors(UIColor.red.withAlphaComponent(1.0))
barChartDataSet.valueTextColor = UIColor.white
break
case "Demand":
print("case demand")
lineChartDataSet.setColors(UIColor.purple.withAlphaComponent(1.0))
lineChartDataSet.valueTextColor = UIColor.white
lineChartDataSet.drawFilledEnabled = true
lineChartDataSet.fillColor = UIColor.purple.withAlphaComponent(0.8)
break
case "Prod":
print("case prod")
lineChartDataSet.setColors(UIColor.magenta.withAlphaComponent(1.0))
lineChartDataSet.valueTextColor = UIColor.white
lineChartDataSet.drawFilledEnabled = true
lineChartDataSet.fillColor = UIColor.magenta.withAlphaComponent(0.8)
break
default:
break
}
//append to correct data set array
if key == "Demand" || key == "Prod"{
lineChartDataSets.append(lineChartDataSet)
} else {
barChartDataSets.append(barChartDataSet)
}
}
//set chart data
let chartData = CombinedChartData()
print("bar count: \(barChartDataSets.count)")
print("line count: \(lineChartDataSets.count)")
chartData.barData = BarChartData(dataSets: barChartDataSets)
chartData.lineData = LineChartData(dataSets: lineChartDataSets)
let activeFeedsCount = self.activeFeeds
if activeFeedsCount > 0 {
self.combinedChart.data = chartData
if chartData.barData.dataSetCount > 1 {
self.combinedChart.barData?.groupBars(fromX: 0, groupSpace: 1.0, barSpace: 0.5)
self.combinedChart.notifyDataSetChanged()
}
} else {
self.combinedChart.data = CombinedChartData()
self.combinedChart.noDataText = "No Feeds To Show"
}
}

Implementing iCloud Key-Value Storage with Swift

I am having troubles with implementing key-value storage into my app. All my iCloud associated code is in my ViewController and it is as follows:
import UIKit
import CloudKit
import NotificationCenter
var purchased = [[Bool]]() {
didSet {
instance.saveToiCloud()
print("SAVED")
}
}
var rockAmount = 0 {
didSet {
instance.saveToiCloud()
print("SAVED")
}
}
var goldAmount = 0 {
didSet {
instance.saveToiCloud()
print("SAVED")
}
}
var adBlock = false {
didSet {
instance.saveToiCloud()
print("SAVED")
}
}
var instance = GameViewController()
class GameViewController: UIViewController {
var iCloudKeyStore: NSUbiquitousKeyValueStore?
var interstitial: GADInterstitial!
var rewardAd = GADRewardBasedVideoAd()
var instRequest = receivingInst.GameScene //Placeholder
var instCatch = false
var rewardCatch = false
override func viewDidLoad() {
super.viewDidLoad()
//Set up iCloud Key-Value Storage
iCloudKeyStore = NSUbiquitousKeyValueStore()
iCloudKeyStore?.synchronize()
//Retrieve Assets from database
retrieveAssets()
NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.ubiquitousKeyValueStoreDidChange), name: NSUbiquitousKeyValueStore.didChangeExternallyNotification, object: iCloudKeyStore)
instance = self
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
//if let scene = SKScene(fileNamed: "GameScene") {
if let scene = SKScene(fileNamed: "LaunchScene") {
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill //.fill
// Present the scene
view.presentScene(scene)
}
view.ignoresSiblingOrder = true
//view.showsFPS = true
//view.showsPhysics = true
}
}
func retrieveAssets() {
//notFirst is to determine if it is the first ti
let notFirst = UserDefaults.standard.bool(forKey: "notFirst")
if !notFirst {
//Create iCloud References
var c = 0
while c < 4 {
var keyMake = ""
switch c {
case 0: keyMake = "purchasedCloud"
saveToiCloudArray(purchased, keyMake)
case 1: keyMake = "goldCloud"
saveToiCloudInt(0, keyMake)
case 2: keyMake = "rocksCloud"
saveToiCloudInt(0, keyMake)
case 3: keyMake = "adBlockCloud"
saveToiCloudBool(false, keyMake)
default: break
}
c += 1
}
print("SET")
}
//Retrieve iCloud Data
getValuesFromiCloud()
}
func ubiquitousKeyValueStoreDidChange(notification: NSNotification) {
let alert = UIAlertController(title: "Change detected",
message: "iCloud key-value-store change detected",
preferredStyle: UIAlertControllerStyle.alert)
let cancelAction = UIAlertAction(title: "OK",
style: .cancel, handler: nil)
alert.addAction(cancelAction)
self.present(alert, animated: true,
completion: nil)
getValuesFromiCloud()
}
func iCloudGetInt(_ key: String) -> Int {
var str = 0
if let saved = iCloudKeyStore?.object(forKey: key) {
print("B-INT\(saved)")
str = saved as! Int
print("A-INT\(saved)")
} else {
str = -10
print("IntFailed")
}
return str
}
func iCloudGetArray(_ key: String) -> [[Bool]] {
var str = [[Bool]]()
if let saved = iCloudKeyStore?.array(forKey: key){
print("B-AR\(saved)")
str = saved as! [[Bool]]
print("A-AR\(saved)")
} else {
str = [[]]
print("ArFailed")
}
return str
}
func iCloudGetBool(_ key: String) -> Bool {
var str = false
if let saved = iCloudKeyStore?.bool(forKey: key){
print("B-BOOL\(saved)")
str = saved as! Bool
print("A-BOOL\(saved)")
} else {
str = false
print("BoolFailed")
}
return str
}
//Set if stored icloud value is greater than current (on button activation)
func saveToiCloudArray(_ txt: [[Bool]],_ key: String) {
iCloudKeyStore?.set(txt, forKey: key)
//iCloudKeyStore?.synchronize()
}
func saveToiCloudInt(_ txt: Int,_ key: String) {
iCloudKeyStore?.set(txt, forKey: key)
//iCloudKeyStore?.synchronize()
}
func saveToiCloudBool(_ txt: Bool,_ key: String) {
iCloudKeyStore?.set(txt, forKey: key)
//iCloudKeyStore?.synchronize()
}
func getValuesFromiCloud() {
var c = 0
while c < 4 {
var keyMake = ""
switch c {
case 0: keyMake = "purchasedCloud"
let ar = iCloudGetArray(keyMake)
if !ar.isEmpty {
purchased = ar
UserDefaults.standard.set(purchased, forKey: "purchased")
} else {
print("Error\(keyMake)")
}
case 1: keyMake = "goldCloud"
let g = iCloudGetInt(keyMake)
if g != -10 {
goldAmount = g
UserDefaults.standard.set(goldAmount, forKey: "goldAmount")
} else {
print("Error\(keyMake)")
}
case 2: keyMake = "rocksCloud"
let r = iCloudGetInt(keyMake)
if r != -10 {
rockAmount = r
UserDefaults.standard.set(rockAmount, forKey: "rockAmount")
} else {
print("Error\(keyMake)")
}
case 3: keyMake = "adBlockCloud"
let r = iCloudGetBool(keyMake)
adBlock = r
UserDefaults.standard.set(adBlock, forKey: "adBlock")
default: break
}
c += 1
}
print(purchased, rockAmount, goldAmount)
}
func saveToiCloud() {
var c = 0
while c < 4 {
var keyMake = ""
switch c {
case 0: keyMake = "purchasedCloud"
saveToiCloudArray(purchased, keyMake)
case 1: keyMake = "goldCloud"
saveToiCloudInt(goldAmount, keyMake)
case 2: keyMake = "rocksCloud"
saveToiCloudInt(rockAmount, keyMake)
case 3: keyMake = "adBlockCloud"
saveToiCloudBool(adBlock, keyMake)
default: break
}
c += 1
}
}
[I realise that the code is not optimised and is not very clean but it's because I have been trying out many different things]
I have enabled iCloud in my Capabilities and done everything for the Provisioning Profile like this (the container exists and is valid):
I was wondering that maybe my issue is one of 2 things:
My code is meant to be in the AppDelegate and not in the ViewController.
OR
I need to write an entitlement here (which is accessible by the .entitlements file):
The highlighted red section is the one I am thinking to change (the iCloud Key-Value Store). Am I meant to write my own thing instead of $(TeamIdentifierPrefix)$(CFBundleIdentifier)? It says that is com.apple.developer.ubiquity-kvstore-identifier but what does this mean and how should I fill it out if I need to (e.g. what is the ubiquity-kvstore-identifier)?
Any sort of help and guidance would be greatly appreciated. Thank you.
The solution I found was to use the default container and not the specified container for iCloud. I'm not sure what the real difference between the 2 is but changing to this worked for me.
Also, I'm not sure if this helped solve getting iCloud key-value data to be stored but I put the code into the AppDelegate instead of the ViewController.

Bridging 'NSNumber' to 'Int' warning

Is this warning anything that I should be concerned about?
If so what would be a solution?
this is my function :
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? ProfileViewController{
let cell = sender as! UITableViewCell
let selectedRow = myTableView.indexPath(for: cell)!.row
switch (mySegmentedControl.selectedSegmentIndex){
case 0:
destination.nameVar = userSFList[selectedRow].name!
destination.imageOneURL = userSFList[selectedRow].image!
destination.bioVar = userSFList[selectedRow].bio!
if let image2 = userSFList[selectedRow].imageTwo {
destination.imageTwoUrl = image2 }
if let contactInt = userSFList[selectedRow].contact as? Int {
destination.contact = contactInt
}
break
case 1:
destination.nameVar = userEBList[selectedRow].name!
destination.imageOneURL = userEBList[selectedRow].image!
destination.imageTwoUrl = userEBList[selectedRow].imageTwo!
if let contactInt = userEBList[selectedRow].contact as? Int {
destination.contact = contactInt
}
break
case 2:
destination.nameVar = userSFOList[selectedRow].name!
destination.imageOneURL = userSFOList[selectedRow].image!
if let contactInt = userSFOList[selectedRow].contact as? Int {
destination.contact = contactInt
}
break
case 3:
destination.nameVar = userSJList[selectedRow].name!
destination.imageOneURL = userSJList[selectedRow].image!
if let contactInt = userSJList[selectedRow].contact as? Int {
destination.contact = contactInt
}
break
default:
break
}
}
}
I am using a segmented control with four different segments and pulling the data using firebase.
My personal rule is always zero warnings.
Better safe than sorry.
Is contact an Optional? If so...
You could use Optional Binding:
if let contactInt = userSFOList[selectRow].contact as? Int {
destination.contact = contactInt
}
Or the Nil-Coalescing Operator:
destination.contact = userSFOList[selectedRow].contact.intValue ?? <Your default Int here>
You could also use guard as pointed out by #Kamil.S, like:
guard let nameVar = userSFOList[selectedRow].name,
let imageVar = userSFOList[selectedRow].image,
let contactVar = contact as? Int else {
// Conditions were failed. `return` or `throw`.
}
destination.nameVar = nameVar
destination.imageOneURL = imageVar
destination.contact = contactVar

IBAction sometimes not being called when touching buttons - Swift

I am trying to develop a word game where players click buttons to select letters.
There seems to be problem where my buttons sometimes do not register touches. It only seems to occur if there is a pause for a few seconds with no user interaction before a button touch. If the first touch works, quick follow up touches also work.
#IBAction func tileButton1(_ sender: UIButton) {
print("Tile 1 Selected")
tileSelected(tileSelected: 1)
}
#IBAction func clearButton(_ sender: Any) {
clearSelectedTiles()
}
#IBAction func SubmitButton(_ sender: Any) {
//print("Submit Button Pressed")
checkIfSubmittedWordIsValid()
}
checkIfSubmittedWordIsValid
func checkIfSubmittedWordIsValid() {
var alreadySelectedWords: [String] = []
switch currentPlayer {
case 1:
alreadySelectedWords = player1words
case 2:
alreadySelectedWords = player2words
case 3:
alreadySelectedWords = player3words
case 4:
alreadySelectedWords = player4words
default:
break
}
if currentWord.characters.count < 3 {
print("Too short")
playSound(fileName: "invalidWord", fileExtension: "aiff", volume: 1.0)
} else if alreadySelectedWords.contains(currentWord) {
print("Already picked this word")
playSound(fileName: "invalidWord", fileExtension: "aiff", volume: 1.0)
} else if wordList.contains(currentWord.lowercased()) {
print("Valid Word")
playSound(fileName: "goodWord", fileExtension: "wav", volume: 0.5)
addWordToPlayerList(word: currentWord)
} else {
print("Not in dictionary")
playSound(fileName: "invalidWord", fileExtension: "aiff", volume: 1.0)
}
clearSelectedTiles()
}
clearSelectedTiles
func clearSelectedTiles() {
tile1.alpha = 1
tile2.alpha = 1
tile3.alpha = 1
tile4.alpha = 1
tile5.alpha = 1
tile6.alpha = 1
tile7.alpha = 1
tile8.alpha = 1
tile9.alpha = 1
tile10.alpha = 1
tile11.alpha = 1
tile12.alpha = 1
tile13.alpha = 1
tile14.alpha = 1
tile15.alpha = 1
tile16.alpha = 1
selectedTiles.removeAll()
validTiles = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
selectedWordLabel.text = ""
currentWord = ""
}
Nothing gets printed when the issue occurs. Following up quickly with a second touch will trigger the IBAction and print to log.
It seems to happen also with all my other buttons (another 15 'tile' buttons and a 'Clear' and 'Submit' button)
What am I doing wrong?
Link to video showing issue First few touches work but then weirdness.
tileSelected
func tileSelected(tileSelected: Int) {
if isTileValid(tile: tileSelected) {
selectedTiles.append(tileSelected)
var surroundingTiles: [Int] = []
switch tileSelected {
case 1:
tile1.alpha = 0.5
surroundingTiles = [2,5,6]
case 2:
tile2.alpha = 0.5
surroundingTiles = [1,3,5,6,7]
case 3:
tile3.alpha = 0.5
surroundingTiles = [2,4,6,7,8]
case 4:
tile4.alpha = 0.5
surroundingTiles = [3,7,8]
case 5:
tile5.alpha = 0.5
surroundingTiles = [1,2,6,9,10]
case 6:
tile6.alpha = 0.5
surroundingTiles = [1,2,3,5,7,9,10,11]
case 7:
tile7.alpha = 0.5
surroundingTiles = [2,3,4,6,8,10,11,12]
case 8:
tile8.alpha = 0.5
surroundingTiles = [3,4,7,11,12]
case 9:
tile9.alpha = 0.5
surroundingTiles = [5,6,10,13,14]
case 10:
tile10.alpha = 0.5
surroundingTiles = [5,6,7,9,11,13,14,15]
case 11:
tile11.alpha = 0.5
surroundingTiles = [6,7,8,10,12,14,15,16]
case 12:
tile12.alpha = 0.5
surroundingTiles = [7,8,11,15,16]
case 13:
tile13.alpha = 0.5
surroundingTiles = [9,10,14]
case 14:
tile14.alpha = 0.5
surroundingTiles = [9,10,11,13,15]
case 15:
tile15.alpha = 0.5
surroundingTiles = [10,11,12,14,16]
case 16:
tile16.alpha = 0.5
surroundingTiles = [11,12,15]
default:
// do nothing
break
}
updateValidTiles(surroundingTiles: surroundingTiles)
//print("Updated Valid Tiles")
//print(validTiles)
//print("Selected Tiles")
//print(selectedTiles)
currentWord = currentWord + boardTiles[tileSelected - 1].tileLetter
selectedWordLabel.text = currentWord
}
}
Try changing touch down to touch up inside, and try changing the state of the button each time it is clicked
I had some labels constrained to the Top Layout Guide.bottom even though I was hiding the status bar with override var prefersStatusBarHidden.
Changing the relevant label constraints to topMargin instead of Top Layout Guide.bottom has solved my problem with touches sometimes being missed.

Resources