Swift 4 function returning 0 for multiple return values - swift

I have been searching around but couldn't find a solution. can someone please let me know what I am doing wrong.
here is my function code: in my database I have hour=5 as Int and Minute=45 as Int
but when I print, the values of the function prints 0,0
var docRefF : DocumentReference!
func getTime()-> (Int, Int){
var FHour = Int()
var FMinute = Int()
docRefF = Firestore.firestore().document("sampleTime/worktime")
dataListener = docRefF.addSnapshotListener { (docSnapshot, error) in
guard let docSnapshot = docSnapshot, docSnapshot.exists else { return }
let data = docSnapshot.data()
let Hour:Int = data["Hour"]! as! Int
let Minute: Int = data["Minute"]! as! Int
FHour = Hour
FMinute = Minute
}
return (FHour, FMinute)
}
let time = getTime()
print("\(time.0),\(time.1)" )
//printed 0,0

Clearly its issue of asynchronous execution. Use * function with Closure* Instead of function with returning value.
Please refer following code
var docRefF : DocumentReference!
func getTime(_ then:(_ first:Int, _ second:Int)->()){
var FHour = Int()
var FMinute = Int()
docRefF = Firestore.firestore().document("sampleTime/worktime")
dataListener = docRefF.addSnapshotListener { (docSnapshot, error) in
guard let docSnapshot = docSnapshot, docSnapshot.exists else { return }
let data = docSnapshot.data()
let Hour:Int = data["Hour"]! as! Int
let Minute: Int = data["Minute"]! as! Int
FHour = Hour
FMinute = Minute
//TODO:- Use other firebase related task same as your code, so that uncomment other lines same as your origional
then(FHour, FMinute) // This is closure call back line
}
}
//Calling your function
getTime { (first, second) in
print(first,second)
}

Related

Can't add items to array

I'm having some trouble with an array. I created an array called 'coins'
var coins = [Coin]()
then appended objects to it within a function
func getCoinData() {
AF.request("https://min-api.cryptocompare.com/data/top/mktcapfull?limit=10&tsym=USD", encoding: JSONEncoding.default).responseJSON { response in
if let json = response.result.value{
let responseDictionary = json as! [String : Any]
let data = responseDictionary["Data"] as! [Any]
for index in data {
let coin = index as! Dictionary<String, Any>
let coinInfo = coin["CoinInfo"] as! Dictionary<String, Any>
let displayInfo = coin["DISPLAY"] as! Dictionary<String, Any>
let usdDisplayInfo = displayInfo["USD"] as! Dictionary<String, Any>
let name = coinInfo["Name"]
let fullName = coinInfo["FullName"]
let imageUrl = coinInfo["ImageUrl"]
let price = usdDisplayInfo["PRICE"]
let marketCap = usdDisplayInfo["MKTCAP"]
let change24Hr = usdDisplayInfo["CHANGE24HOUR"]
let newCoin = Coin()
if let newCoinName = name, let newCoinFullName = fullName, let newCoinImageUrl = imageUrl, let newCoinPrice = price, let newCoinMarketCap = marketCap, let newCoinChange24hr = change24Hr {
let coinName = newCoinName
let coinFullName = newCoinFullName
let coinImageUrl = newCoinImageUrl
let coinPrice = newCoinPrice
let coinMarketCap = newCoinMarketCap
let coinChange24Hr = newCoinChange24hr
newCoin.name = "\(coinName)"
newCoin.fullName = "\(coinFullName)"
newCoin.imageURL = "\(coinImageUrl)"
newCoin.price = "\(coinPrice)"
newCoin.marketCap = "\(coinMarketCap)"
newCoin.change24Hr = "\(coinChange24Hr)"
self.coins.append(newCoin)
}
}
}
}
}
When i print 'self.coins.count' within the scope of the function i can see the count incrementing. Outside the function it's reading 0 items in the array.
Written for Swift 5
The problem is that you have a URL request which is Asynchronous. This means that the task is not waited for to complete.
In your problem, inside the function coins is printed after it has been assigned, after the URL request. However, when coins is printed outside the function, it is printed before it has been changed, as the URL request has not yet completed.
To solve this, you need to create a completion handler. A basic one is shown here:
// Our errors which could occur
enum SomeError: Error { case unknown }
// Function which is ASYNCHRONOUS
func someAsyncFunction(completion: #escaping (Result<Int, SomeError>) -> ()) {
// Temporary for this example
let success = true
let myNum = 3
// Return value if it is a success, otherwise return the error
if success {
completion(.success(myNum))
} else {
completion(.failure(.unknown))
}
}
// Call
someAsyncFunction { (result) in
print("Result: \(result)")
/* PRINT COINS HERE */
}
See a full guide on completion handlers using Result in Swift 5 at hackingwithswift.com.

