2015-07-12 1 views
1
typealias CBType =() -> Void 

class A { 

    let b = B() 

    func test() { 
     let token = b.register { CBType in 
      self.b.waitFor([token]) // ERROR: Variable used within its own initial value 
     } 

     b.dispatch() 
    } 
} 

class B { 
    private var _callbacks = [String:CBType]() 

    func register(callback: CBType) -> String { 
     let id = "1234" 
     _callbacks[id] = callback 
     return id 
    } 

    func dispatch() { 
     for (_, cb) in self._callbacks { 
      cb() 
     } 
    } 

    func waitFor(tokens: [String]) { 
    } 
} 

A().test() 

Когда я изменяю тестовую функцию для использования переменной экземпляра, все работает снова, но этот синтаксис немного тяжелее.Переменная, используемая в пределах ее собственного начального значения, в то время как переменная используется в закрытии после инициализации

class A { 

    let b = B() 
    var token: String? 

    func test() { 
     token = b.register { CBType in 
      self.b.waitFor([self.token!]) 
     } 

     b.dispatch() 
    } 
} 

Почему я не могу использовать локальную переменную в закрытии, так как она будет проходить мимо инициализации, когда окончательно вызывается замыкание?

ответ

9

Константа token не имеет значения во время захвата крышкой.

Вместо этого вы можете использовать изменяемую переменную, а замыкание будет фиксировать переменную, а не ее значение.

func test() { 
    var token = "" 
    token = b.register { 
     self.b.waitFor([token]) 
    } 

    b.dispatch() 
} 

В качестве альтернативы, вы можете передать маркер в качестве параметра в замыкании:

typealias CBType = (String) -> Void 

class A { 
    let b = B() 

    func test() { 
     let token = b.register { theToken in 
      self.b.waitFor([theToken]) 
     } 

     b.dispatch() 
    } 
} 

class B { 
    private var _callbacks = [String:CBType]() 

    func register(callback: CBType) -> String { 
     let id = "1234" 
     _callbacks[id] = callback 
     return id 
    } 

    func dispatch() { 
     for (id, cb) in self._callbacks { 
      cb(id) 
     } 
    } 

    func waitFor(tokens: [String]) { 
     println("Wait for \(tokens)") 
    } 
} 

A().test() 
0

В вашем первом примере token не имеет значения при совершении вызова self.b.waitFor([token]).

В вашем втором примере все работает, потому что объявив token следующим образом: var token: String? задано начальное значение (nil).

Проблема заключается не в том, используете ли вы переменную экземпляра -vs- локальную переменную (или что она используется в закрытии), проблема в том, что (в первом примере) вы пытаетесь использовать token в пределах выражения, которое дает свое начальное значение.

Эквивалентно этому было бы объявлено Int так: let myValue: Int = myValue + 1 - его начальное значение должно быть «что» + 1?

+0

Я понимаю это, но я до сих пор смущает тот факт, что закрытие только указатель функции: код функции не запускается до тех пор, пока не будет вызвано замыкание. Итак, почему компилятор настаивает на инициализации переменной, если одна и та же переменная не ссылается до тех пор, пока не будет выполнен код закрытия? – Laurent

+1

компилятор выполняет свою работу :) нет возможного условия, при котором «токен» может быть успешно инициализирован, следовательно, ошибка re: ссылается на себя при установке его начального значения - я благодарен, что он достаточно умен, чтобы дать мне эти виды ошибок! – fqdn

+2

@JohnDifool ваша догадка правильная. Здесь нет проблем, и это работает на других языках, таких как Haskell, и называется «связывание узла». Это быстрый дефицит. – user239558