How to receive an output of an array of [TweetSentimentClassifierInput] objects to send it further to my prediction model?
I have the array but inside a closure which turns it unavailable to return as a method output. If I initialize an empty array outside the closure then the output is always an empty array since fetch closure takes time to be completed.
Code
struct TweetFetcher {
let tweetCount = 100
let swifter = Swifter(consumerKey: key, consumerSecret: secret)
func fetchTweets(with searchText: String) -> [TweetSentimentClassifierInput] {
swifter.searchTweet(using: searchText, lang: "en", count: tweetCount, tweetMode: .extended) {(results, searchMetadata) in
var tweets = [TweetSentimentClassifierInput]()
let data = results.description.data(using: .utf8)
do {
let decodedData = try JSONDecoder().decode([TweetData].self, from: data!)
} catch {
print("Error with decoding, \(error)")
}
for tweet in decodedData {
let tweetForClassification = TweetSentimentClassifierInput(text: tweet.full_text)
tweets.append(tweetForClassification)
}
} failure: { (error) in
print("Error with the Twitter API request, \(error)")
}
}
}
How can I return a non-empty array from a closure as a method output?
CodePudding user response:
You should use a completionHandler
concept to achieve async operations like this:
struct TweetFetcher {
let tweetCount = 100
let swifter = Swifter(consumerKey: key, consumerSecret: secret)
func fetchTweets(with searchText: String, completion: @escaping ([TweetSentimentClassifierInput]?, Error?) -> Void) {
swifter.searchTweet(using: searchText, lang: "en", count: tweetCount, tweetMode: .extended) {(results, searchMetadata) in
var tweets = [TweetSentimentClassifierInput]()
let data = results.description.data(using: .utf8)
do {
let decodedData = try JSONDecoder().decode([TweetData].self, from: data!)
} catch {
print("Error with decoding, \(error)")
completion(nil, error)
}
for tweet in decodedData {
let tweetForClassification = TweetSentimentClassifierInput(text: tweet.full_text)
tweets.append(tweetForClassification)
}
completion(tweets, nil)
} failure: { (error) in
print("Error with the Twitter API request, \(error)")
completion(nil, error)
}
}
}
Usage
let fetcher = TweetFetcher()
fetcher.fetchTweets(with: "Keyword...") { tweets, error in
if let error = error {
print(error.localizedDescription)
} else {
// Use tweets array content here ...
}
}
CodePudding user response:
Convert this method in async, passing closure with [TweetSentimentClassifierInput]
as closure argument, and an error as secondary closure argument,
func fetchTweets(with searchText: String, finished: ((_ sentiments: [TweetSentimentClassifierInput]?,_ error: Error?) -> Void)) {
swifter.searchTweet(using: searchText, lang: "en", count: tweetCount, tweetMode: .extended) {(results, searchMetadata) in
var tweets = [TweetSentimentClassifierInput]()
let data = results.description.data(using: .utf8)
do {
let decodedData = try JSONDecoder().decode([TweetData].self, from: data!)
} catch {
print("Error with decoding, \(error)")
}
for tweet in decodedData {
let tweetForClassification = TweetSentimentClassifierInput(text: tweet.full_text)
tweets.append(tweetForClassification)
}
finished(tweets, nil)
} failure: { (error) in
print("Error with the Twitter API request, \(error)")
finished(nil, error)
}
}
CodePudding user response:
You need a completion handler.
The modern Result
type which can contain both the good data and an error provides a convenience initializer to catch the DecodingError
implicitly
struct TweetFetcher {
let tweetCount = 100
let swifter = Swifter(consumerKey: key, consumerSecret: secret)
func fetchTweets(with searchText: String, completion: @escaping (Result<[TweetSentimentClassifierInput], Error>) -> Void) {
swifter.searchTweet(using: searchText, lang: "en", count: tweetCount, tweetMode: .extended) {(results, searchMetadata) in
completion( Result {
try JSONDecoder().decode([TweetData].self, from: Data(results.description.utf8))
.map{TweetSentimentClassifierInput(text: $0.full_text)}
})
} failure: { completion(.failure($0)) }
}
}
And call it
fetchTweets(with: "Foo") { result in
switch result {
case .success(let input): print(input)
case .failure(let error): print(error)
}
}