Label intValue not show for greater than (>) to work

I am new at Swift the code builds just fine but the greater than (>) dose not work. I'm trying to producing at a number in the "totalCoal" label, but never goes over the "coalPileHolding" Second label. I know that this code can be way better But i am trying to get the basic first. I also know that the timeDiffernt ">" dose not work also so somehow I am missing something. Thank you for your help
#IBOutlet weak var coalPileHoldingLabel: UILabel!
func loadBigCoalPile () {
var coalPileHolding = Int ()
if UserDefaults.standard.object(forKey: "coalPileResearch") == nil {
coalPileHolding = 0 } else {
coalPileHolding = UserDefaults.standard.object(forKey: "coalPileResearch") as! Int}
if coalPileHolding == 1 {
let coalPileHolding = 200
coalPileHoldingLabel.text = String(coalPileHolding) }
if coalPileHolding == 2 {
let coalPileHolding = 300
coalPileHoldingLabel.text = String(coalPileHolding) }
if coalPileHolding == 3 {
let coalPileHolding = 400
coalPileHoldingLabel.text = String(coalPileHolding) }
#objc func buttonIsInAction(){
}
#IBOutlet weak var coalRunButton: UIButton!
#IBAction func coalRunButton(_ sender: Any) {
func getMillisecondsNow() -> Int64{
let currentDate = Date()
return getMillisecondsFromDate(date: currentDate)
}
func getMillisecondsFromDate(date: Date) -> Int64{
var d : Int64 = 0
let interval = date.timeIntervalSince1970
d = Int64(interval * 1000)
return d
}
func getTimeDifferenceFromNowInMilliseconds(time: Int64) -> Int64{
let now = getMillisecondsNow()
let diff: Int64 = now - time
return diff
}
var terminationTime = Int64()
if UserDefaults.standard.object(forKey: "latestTerminationDate") == nil {
terminationTime = getMillisecondsNow()
UserDefaults.standard.set(terminationTime, forKey:"latestTerminationDate")
}
else {
terminationTime = UserDefaults.standard.object(forKey: "latestTerminationDate") as! Int64 }
let timeDiff = getTimeDifferenceFromNowInMilliseconds(time: terminationTime)
let timeDiffernt = Int(timeDiff)
let now = getMillisecondsNow()
UserDefaults.standard.set (now, forKey: "latestTerminationDate")
if timeDiffernt > 86400000 { _ = 86400000}
var methodOfCut = Int ()
var machineryButton = Int ()
var qualityOfWorkers = Int ()
if UserDefaults.standard.object(forKey: "methodOfCut") == nil {
methodOfCut = 0 } else {
methodOfCut = UserDefaults.standard.object(forKey: "methodOfCut") as! Int}
if UserDefaults.standard.object(forKey: "machineryButton") == nil {
machineryButton = 0 } else {
machineryButton = UserDefaults.standard.object(forKey: "machineryButton") as! Int}
if UserDefaults.standard.object(forKey: "qualityOfWorkers") == nil {
qualityOfWorkers = 0 } else {
qualityOfWorkers = UserDefaults.standard.object(forKey: "qualityOfWorkers") as! Int}
let coalMayham = (machineryButton) + (qualityOfWorkers) + (methodOfCut)
let (dailyCoalAccumulate) = ((timeDiffernt) * (coalMayham) + 1) / 10000
var coalPileHolding2 = 0
if let coalPile = Int(coalPileLabel.text!) {
let totalCoal = (dailyCoalAccumulate) + coalPile
coalPileHolding2 = Int(coalPileHoldingLabel.text!) ?? 0
if totalCoal > coalPileHolding2 { coalPileHolding2 = totalCoal }
coalPileLabel.text = String(totalCoal)
UserDefaults.standard.set(totalCoal, forKey:"totalCoal")}
callOutLabel.text = String(dailyCoalAccumulate)}}
That mix of numeric types (Int32, Float, Int) is rather confusing. In general you want to use Int or Double. All other variants should only be used when absolutely necessary, for example if an API requires a different type. So lets assume that dailyCoalAccumulate is Int and switch everything else to Int too:
let coalPileHolding = 0
if let coalPile = Int(coalPileLabel.text!) {
let totalCoal = dailyCoalAccumulate + coalPile
let coalPileHolding = Int((coalPileHoldingLabel.text as! NSString).intValue)
if totalCoal > coalPileHolding {
let coalPileHolding = totalCoal
}
coalPileLabel.text = String(totalCoal)
UserDefaults.standard.set(totalCoal, forKey:"totalCoal")
}
callOutLabel.text = String(dailyCoalAccumulate)
Here the intValue API of NSString returns Int32 but I immediately convert it to a regular Int. But of course there is a better way to do this without having to bridge to the Objective-C NSString. If the string doesn't contain a number intValue simply returns zero. We can produce the same behavior when we use the Int initializer to convert the string and then replace the nil value with zero: Int(coalPileHoldingLabel.text!) ?? 0.
Then we have three different variables named coalPileHolding. Since they are defined in different scopes they can share the same name, but are still different variables. My guess is that you want to actually update the coalPileHolding variable. Otherwise the assignment in the inner if makes no sense - the compiler even warns about that.
So lets change coalPileHolding to var and update its value.
var coalPileHolding = 0
if let coalPile = Int(coalPileLabel.text!) {
let totalCoal = dailyCoalAccumulate + coalPile
coalPileHolding = Int(coalPileHoldingLabel.text!) ?? 0
if totalCoal > coalPileHolding {
coalPileHolding = totalCoal
}
coalPileLabel.text = String(totalCoal)
UserDefaults.standard.set(totalCoal, forKey:"totalCoal")
}
callOutLabel.text = String(dailyCoalAccumulate)

