J Norris J Norris - 7 months ago 149
Swift Question

Missing argument for parameter #1 in call // Twitter

I am creating an app that generates a diferent quote everyday. I wanted to give the user the ability to Share with twitter the quote that was given. I was able to get twitter to pop up with the tweet box, but the quote was not showing up. I tried to get that to happen and now, I get a constant error:


Missing argument for parameter for parameter #1 in call


Problem:
I would like to be able to get the quote to fill the tweet box as it pops up after the user taps the twitter button

Here's a screenshot with the errorenter image description here

Here's the code:

@IBAction func shareTweet(sender: AnyObject) {
if SLComposeViewController.isAvailableForServiceType(SLServiceTypeTwitter) {
Share(text:Quote).shareTwitter().characters.count{ sheet in self.presentViewController(sheet, animated: true, completion: nil)};
let tweetShare:SLComposeViewController = SLComposeViewController(forServiceType: SLServiceTypeTwitter)

self.presentViewController(tweetShare, animated: true, completion: nil)

} else {

let alert = UIAlertController(title: "Accounts", message: "Please login to a Twitter account to tweet.", preferredStyle: UIAlertControllerStyle.Alert)

alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))

self.presentViewController(alert, animated: true, completion: nil)
}

}


Here is the share.swift class:

import Social
struct Share {
let text: String

init(text: String) {
self.text = text
}

typealias ShareSheet = SLComposeViewController

func shareTwitter(count: Int, action: (ShareSheet -> ()), error: (UIAlertController -> ())) { // Returns either tweetSheet or alert view
if (count < 140) {
if (SLComposeViewController.isAvailableForServiceType(SLServiceTypeTwitter)) {
// Tweets Quote
let sheet: SLComposeViewController = SLComposeViewController(forServiceType: SLServiceTypeTwitter)
sheet.setInitialText(text)
action(sheet)
} else {
// Not logged into Twitter
let alert = UIAlertController(title: "Accounts", message: "Please login to a Twitter account to share", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
error(alert)
}
} else {
// Character Count is greater then 140
let alert = UIAlertController(title: "Character Count", message: "Sorry this is too long to tweet", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
error(alert)
}
}


Help would be greatly appreciated. Thank you in advance.
If you need any more references to answer, comment what I should add to the question. Thank you.

Answer

Your shareTwitter(count: action:) function takes two parameters. You are calling it with no parameters. You are then trying to call trailing closure parameter on characters.count. I'm assuming that what you mean to do is this:

Share(text:Quote).shareTwitter(Quote.characters.count) { sheet in self.presentViewController(sheet, animated: true, completion: nil)};

I don't think you actually need the count parameter on your shareTwitter() function though. The Share struct already has the text stored in a property. Why not just use that?

func shareTwitter(action: (ShareSheet -> ()), error: (UIAlertController -> ())) { // Returns either tweetSheet or alert view
    if (text.characters.count < 140) {
        // Code removed for brevity 

    } else {
        // Code removed for brevity
    }
}

Then you can make your function call like this:

Share(text:Quote).shareTwitter() { sheet in self.presentViewController(sheet, animated: true, completion: nil)};

Additionally, you don't seem to be returning another closure in your action closure. I think you mean to have your closure parameter returning Void.

On another note, because you are using two closure parameters, one for action and another for error, I don't think your code is going to compile even with that change. You would need to do this:

Share(text:Quote).shareTwitter(action: { sheet in 
    self.presentViewController(sheet, animated: true, completion: nil)

}) { error in 

}

When using a closure that may have an error, the best way to do this is to use a Result monad. It's not hard to implement this for yourself, but you can take a look at antitypical/Result for a library that gives you a Result monad out of the box.

With both of those changes, your shareTwitter() function looks like this:

func shareTwitter(action: (Result<ShareSheet, NSError> -> Void)) { // Returns either tweetSheet or alert view
    if (text.characters.count < 140) {
        // Code removed for brevity 

    } else {
        // Code removed for brevity
    }
}

And it is called like this:

Share(text:Quote).shareTwitter() { result in 
    switch result {
    case .Success(let sheet): 
        self.presentViewController(sheet, animated: true, completion: nil)};

    case .Failure(let error):
        // Do something with your error
    }
}