Вызов быстрого закрытия в закрытом помещении

У меня есть следующий код:

  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