Crash due to optional string in swift 3.0

I was converting the timestamp to time but my timeStampToDate is giving this output "Optional(1476775542548)" due to which it crashes.So how i can remove this Optional string.
let timeStampToDate = (String(describing:merchant.post["timestamp"])) as String
let timeSt = Date(jsonDate:"/Date(\(timeStampToDate))/")
merchantOpenLbl.text = Date().onlyTimee(date: timeSt!)
init?(jsonDate: String) {
// "/Date(1487058855745)/"
let prefix = "/Date("
let suffix = ")/"
let scanner = Scanner(string: jsonDate)
// Check prefix:
guard scanner.scanString(prefix, into: nil) else { return nil }
// Read milliseconds part:
var milliseconds : Int64 = 0
guard scanner.scanInt64(&milliseconds) else { return nil }
// Milliseconds to seconds:
var timeStamp = TimeInterval(milliseconds)/1000.0
// Read optional timezone part:
var timeZoneOffset : Int = 0
if scanner.scanInt(&timeZoneOffset) {
let hours = timeZoneOffset / 100
let minutes = timeZoneOffset % 100
// Adjust timestamp according to timezone:
timeStamp += TimeInterval(3600 * hours + 60 * minutes)
}
// Check suffix:
guard scanner.scanString(suffix, into: nil) else { return nil }
// Success! Create NSDate and return.
self.init(timeIntervalSince1970: timeStamp)
}
Wrapped the optional value that you getting from merchant.post["timestamp"].
if let timeStampToDate = merchant.post["timestamp"] as? String {
print(timeStampToDate)
let timeSt = Date(jsonDate:"/Date(\(timeStampToDate)))/")
merchantOpenLbl.text = Date().onlyTimee(date: timeSt!)
}
Note: If it is still not works then you need to show us declaration of Date(jsonDate:)
Edit: If it is not string then try like this way
if let timeStampToDate = merchant.post["timestamp"] {
print(timeStampToDate)
let timeSt = Date(jsonDate:"/Date(\(timeStampToDate)))/")
merchantOpenLbl.text = Date().onlyTimee(date: timeSt!)
}
You can use guard let to wrap the optional value. Replace your code with below code.
guard let timeStampToDate = merchant.post["timestamp"] as? String else {
return
}
let timeSt = Date(jsonDate:"/Date(\(timeStampToDate))/")
merchantOpenLbl.text = Date().onlyTimee(date: timeSt!)
let timeStampToDate = (String(describing:merchant.post["timestamp"])) as String
let timeSt = Date(jsonDate:"/Date(\(timeStampToDate!))/")
merchantOpenLbl.text = Date().onlyTimee(date: timeSt!)
Edit
if let timeStampToDate = (String(describing:merchant.post["timestamp"])) as? String {
let timeSt = Date(jsonDate:"/Date(\(timeStampToDate))/")
merchantOpenLbl.text = Date().onlyTimee(date: timeSt!)
}

Swift 2.0 Guard Statement Fails Struct Initializer

