Вызов быстрого закрытия в закрытом помещении
У меня есть следующий код:
twitterAPI?.verifyCredentialsWithUserSuccessBlock({ (userName, password) -> Void in
twitterAPI?.getUserTimelineWithScreenName(userName, count: 100, successBlock: { ([AnyObject]!) -> Void in
}, errorBlock: { (error :NSError!) -> Void in
})
}, errorBlock: { (error :NSError!) -> Void in
println("error block")
})
Я получаю следующие ошибки:
![enter image description here]()
Я попытался сказать себя внутри внешнего закрытия, но это не сработало. Что мне не хватает?
ОБНОВЛЕНО: по-прежнему возникают ошибки сборки:
![enter image description here]()
UPDATE: если я положу метод getUserTimeline вне закрытия, он будет работать. ЭТО ОДИН РАБОТАЕТ.
// twitterAPI?.getUserTimelineWithScreenName("", successBlock: { (objects :[AnyObject]!) -> Void in
//
// }, errorBlock: { (error: NSError!) -> Void in
//
// })
Но это НЕ:
twitterAPI?.verifyCredentialsWithUserSuccessBlock({ (userName, password) -> Void in
self.twitterAPI?.getUserTimelineWithScreenName("", successBlock: { (objects :[AnyObject]!) -> Void in
}, errorBlock: { (error: NSError!) -> Void in
})
}, errorBlock: { (error :NSError!) -> Void in
})
UPDATE: определение метода getUserTimeLine
self.twitterAPI?.getUserTimelineWithScreenName(<#screenName: String!#>, successBlock: <#(([AnyObject]!) -> Void)!##([AnyObject]!) -> Void#>, errorBlock: <#((NSError!) -> Void)!##(NSError!) -> Void#>)
![enter image description here]()
UPDATE: Теперь у меня возникает ошибка сборки, в которой указывается отсутствующий аргумент fromID. Я даже не использую этот конструктор.
if let twitterAPI = self.twitterAPI {
twitterAPI.verifyCredentialsWithUserSuccessBlock({ (userName, password) -> Void in
twitterAPI.getUserTimelineWithScreenName(userName, successBlock: { (objects :[AnyObject]!) -> Void in
}, errorBlock: { (error :NSError!) -> Void in
})
}, errorBlock: { (error :NSError!) -> Void in
})
}
Ответы
Ответ 1
Try:
twitterAPI?.verifyCredentialsWithUserSuccessBlock({ (userName, password) -> Void in
self.twitterAPI?.getUserTimelineWithScreenName(userName, successBlock: { (objects :[AnyObject]!) -> Void in
}, errorBlock: { (error :NSError!) -> Void in
})
return // <-- ADDED
}, errorBlock: { (error :NSError!) -> Void in
})
В этом случае
{ (userName, password) -> Void in
self.twitterAPI?.getUserTimelineWithScreenName("", successBlock: { (objects :[AnyObject]!) -> Void in
}, errorBlock: { (error: NSError!) -> Void in
})
}
- это "закрытие одного выражения", которое имеет неявный non Void
return.
Как и в Xcode 6.2/Swift 1.1, здесь требуется явно return
.
Или используйте Xcode 6.3/Swift 1.2, который исправил эту проблему.
Смотрите этот вопрос: Однострочное закрытие без возвращаемого типа или Swift - 'Bool' не является подтипом ' Пустота?
Ответ 2
Хорошо, по именам методов, которые вы используете, я предполагаю, что вы используете библиотеку STTwitter. Если это произойдет, вам нужно что-то вроде этого:
if let twitterAPI = self.twitterAPI {
twitterAPI.verifyCredentialsWithSuccessBlock({ (String) -> Void in
twitterAPI.getUserTimelineWithScreenName("test", successBlock: { (objects: [AnyObject]!) -> Void in
println("success")
}, errorBlock: { (error: NSError!) -> Void in
println("failure")
})
}, errorBlock: { (error: NSError!) -> Void in
})
}
Обратите внимание на вызов let перед использованием необязательной переменной self.twitterAPI
.
Ответ 3
Swift 4
Вот простой пример. Но лучше сделать реализацию через монаду.
...
guard let api = twitterAPI else { return }
api.verifyCredentialsWithUserSuccessBlock({ userName, password in
api.getUserTimelineWithScreenName(
userName,
count: 100,
successBlock: { value in
// success
}) { error in
print("get user error: \(error)")
}
}) { error in
print("verify error: \(error)")
}
Ответ 4
Это действительно вводящее в заблуждение сообщение об ошибке. Проблема в том, что внутренняя переменная не может быть необязательного типа, поэтому вам нужно if/let
ее.
Проверьте это на игровой площадке...
class Foo:NSObject {
func doThing(bug:Int,completion:((Void)->(Void))) {
}
}
let woot = Foo()
var bar:Foo? = Foo()
bar?.doThing(7, completion: {});
woot.doThing(3, completion: {
bar?.doThing(4, completion:{});
});
Он не компилируется и сообщение
Невозможно преобразовать тип выражения '(IntegerLiteralConvertible, завершение:() → () - $T3) 'для ввода'() '
Не совсем освещает проблему.
Итак, вы разворачиваете необязательный
woot.doThing(3, completion: {
if let bar = bar {
bar.doThing(4, completion:{});
}
});
И теперь он компилируется.
И к другой проблеме
Если вы проверите заголовок STTwitterAPI.h
- (NSObject<STTwitterRequestProtocol> *)getUserTimelineWithScreenName:(NSString *)screenName
successBlock:(void(^)(NSArray *statuses))successBlock
errorBlock:(void(^)(NSError *error))errorBlock;
является просто удобством для полной сигнатуры этого.
- (NSObject<STTwitterRequestProtocol> *)getUserTimelineWithScreenName:(NSString *)screenName
sinceID:(NSString *)sinceID
maxID:(NSString *)maxID
count:(NSUInteger)count
successBlock:(void(^)(NSArray *statuses))successBlock
errorBlock:(void(^)(NSError *error))errorBlock;
Obj-C to Swift связывает все после первого селектора в скобках, поэтому удобные методы, как правило, путают вещи по завершению кода, но не предоставляют канонический случай.
Итак, в вашем случае (без меня STTwitter
) это то, что вы хотите.
twitterAPI?.verifyCredentialsWithUserSuccessBlock({ (userName, password) -> Void in
if let twitterAPI = self.twitterAPI {
twitterAPI.getUserTimelineWithScreenName("JohnSmith",sinceID:someID,maxID:anotherID,count:1000, successBlock: { (objects)[AnyObject]!) -> Void in
}, errorBlock: { (error: NSError!) -> Void in
})
}
}, errorBlock: { (error :NSError!) -> Void in
})
как вы хотите заполнить sinceID
, maxID
и count
зависит от вас. Я никогда не использовал API, поэтому не догадываюсь. Они могут быть nil'able