【问题标题】:iOS Swift convenience initializer self used before self.init called在调用 self.init 之前使用的 iOS Swift 便利初始化器 self
【发布时间】:2017-09-05 20:13:44
【问题描述】:

所以我一直在尝试创建一个“Period”类,具有以下属性:

class PTPeriod {

    // MARK: Stored Properties

    var start: Date
    var end: Date
    var place: PTPlace?


//MARK: DESIGNATED NITIALIZER
init(start: Date, end: Date, place: PTPlace? = nil) {
    self.start = start
    self.end = end
    self.place = place

}

我想用一个方便的 init 来初始化它,它接受如下字典:

        {
           "close" : {
              "day" : 1,
              "time" : "0000"
           },
           "open" : {
              "day" : 0,
              "time" : "0900"
           }
        }

这是我的初始化程序,最初我把繁重的工作放到了一个辅助方法中。但是,我遇到了与现在相同的错误,因此我删除了辅助方法,但错误仍在发生。不确定它认为我在哪里称呼自己。

更新:将日期格式移动到日期格式器扩展中,但错误仍然存​​在!不确定为什么。显示新的初始化:

我的新便利初始化:

// MARK: Convenience init for initializing periods pulled from Google Place API
convenience init?(placeData: [String:Any], place: PTPlace? = nil) throws {
    var start: Date? = nil
    var end: Date? = nil
    var formatter = DateFormatter()

    do {
        for (key, value) in placeData {
            let period = value as! [String: Any]
            if (key == "open") {
                start = try formatter.upcoming_date(with: period)
            } else if (key == "close") {
                end = try formatter.upcoming_date(with: period)
            } else {
                break
            }
        }
        if (start != nil && end != nil) { self.init(start: start!, end: end!, place: place) }
        else { print("we f'd up") }

    }

    catch { print(error.localizedDescription) }
}

这是我的 DateFormatter.upcoming_date 方法:

   func upcoming_date(with googlePlacePeriod: [String: Any]) throws -> Date? {
    if let day = googlePlacePeriod["day"] as? Int {
        if (day < 0) || (day > 6) { throw SerializationError.invalid("day", day) } // throw an error if day is not between 0-6
        if let time = googlePlacePeriod["time"] as? String {
            if time.characters.count != 4 { throw SerializationError.invalid("time", time) } // throw an error if time is not 4 char long
            var upcoming_date: Date
            let gregorian = Calendar(identifier: .gregorian)

            let current_day_of_week = Date().getDayOfWeekInt()
            let dayOfPeriod = day + 1

            ///TRUST THAT THIS WORKS... NO JODAS
            var distance = dayOfPeriod - current_day_of_week // inverse = false

            if (dayOfPeriod < current_day_of_week) {
                switch distance {
                case -1: distance = 6
                case -2: distance = 5
                case -3: distance = 4
                case -4: distance = 3
                case -5: distance = 2
                case -6: distance = 1
                default: break
                }
            }
            /** time example: "1535" translates into 3:35PM
             first two characters in string are "hour" (15)
             last two characters in string are "minute(35)
             **/

            let hour = Int(time.substring(to: time.index(time.startIndex, offsetBy: 2)))!
            let minute = Int(time.substring(from: time.index(time.endIndex, offsetBy: -2)))


            upcoming_date = Date().fastForward(amount: distance, unit: "days", inverse: false)!
            var components = gregorian.dateComponents([.year, .month, .day, .hour, .minute, .second], from: upcoming_date)
            components.hour = hour
            components.minute = minute
            upcoming_date = gregorian.date(from: components)!
            return upcoming_date
        }
        else { throw SerializationError.missing("time") }
    }
    else { throw SerializationError.missing("day") }
}

【问题讨论】:

  • 我不知道您标题中的错误,但您列出的代码并未在 else 块中调用 self.init。同样,如果抛出错误,您将捕获它(而不是调用self.init),而不是让它冒泡到调用者。
  • @Honey- 我确实有一个指定的初始化程序,但它需要初始化“start”和“end”。为了清楚起见,我会将其添加到问题中
  • @Kevin- 感谢您指出这一点,我不太清楚何时捕获错误以及何时让它们“冒泡”,尽管我已经做了很多阅读它。我在初始化失败时添加了一个“return nil”(作为一个可失败的初始化程序)
  • 方法upcoming_date从何而来?它与标准 DateFormatter 无关(当然不是因为 Swift 方法 从不 使用蛇形变量名称)。我怀疑在调用时使用self 的类中声明了另一个formatter。除非您知道自己在做什么,否则不鼓励使用相同名称命名局部变量和属性。
  • @markocalvocruz 我删除了我的评论,它不是 100% 正确的。你在哪里添加return nil?但基本上你得到这个错误的原因是,你正在访问一些属性,即你正在做self.someProperty之前你要么做self.init(...)要么return nil

标签: ios swift


【解决方案1】:

你有一个失败的初始化器,所以如果它失败了,你必须return nil让它知道它失败了:

if (start != nil && end != nil) { 
    self.init(start: start!, end: end!, place: place) }
} else { 
    print("we f'd up") 
    return nil
}

另外,在您的do-catch 中,您需要

  • re-throwcatch 块中的错误

    catch {
        print(error.localizedDescription)
        throw error
    }
    
  • 完全消除 do-catch 块;或

  • 只需return nil:

    catch {
        print(error.localizedDescription)
        return nil
    }
    

    如果您这样做,您可能不会将这个可失败的初始化程序定义为 throws 的初始化程序,因为您不再抛出。


鉴于您不太可能对抛出的错误做任何有意义的事情,我只会将其设为一个不会抛出的可失败初始化程序:

convenience init?(placeData: [String: Any], place: PTPlace? = nil) {
    var start: Date?
    var end: Date?
    let formatter = DateFormatter()

    for (key, value) in placeData {
        let period = value as! [String: Any]
        if key == "open" {
            start = try? formatter.upcoming_date(with: period)
        } else if key == "close" {
            end = try? formatter.upcoming_date(with: period)
        } else {
            break  // I'm not sure why you're doing this; it seems extremely imprudent (esp since dictionaries are not ordered)
        }
    }

    if let start = start, let end = end {
        self.init(start: start, end: end, place: place)
    } else {
        print("either start or end were not found")
        return nil
    }
}

【讨论】:

  • 成功了,你让问题消失了!!我不太明白(还)为什么这给我带来了问题,但谢谢。我不会怀疑这是问题
  • 诀窍在于,在可失败初始化程序中,每个执行路径都必须调用指定的初始化程序或必须return nil(或者,如果初始化程序throws,则必须throw一个实际错误) .您有两条执行路径(else 子句和 catch 块,未能这样做)。编译器错误消息只是误导。
猜你喜欢
  • 2019-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多