There was a similarly named topic but the example was an error due to user mistake. I believe this example is an actual XCode issue.
I was following a treehouse tutorial and in the spirit of swift 2.0 I used guard statements instead of if lets in the initializer. My code was identical to the instruction except for the use of guard statements. It had one error that said "return from initializer without initializing all stored properties". Once I changed it to if let statements, it worked. Perhaps I made a mistake somewhere but I stared at it for atleast an hour, no properties were left un-initialized.
I made the properties equal to nil in the else clauses just in case but that didnt affect anything.
struct DailyWeather {
let maxTemp: Int?
let minTemp: Int?
let humidity: Int?
let precipChance: Int?
var summary: String?
var icon: UIImage? = UIImage(named: "default.png")
var largeIcon: UIImage? = UIImage(named: "default_large.png")
var sunriseTime: String?
var sunsetTime: String?
var day: String?
let dateFormatter = NSDateFormatter()
init(dailyWeatherDictionary: [String:AnyObject]) {
minTemp = dailyWeatherDictionary["temperatureMin"] as? Int
maxTemp = dailyWeatherDictionary["temperatureMax"] as? Int
guard let humidityFloat = dailyWeatherDictionary["humidity"] as? Double else { humidity = nil ; return }
humidity = Int(humidityFloat * 100)
guard let precipFloat = dailyWeatherDictionary["precipProbability"] as? Double else { precipChance = nil ; return }
precipChance = Int(precipFloat * 100)
summary = dailyWeatherDictionary["summary"] as? String
guard let
iconString = dailyWeatherDictionary["icon"] as? String,
iconEnum = Icon(rawValue: iconString) else { icon = nil ; largeIcon = nil ; return }
(icon, largeIcon) = iconEnum.toImage()
guard let sunriseDate = dailyWeatherDictionary["sunriseTime"] as? Double else { sunriseTime = nil ; return }
sunriseTime = timeStringFromUnixTime(sunriseDate)
guard let sunsetDate = dailyWeatherDictionary["sunsetTime"] as? Double else { sunsetTime = nil ; return }
sunsetTime = timeStringFromUnixTime(sunsetDate)
guard let time = dailyWeatherDictionary["time"] as? Double else { day = nil ; return }
day = dayStringFromUnixTime(time)
}
func timeStringFromUnixTime(unixTime: Double) -> String {
let date = NSDate(timeIntervalSince1970: unixTime)
dateFormatter.dateFormat = "hh:mm a"
return dateFormatter.stringFromDate(date)
}
func dayStringFromUnixTime(unixTime: Double) -> String {
let date = NSDate(timeIntervalSince1970: unixTime)
dateFormatter.locale = NSLocale(localeIdentifier: NSLocale.currentLocale().localeIdentifier)
dateFormatter.dateFormat = "EEEE"
return dateFormatter.stringFromDate(date)
}
}
let's have
struct S {
var i: Int?
init(b: Bool){
guard b == false else { return }
//if b == true { return }
i = 0 // if b == true, this statement doesn't execute
}
}
let s1 = S(b: true)
let s2 = S(b: false)
print(s1, s2) // S(i: nil) S(i: Optional(0))
because var i: Int? has a default value nil, even though i = 0 is not reachable if parameter of init is true, the compiler doesn't complain.
struct S {
let i: Int?
init(b: Bool){
guard b == false else { return }
//if b == true { return }
i = 0 // if b == true, this statement doesn't execute
}
}
will NOT compile, with error: return from initializer without initializing all stored properties and note: 'self.i' not initialized, because constant let i: Int? doesn't have any default value
Your trouble is, that you return from init. Normally, avoid return from an initializer if your initializer is not fail-able / init? /. In case of fail-able init? the only accepted return value is nil.

extension of Int needs an explicit call to init

I am creating an extension of Int with my own init but I cannot use the init implicitly. Can somebody please explain why? I can however call the init explicitly as shown below.
extension Int {
init?(fromHexString: String) {
let HexRadix:Int = 16
let DigitsString = "0123456789abcdefghijklmnopqrstuvwxyz"
let digits = DigitsString
var result = Int(0)
for digit in fromHexString.lowercaseString {
if let range = digits.rangeOfString(String(digit)) {
let val = Int(distance(digits.startIndex, range.startIndex))
if val >= Int(HexRadix) {
return nil
}
result = result * Int(HexRadix) + val
} else {
return nil
}
}
self = result
}
}
let firstString = "ff"
//This works
let parsedInt:Int = Int.init(fromHexString: firstString)!
println("\(parsedInt)")
//But this does not ; Error: Int is not identical to Int? Why??
let parsedInt1:Int = Int(fromHexString: firstString)!
println("\(parsedInt1)")