Function not working in Swift - ios

So I've been trying to learn a bit of Swift and I've been looking at functions with return types. I added this function, and it should work, but I still get the error "Could not find member 'convertFromStringInterpolationSegment.' I've looked at other stack overflow questions and have tried to apply their answers, but to no avail. Some help would be greatly appreciated.
func getGasPrices2(price1: Double, price2:Double, price3:Double)
{
return "The prices are \(String(price1)), \(String(price2)), \(String(price3))."
}
getGasPrices2(3.59, 3.69, 3.79)

You forgot to declare a return type. Since you want to return a String, the function needs to declare that:
func getGasPrices2(price1: Double, price2:Double, price3:Double) -> (String)
I'm sure that Apple will work on these wonderful error messages. :)

As Alvin stated, you were simply missing the return type
-> (String)
...in the function's declaration.
I find myself doing the same thing, forgetting the return type at the end, as I'm still getting used to writing in Swift while having the function-type-declaration-first of Objective-C habit
...
Basically your function in Swift...
func getGasPrices2(price1: Double, price2:Double, price3:Double) -> (String)
...is equivalent* to
-(NSString*)getGasPrices2: (double)price1 price2:(double)price2 price3:(double)price3
...in Objective-C*
*Strings in Swift aren't exactly the same as NSStrings but both functions would be able to accomplish what you are looking to do; one in Objective-C, the other in Swift (as long as you make sure to actually return a String/NSString at the end :-)

Related

Swift ExpressibleByIntegerLiteral - How exactly does it work?

Taken from iOs 10 Programming Fundamentals:
"Because Nest adopts ExpressibleByIntegerLiteral, we can pass an Int where a nest is expected, and our init(integerLiteral:) will be called AUTOMATICALLY....."
struct Nest : ExpressibleByIntegerLiteral {
var eggCount : Int = 0
init() {}
init(integerLiteral val: Int) {
self.eggCount = val
}
}
Okay so my question is this...How does it get called automatically though?? My logic runs into a brick wall when I try to figure out why. From what I see, you can say:
var eggie : Nest = 5
but... okay where is the logic in how the number 5 after the equal sign is actually a shorthand for:
var eggie : Nest = Nest(5)
AKA the 'standard' way of initializing a new instance...
Is that just something hidden deep inside the ExpressibleByIntegerLiteral protocol that is handling that transformation?
Thanks
It's compiler magic, so unfortunately you cannot declare such a protocol yourself. :(
It has nothing to do with the internal workings of the ExpressibleByIntegerLiteral. The compiler only sees a variable of type Nest on the left and an integer literal on the right. It thinks,
Oh! The Nest type conforms to ExpressibleByIntegerLiteral! And I see an integer literal. This means that I can change the integer literal to Nest(integerLiteral: 5)!
It's as simple as that. This is also true for other ExpressibleByXXXLiteral protocols.
You cannot declare your own ExpressibleByMyClass protocol because the compiler doesn't know about it.
The ExpressibleBy*Literal protocols are Swift protocols to "hook" into special compiler behaviour. Without the compiler doing the lifting in the back, they wouldn't be able to do anything.

Xcode 8 :function types cannot have argument label breaking my build

