I've been working on this for a day and can't figure out what is going wrong. I've searched here and the documentation and still can't find the answer.
Here's the code:
`var counter = 60
let timer = scheduledTimer(timeInterval:1.0, target: Any?, #selector(timerAction), userInfo: Any?, repeats: true)
func timerAction() {
for i in timer {
counter -= 1
print(counter)
}
}
timerAction()`
Any help would be greatly appreciated.
Related
I have a very similar question to:
Swift: Store arrays of custom classes in Core Data
The difference is that question was looking to add to a custom class array in Core Data one element at a time. I am looking to add the entire array at once. When I try to, I get the following error:
[CDTester.MassOfSubpart entity]: unrecognized selector sent to instance.
I made a simple app to demonstrate the error and hopefully figure out where I am going wrong. I uploaded it to GitHub here: https://github.com/Yrban/Core-Data-Test-App
The code where it crashes is here:
func saveWidget(){
print("saveWidget() entered")
if self.massOfSubpartMeasurementDict.count > 0,
self.massOfSubpartMeasurementDict.count == self.numberOfSubparts,
self.manufacturer != "",
self.title != "" {
var massPerSubpartMeasurementArray: [MassOfSubpart]
massPerSubpartMeasurementArray = massOfSubpartMeasurementDict.map {
return MassOfSubpart(subpart: $0.key, mass: Measurement(value: Double($0.value)!, unit: self.massUnit))
}
let massOfSubpartSet = Set(massPerSubpartMeasurementArray)
let widget = Widget(context: self.managedObjectContext)
widget.id = UUID()
widget.madeBy?.name = self.manufacturer
widget.hasMassOfPart = massOfSubpartSet // FIXME: The crash is here
widget.title = self.title
do {
print("SaveWidget() attempted/n")
try self.managedObjectContext.save()
} catch {
print("SaveWidget() failed/n")
// handle the Core Data error
// Show alert as to status
}
}
}
My Core Data model is:
MassOfSubpart is a custom object:
import SwiftUI
public class MassOfSubpart: NSObject, Codable {
var subPart: Int
var mass: Measurement<UnitMass>
override init() {
self.subPart = 1
self.mass = Measurement(value: 0.0, unit: UnitMass.grams)
}
init(subpart: Int, mass: Measurement<UnitMass>){
self.subPart = subpart
self.mass = mass
}
}
I have read everything I could find, including Apple's documentation. I feel I am close, but I am obviously missing something important. Any help would be appreciated.
I finally figured out my error. I have not used relationships before, so it didn't dawn on me what I was doing. When I was accessing MassOfPartEntity through its relationship with Widget, I was sending a Set, my custom object through. However, I had to send a Set, the actual entity through. Therefore, I changed saveWidget to this:
func saveWidget(){
print("saveWidget() entered")
if self.massOfSubpartMeasurementDict.count > 0,
self.massOfSubpartMeasurementDict.count == self.numberOfSubparts,
self.manufacturer != "",
self.title != "" {
let massOfPartEntity = MassOfPartEntity(context: self.managedObjectContext)
var massPerSubpartEntityArray: [MassOfPartEntity]
massPerSubpartEntityArray = massOfSubpartMeasurementDict.map {
massOfPartEntity.subPart = Int16($0.key)
if let massDouble = Double($0.value) {
massOfPartEntity.mass = Measurement(value: massDouble, unit: massUnit)
} else {
massOfPartEntity.mass = Measurement(value: 0.0, unit: massUnit)
}
return massOfPartEntity
}
let massOfSubpartSet = Set(massPerSubpartEntityArray) as NSSet
let widget = Widget(context: self.managedObjectContext)
widget.id = UUID()
widget.madeBy?.name = self.manufacturer
widget.addToHasMassOfPart(massOfSubpartSet) // FIXME: The crash is here
widget.title = self.title
do {
print("SaveWidget() attempted/n")
try self.managedObjectContext.save()
} catch {
print("SaveWidget() failed/n")
// handle the Core Data error
// Show alert as to status
}
}
}
changing the Map function return so that it returned MassOfPartEntity's that eventually became a Set. Essentially, it was a type mismatch.
Thanks to those who responded as talking it out definitely helped resolve this.
My code is alright but keeping getting time out on some test cases, any tips to improve this? My guess is the indexOf function taking too long.
func checkMagazine(magazine: [String], note: [String]) -> Void {
var mutableMag = magazine
if note.count > mutableMag.count {
print("No")
return
}
for word in note {
if let index = mutableMag.index(of: word) {
mutableMag.remove(at: index)
} else {
print("No")
return
}
}
print("Yes") }
Please find the challenge in this link: https://www.hackerrank.com/challenges/ctci-ransom-note/problem
One possible solution that passes all tests is using NSCountedSet for storing the words in the note and magazine and comparing the count of each word in note to the count of that word in magazine and if any of them is lower in magazine, making an early return and printing No.
I'd also suggest changing the function signature to return a Bool value even though the function prototype generated by hacker rank returns Void. It's better to make checkMagazine a pure function and not doing any I/O operations in it.
func checkMagazine(magazine: [String], note: [String]) -> Bool {
let magazineWords = NSCountedSet(array: magazine)
let noteWords = NSCountedSet(array: note)
for noteWord in noteWords {
if magazineWords.count(for: noteWord) < noteWords.count(for: noteWord) {
return false
}
}
return true
}
Then you just need to change the end of the generated code to the following:
let magazineWorks = checkMagazine(magazine: magazine, note: note)
if magazineWorks {
print("Yes")
} else {
print("No")
}
func checkMagazine(magazine: [String], note: [String]) -> Void {
var notesDictionary : [String : Int] = [:]
var magazineDictionary : [String : Int] = [:]
var canMakeRansom = true
for n in note {
var count = notesDictionary[n] ?? 0
count += 1
notesDictionary[n] = count
}
for n in magazine {
var count = magazineDictionary[n] ?? 0
count += 1
magazineDictionary[n] = count
}
for note in notesDictionary {
if note.value > magazineDictionary[note.key] ?? 0 {
canMakeRansom = false
}
}
print(canMakeRansom ? "Yes" : "No")
}
This is another way to solve this.
I think this does what NSCountedSet does by itself somehow.
I am new to Swift and i'm trying to mess around with some UITableViews and Arrays.
I have an array of type [Day], named daysArray.
I'm initiating the array in ViewDidLoad(), daysArray has 7 "days" in it.
Also, I have UITableView, which is being populated with the daysArray.
When I'm trying to change one day (one element in the array), the whole daysArray days are changed and consequently, all cells in the UITableView are the same.
This is so peculiar, I really don't know what is wrong (:
The Day class:
import Foundation
class Day {
private var _name: String!
private var _starts: Double!
private var _ends: Double!
var name: String! {
get {
if _name == nil {
_name = "Sunday"
}
return _name
}
set {
_name = newValue
}
}
var starts: Double! {
get {
if _starts == nil {
_starts = 8.00
}
return _starts
}
set {
_starts = newValue
}
}
var ends: Double! {
get {
if _ends == nil {
_ends = 20.00
}
return _ends
}
set {
_ends = newValue
}
}
init(dayDict: Dictionary<String, AnyObject>) {
if let dictName = dayDict["name"] as! String! {
self._name = dictName
}
if let dictIsWorking = dayDict["isWorking"] as! Bool! {
self._isWorking = dictIsWorking
}
if let dictStarts = dayDict["starts"] as! Double! {
self._starts = dictStarts
}
if let dictEnds = dayDict["ends"] as! Double! {
self._ends = dictEnds
}
}
}
The code that seems to be problematic is:
import UIKit
let GeneralDayDict: [String : AnyObject] = ["name" : "Sunday" as AnyObject, "starts": 8.00 as AnyObject, "ends" : 20.00 as AnyObject]
let someDay: Day = Day(dayDict: GeneralDayDict)
class ViewController: UIViewController {
var daysArray: [Day]! = []
override func viewDidLoad() {
super.viewDidLoad()
for i in 0...6 {
let generalDay: Day = someDay
daysArray.append(generalDay)
}
changeArray()
// Do any additional setup after loading the view, typically from a nib.
}
func changeArray() {
daysArray[5].starts = 6.00
for day in daysArray {
print("Each day in the array starts at: ", day.starts)
}
}
}
The print command in changeArray prints this:
Each day in the array starts at: 6.0
Each day in the array starts at: 6.0
Each day in the array starts at: 6.0
Each day in the array starts at: 6.0
Each day in the array starts at: 6.0
Each day in the array starts at: 6.0
Each day in the array starts at: 6.0
As I said, very very peculiar...
Thank you for just reading my question, and also for answering of course (:
In your loop you instantiate objects with the same reference.
You have to replace :
let generalDay: Day = someDay
by this :
let generalDay = Day(dayDict: GeneralDayDict)
Then you will be able to change attributes of generalDay individually
Classes in Swift are passed by reference. Meaning each item in your array points to the same thing. So when you update one, you update them all.
Try doing this with a struct instead of using a class and you will see the difference.
See this Documentation for a better explanation and the reasoning behind this.
Set the class of Day to be NSObject
class Day : NSObject {
}
for i in 0...6 {
let generalDay: Day = someDay
daysArray.append(generalDay.copy())
}
then just append the copy of the generalDay Object
Hope it helps!!
Hello I am trying to take an array I have and update a label to display each element in the array one second apart. An example would be me having the array [3,6,2] and my label would show 3 then wait a second and show 6 then wait a second and show 2. I've seen many NSTimer examples with update functions doing things like this but only with an incrementation on a number, never trying to parse an array. Can anyone help?
Update
I am calling my timer in a UIButton and am running into a problem. The timer works fine but my code in the button function under my timer runs before the timer and update function. My code below generates a random array of numbers then should display them one second apart. It is doing this correct but my print statement under my timer is running before it updates and displays the numbers in the textbook. I do not know why? Is the timer running on a different thread?
func updateCountdown() {
if(numbersIndex <= numberLimit){
self.counter.text = String(numbers[numbersIndex])
}else if(numbersIndex == numberLimit+1){
self.counter.text = ""
}else{
timer!.invalidate()
timer=nil
}
numbersIndex+=1
}
#IBAction func startButton(_ sender: AnyObject){
startB.setTitle("", for: .normal)
var highestLength = 3
//for trialNumber in 0...11{
var numberSequence = Array(repeating:11, count: highestLength)
for count in 0...highestLength-1{
var randomNumber = Int(arc4random_uniform(10))
if(count>0){
while(numberSequence.contains(randomNumber) || randomNumber-1 == numberSequence[count-1]){
randomNumber = Int(arc4random_uniform(10))
}
}
numberSequence[count] = randomNumber
}
print(numberSequence)
self.numbers = numberSequence
self.numbersIndex = 0
self.numberLimit = numberSequence.count-1
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateCountdown), userInfo: nil, repeats: true)
print("this should be last")
//do other stuff too
//}
}
you can do something like this.
var counter = 0
var list: [String] = ["Eggs", "Milk"]
override func viewDidLoad() {
super.viewDidLoad()
var timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.update), userInfo: nil, repeats: true)
}
func update() {
label.text = "\(list[counter])"
counter += 1
if (counter >= list.count) {
counter = 0
}
}
this is assumming the name of you Label is label
I have run in to a slight problem when trying to manage multiple NSTimers in SWIFT. No matter what I Try it will only ever invalidate the last timer I create. But I need to be able to invalidate any of the timers by choice.
Is there some way to create a reference ID that I could then use to select the specific NSTimer I want to invalidate? Any help would be great.
here is a snippet of my code.
import UIKit
var myTimer:NSTimer!
class TimerManager: NSObject {
}
public class Timer {
// each instance has it's own handler
private var handler: (timer: NSTimer) -> () = { (timer: NSTimer) in }
public class func start(duration: NSTimeInterval, repeats: Bool, handler:(timer: NSTimer)->()) {
var t = Timer()
t.handler = handler
myTimer = NSTimer.scheduledTimerWithTimeInterval(duration, target: t, selector: "processHandler:", userInfo: nil, repeats: repeats)
}
#objc private func processHandler(timer: NSTimer) {
self.handler(timer: timer)
}
}
class countdown{
//handles the countdown for the timer and invalidates when it reaches 0
var y = 0
func begin(length:Int) {
y = length
let delta = 1
let delay = 1.0
Timer.start(delay, repeats: true) {
(t: NSTimer) in
self.y -= delta
println(self.y)
if (self.y <= 0) {
t.invalidate()
}
}
}
func end () {
println("timer stopped")
myTimer.invalidate()
}
}
And I create the timer like so:
countdownTimer.begin(120) //time length in seconds ... 120 = 2 mins
To stop timer:
countdownTimer.end()
You may create a dictionary retaining NSTimer objects. Note that timerManager needs to be defined at global scope. Hope it shed light.
class TimerManager {
var _timerTable = [Int: NSTimer]()
var _id: Int = 0
/*! Schedule a timer and return an integer that represents id of the timer
*/
func startTimer(target: AnyObject, selector: Selector, interval: NSTimeInterval) -> Int {
var timer = NSTimer.scheduledTimerWithTimeInterval(interval, target: target, selector: selector, userInfo: nil, repeats: true)
_id += 1
_timerTable[_id] = timer
return _id
}
/*! Stop a timer of an id
*/
func stopTimer(id: Int) {
if let timer = _timerTable[id] {
if timer.valid {
timer.invalidate()
}
}
}
/*! Returns timer instance of an id
*/
func getTimer(id: Int) -> NSTimer? {
return _timerTable[id]
}
}
// This needs to be delcared at global scope, serving as "singleton" instance of TimerManager
let timerManager = TimerManager()
Following code creates a new timer.
var aTimer = timerManager.startTimer(self, selector: Selector("timerFunction"), interval: 1)
To stop the timer, simply pass id to stopTimer(id: Int).
/* Code ... */
timerManager.stopTimer(aTimer)
Also note getTimer method returns the actual instance with an id.
Regards