It seems that for some reason Swift have chosen to make coding in it less readable by forcing users to remove completion handler parameter labels. I have read the Swift discussion and still think it's a mistake. At least they could have made it optional.
When building using Xcode 8 - is there a way to force the compiler to use Swift 2.3 so I don't get these errors anymore?
I have updated the option to use legacy Swift (under build settings)
but I still seem to get this error:
Function types cannot have argument label 'isloggedIn'; use '_'
instead
How can I keep my labels in my completion handlers?
The Swift designers decided to prohibit argument labels for function types.
The reasoning is explained here: https://github.com/apple/swift-evolution/blob/master/proposals/0111-remove-arg-label-type-significance.md
This is a frustrating and questionable choice, as prohibiting argument labels makes it much easier to incorrectly invoke closures, which seems more important than simplifying the language's type system.
Usability > ideology.
A workaround to consider. You can't do:
func doStuff(completion: (foo: Int, bar: String) -> Void) {
...
completion(foo: 0, bar: "")
}
... but you can do:
func doStuff(completion: ((foo: Int, bar: String)) -> Void) {
...
completion((foo: 0, bar: ""))
}
i.e. have a single unnamed argument to your closure which is a tuple, in this case (foo: Int, bar: String).
It's ugly in its own way, but at least you retain the argument labels.
Based on the information above - it appears that the only way to really fix this and ensure that its performant is to raise a proposal to
Make argument labels optional with a view to :
improving the speed of development ( without argument labels it requires us to scroll up to the top of the method each time we put in the completion handler.
Reduce Errors : ( I have already had several errors caused due to incorrect completion handler entries especially with those that expect boolean values)
Make code more readable across team members. Not everyone has only one team member and thus being able to easily pick up other peoples code is a must have.
Lastly good programming practice means that the solution should look as much like the actual item being developed. completionhandler: (newvalues, nil) looks less like the item being managed than completionhandler(results: newValue, error:nil)
I would love for people reading this to share their feedback/ comments
on this below before I submit it so I can show there are others that
support this.
Edit:
I have submitted the pitch here :
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20161010/028083.html
which appears to have been agreed. It looks like its going to happen, however the discussion is whether this is submitted as a Swift 4 improvement ( highly probable)
You have to use _ to make your parameters unnamed, and that is unfortunate. Instead of tacking _ on to each parameter and then blindly calling your function I would suggest making a wrapper object.
Since losing named parameters for function types introduces more risk that you will call the function with the wrong values, I would suggest wrapping the parameters in a struct and having that be the one and only parameter to your function.
This way the fields of you struct are named, and there is only one type of value to pass into your function. It is more cumbersome than if we were able to name the parameters of the function, but we can't. At least this way you'll be safer and you'll feel less dirty.
struct LineNoteCellState {
var lineNoteText: String?
var printOnInvoice = false
var printOnLabel = false
}
Here is an example of it being used:
cell.configure(editCallback: { (_ state: LineNoteCellState) in
self.lineNoteText = state.lineNoteText
self.printOnInvoice = state.printOnInvoice
self.printOnLabel = state.printOnLabel
})
Semi-workaround, note the _
completion: (_ success: Bool) -> Void

What is the difference between '(String)' and 'String' in a Swift error message

I wrote a function that takes a non-optional String as a parameter.
I declared a variable property of type String, which is also not an optional.
When I try to call my function with this property as an argument, I get the following error.
Cannot invoke 'localesForCountryCode' with an argument list of type '(String)'
Notice that the error lists the type as '(String)' not 'String'. What do the parens signify? I thought they meant that the type was optional, but nothing is declared as an optional anywhere.
My Function (An extension of NSLocale):
func localesForCountryCode(countryCode: String) -> [NSLocale] {
let localeIdentifiers = localeIdentifiersForCountryCode(countryCode)
var locales = [NSLocale]()
for localeIdentifier in localeIdentifiers {
let localeForIdentifier = NSLocale(localeIdentifier: localeIdentifier)
locales.append(localeForIdentifier)
}
return locales
}
Code That Calls My Function
let currentCountryCode = "US"
var localesForCurrentCountry = [NSLocale]()
func updateWithNewLocation(newLocation: CLLocation) {
geoCoder.reverseGeocodeLocation(newLocation, completionHandler: { (placemarks, error) -> Void in
if placemarks.count > 0 {
let placemark = placemarks.first as! CLPlacemark
self.currentCountry = placemark.country
self.localesForCurrentCountry = NSLocale.localesForCountryCode(self.currentCountryCode)
}
})
}
Update 1
When I move my function code from the NSLocale extension to the view controller from which I am calling the function, the error goes away. Any ideas why this may be the case? Absolutely no changes to the function were made.
Update 2
I continue to run into this problem. The following is another example. Again, it seems to happen only when a function is called as a class method.
I was rereading your question and realized that your question is not really your question. Your problem has nothing to do with parentheses (see below about why). You're just calling the wrong method. NSDateComponentsFormatter is a class. stringFromTimeInterval() is an instance method. You have to crate an actual date formatter to work with. If you want a default one, you can do this:
return NSDateComponentsFormatter().stringFromTimeInterval(unwrappedTimespan)
Note the extra set of parentheses. Your probably don't want the default one, though. You probably want to configure one. See Date Formatters for an introduction to that topic. Note that date formatters can be pretty expensive to create, so you usually want to reuse them.
You're doing the same thing with localesForCountryCode. This is an instance method, not a class method. You have to create an NSLocale first.
This does open up an interesting topic, though. Why does NSDateComponentsFormatter.stringFromTimeInterval() act like a function that you're just passing the wrong arguments to? Why doesn't it say "hey, you're calling a class method?" It's because it is a function that you're just passing the wrong arguments to.
Every method is really just a curried function that takes the target object as the first parameter. See Ole Begemann's quick intro to the topic: Instance Methods are Curried Functions in Swift.
Some more on your explicit question about parentheses:
As others have noted, a (String) is a one-tuple of String. The important point is that in Swift, any type is trivially convertible to a one-tuple of that type, so the extra parentheses here are unimportant. There is no meaningful distinction between String and (String) in Swift.
All Swift functions technically take one value and return one value. So one can correctly think of:
func f(x: Int, y: Int) -> Int
as a function that takes a tuple (Int,y:Int) and returns an Int (or possibly (Int); I believe Swift actually does the former, though). This is subtly connected to how currying works in Swift. In a simpler case:
func f(x: Int)
This is a function that technically takes (Int) and returns (). That's why sometimes you will see (Type) show up in error messages. But it is not a meaningful distinction.
String - it's simple String type.
But (String) - it's a compound type called Tuple.
That means you passing to you function Tuple, not String.
A compound type is a type without a name, defined in the Swift language itself. There are two compound types: function types and tuple types. A compound type may contain named types and other compound types. For instance, the tuple type (Int, (Int, Int)) contains two elements: The first is the named type Int, and the second is another compound type (Int, Int).
In general the error message says (String) because that is the tuple / list of parameters. If you method would expect a String and afterwards an Int an error message might mention (String, paramName: Int)
So basically so far everything looks fine. You need to show us the code for us to be able to fix your exact problem. Because String and (String) normally should match in the given scenario.
Consider the following example:
func k (a:String, b:Int) {}
k(12, b:"123")
which will cause the error
Cannot invoke 'k' with an argument list of type (Int, b:String)
While
k("12", b:123)
does what you would expect.

Swift `in` keyword meaning?

I am trying to implement some code from parse.com and I notice a keyword in after the void.
I am stumped what is this ? The second line you see the Void in
PFUser.logInWithUsernameInBackground("myname", password:"mypass") {
(user: PFUser?, error: NSError?) -> Void in
if user != nil {
// Do stuff after successful login.
} else {
// The login failed. Check error to see why.
}
}
The docs don't document this. I know the in keyword is used in for loops.
Anyone confirm?
In a named function, we declare the parameters and return type in the func declaration line.
func say(s:String)->() {
// body
}
In an anonymous function, there is no func declaration line - it's anonymous! So we do it with an in line at the start of the body instead.
{
(s:String)->() in
// body
}
(That is the full form of an anonymous function. But then Swift has a series of rules allowing the return type, the parameter types, and even the parameter names and the whole in line to be omitted under certain circumstances.)
Closure expression syntax has the following general form:
The question of what purpose in serves has been well-answered by other users here; in summary: in is a keyword defined in the Swift closure syntax as a separator between the function type and the function body in a closure:
{ /parameters and type/ in /function body/ }
But for those who might be wondering "but why specifically the keyword in?", here's a bit of history shared by Joe Groff, Senior Swift Compiler Engineer at Apple, on the Swift forums:
It's my fault, sorry. In the early days of Swift, we had a closure
syntax that was very similar to traditional Javascript:
func (arg: -> Type, arg: Type) -> Return { ... }
While this is nice and regular syntax, it is of course also very bulky
and awkward if you're trying to support expressive functional APIs,
such as map/filter on collections, or if you want libraries to be able
to provide closure-based APIs that feel like extensions of the
language.
Our earliest adopters at Apple complained about this, and mandated
that we support Ruby-style trailing closure syntax. This is tricky to
fit into a C-style syntax like Swift's, and we tried many different
iterations, including literally Ruby's {|args| } syntax, but many of
them suffered from ambiguities or simply distaste and revolt from our
early adopters. We wanted something that still looked like other parts
of the language, but which could be parsed unambiguously and could
span the breadth of use cases from a fully explicit function signature
to extremely compact.
We had already taken in as a keyword, we couldn't use -> like Java
does because it's already used to denote the return type, and we were
concerned that using => like C# would be too visually confusing. in
made xs.map { x in f(x) } look vaguely like for x in xs { f(x) },
and people hated it less than the alternatives.
*Formatting and emphasis mine. And thanks to Nikita Belov's post on the Swift forums for helping my own understanding.

Function with Enumeration Parameter (and Default value)

I wanted to create an extension method function called toCurrencyString that has one parameter that is actually an integer enumeration of type CurrencyFormatType. The enum and code would be:
enum CurrencyFormatType: Int {
/// Formats a standard currency string (localized) such as $45.35 or *45,00
case Standard = 1,
///Rounded currency format (rounds up last decimals and does not return any decimals in string)
Rounded,
///Will not include the thousands separator (, or .) in a string. Retains localized currency symbol.
WithoutThousandsSeparator
}
func toCurrencyString(currencyFormat: CurrencyFormatType = 1) -> String
{
..my switch code w/ default to the first option if nothing passed in
}
I'd like to do this so that I can call .toCurrencyString on NSDecimalNumbers without having to pass in the optional parameter (most of the time I won't need it), but on the few times I do, i'd like to use an enum to select other options.
It complains at me telling me that my enum doesn't conform to IntegerLiteralConvertible. I did a little reading on how this would work but couldn't figure out the code.
Could anyone shed some light on how to get this working?
thanks for your help!
My apologies, no sooner did I ask it than I figured it out. I should have waited a bit longer.
In hopes of helping others out, just a reminder about the 'Raw' aspect of enums:
Adding this to my function signature helped:
CurrencyFormatType.Raw = 1
Thanks!
alternately you could have done:
func toCurrencyString(currencyFormat: CurrencyFormatType = CurrencyFormatType.Standard) -> String
{
...

Resources