Trying to do a basic web view app for experimenting, I ran into the loadRequest method. Methods with swift accept the named parameters, however loadRequest does not. Just wondering on the reasoning for this? I found the inconsistency kind of odd.
import UIKit
class ViewController: UIViewController {
#IBOutlet var webView: UIWebView
override func viewDidLoad() {
super.viewDidLoad()
let url = NSURL(string: "http://en.wikipedia.org")
let request = NSURLRequest(URL: url)
self.webView.loadRequest(request)
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
The parameters in standalone functions and instance methods in a class are handled differently. The Swift book has this to say about it:
“Swift gives the first parameter name in a method a local parameter
name by default, and gives the second and subsequent parameter names
both local and external parameter names by default. This convention
matches the typical naming and calling convention you will be familiar
with from writing Objective-C methods, and makes for expressive method
calls without the need to qualify your parameter names.”
An example:
class Counter {
var count: Int = 0
func incrementBy(amount: Int, numberOfTimes: Int) {
count += amount * numberOfTimes
}
}
var myCounter = Counter()
myCounter.incrementBy(3, numberOfTimes: 4)
println(myCounter.count) // 12
There are somewhat complicated rules around what the default behavior is for named parameters. However, they are all centered around the idea of making Swift method calls read the same way that Objective-C method calls are read. There are two types of names for each parameter: external and internal. External names are used when calling the function / method / initializer, and internal names are used only within the implementation of the function / method / initializer.
With initialization methods, the "initWith" is left off but otherwise it is the same. So ---[NSURL initWithString:] becomes NSURL(string:).
initializers do not have an identifying function name before their
parentheses in the way that functions and methods do. Therefore, the
names and types of an initializer’s parameters play a particularly
important role in identifying which initializer should be called.
Because of this, Swift provides an automatic external name for every
parameter in an initializer if you don’t provide an external name
yourself
All other methods are defaulted to not name the first parameter but name all of the following parameters.
Swift gives the first parameter name in a method a local parameter
name by default, and gives the second and subsequent parameter names
both local and external parameter names by default. This convention
matches the typical naming and calling convention you will be familiar
with from writing Objective-C methods, and makes for expressive method
calls
Functional calls have a 3rd rule applied to them. They default to not have any external name.
If you want users of your function to provide parameter names when
they call your function, define an external parameter name for each
parameter, in addition to the local parameter name. You write an
external parameter name before the local parameter name it supports
Related
Apple's book "The Swift Programming Language (Swift 3.1)" states the following:
As with function and method parameters, initialization parameters can have both a parameter name for use within the initializer’s body and an argument label for use when calling the initializer.
However, initializers do not have an identifying function name before their parentheses in the way that functions and methods do. Therefore, the names and types of an initializer’s parameters play a particularly important role in identifying which initializer should be called. Because of this, Swift provides an automatic argument label for every parameter in an initializer if you don’t provide one.
I don't understand the last sentence, as I didn't notice any difference between functions/methods and initializers when it comes to parameters names/labels. How is the argument label automatically provided for an initializer?
The feature being described is this: Given a struct:
struct Point {
let x: Double
let y: Double
}
Swift will automatically generate Point.init(x: Double, y: Double). If you add an init method of your own in the main struct definition, then Swift won't create that automatic init. (If you add an init in an extension, then you will get an automatic init. This is why people often add convenience init in an extension for structs.)
The point the last paragraph is trying to make is that Point(x:y:) is preferable to Point(_:_:). The labels in an initializer are even more valuable than labels in method names, because all initializers have the same "base" name ("init"). They're just explaining why they didn't choose a more implicit default that some people might expect coming from other languages.
In short, sometimes unlabeled parameters make sense in methods depending on what the name of the method is and how unambiguous that makes the first parameter. But in init, unlabeled parameters should be eyed with strong suspicion.
In languages like Java, PHP, Swift, there are keywords like this, $this, and self, respectively, which are reflexive pointers to a particular instance of the containing class. Both Java and Swift allow the programmer to omit this statement entirely if no other local variables share the same identifier. My question is what is the recommended way to write this in production? For example, is it acceptable for a programmer in production to omit self when it is not necessary?
var name: String = ""
init(name: String) {
self.name = name
}
func doSomeMethod() {
print(name)
}
or should a developer in production always use the self clause when accessing instance properties in general like
var name: String = ""
init(name: String) {
self.name = name
}
func doSomeMethod() {
print(self.name)
}
The documentation describes it very well
The self Property
Every instance of a type has an implicit property called self, which
is exactly equivalent to the instance itself. You use the self
property to refer to the current instance within its own instance
methods.
The increment() method in the example above (see the example in the linked guide) could have been written
like this:
func increment() {
self.count += 1
}
In practice, you don’t need to write self in your code very often.
If you don’t explicitly write self, Swift
assumes that you are referring to a property or method of the current
instance whenever you use a known property or method name within a
method. This assumption is demonstrated by the use of count (rather
than self.count) inside the three instance methods for Counter. (Counter is a class mentioned in the section).
The main exception to this rule occurs when a parameter name for an
instance method has the same name as a property of that instance. In
this situation, the parameter name takes precedence, and it becomes
necessary to refer to the property in a more qualified way. You use
the self property to distinguish between the parameter name and the
property name.
Source: The Swift Language Guide: Methods
I am a big fan of always using this in production code.
It has no affect on the emitted machine code, and making things easier for programmers is pointless as opposed to making things easier for the variety
of other tools you might want to use. (i.e. code searching tools, lint-type tools, and etc.)
Also, the time saved in avoiding stupid typo bugs is much greater than the time saved in typing.
There's currently a proposal on the swift-evolution repository to require self when accessing instance properties. It makes a fairly compelling argument for always requiring it.
What does the lone underscore mean in function definitions?
e.g. map(_:)
I understand that when defining functions I can do:
func myFunc(_ string: String) { ... }
Would I then refer to that as myFunc(_:) instead of myFunc(_string:), i.e. purposefully hiding the parameter name?
The _ is used to define that the parameter is not named
If you have multiple _ it states that you do not need to name the parameters in your function call
func myFunc(name:String, _ age:String){
}
myFunc(“Milo", "I'm a really old wizard")
If you do not use the underscore you would use
myFunc(“Milo”, age: "I'm a really old wizard")
The _ is not necessary for function calls. It is just used to indicate that something does not need to have a name.
In regards to how you would refer to your function, You would not have to pass any name for the function call.
But since you also don’t define a parameter type this seems to me like an invalid example (it at least doesn’t work in Xcode 7 with Swift 2.0)
Edit:
Since Swift 3.0
myFunc(name: “Milo”, age: "I'm a really old wizard")
Should be used
Swift needs a convention for saying what the name of a function is, including not only the function name itself (before the parentheses) but also the external names of the parameters. The convention is that the names are followed by colons. So here's a function declaration (in Swift 2.0):
func myFunc(param1 param1:String, param2:String, param3:String) {}
And here is that function's name:
myFunc(param1:param2:param3:)
In real life, however, it is possible (indeed likely) that one or more parameters will not externalize any name. Thus we need a placeholder for that name. The underscore is that placeholder - just as the underscore is the symbol in the declaration suppressing externalization of the name. So, here's another function declaration (in Swift 2.0):
func myFunc2(param1:String, _ param2:String, _ param3:String) {}
And here is that function's name:
myFunc2(_:_:_:)
[The Swift 2.0 spec is important here. In Swift 2.0, the first param name is always not externalized by default, and the other param names are externalized by default. In Swift 1.2 and before, the externalization rules depended on where the declaration appeared, which was unnecessarily inconsistent and confusing.]
When referring to a function, in order to disambiguate it is necessary to provide the function name along with the external names of any parameters that it expects.
For example,
func myFunc(myString string: String) { ... }
and
func myFunc(_ string: String) { ... }
represent two different functions, one where an external label is provided for the first String parameter when the function is called and the other where no label is used, as in:
myFunc(myString: "hi")
and
myFunc("hi")
So, in order to identify a function we include the external label for each parameter where ':' indicates that a parameter is to be provided - e.g. yourFunc(arg1:arg2:) will take 2 arguments.
When no external label is used, we place an underscore ('_').
For the 2 functions given above, we would uniquely identify them using:
myFunc(myString:) and myFunc(_:)
Ok so I have a a bunch of helper functions in my project that I originally had in a class called Animate. I was wonder what are the benefits of declaring func vc class func.
Lets use this as an example class:
class Animate{
func moveView(...){
...
}
}
So I believe if I have a class func I don't have to instantiate the class as so.
Animate.moveView(...)
And if I just declare the function with func it would be:
Animate().moveView(...)
However if I don't declare the file as a class at all as so:
func moveView(...){
...
}
When I call the function it is just:
moveView(...)
With no indication where the code came from and it can be just used like this anywhere in the project.
What are the pros and cons of these three ways? Is not declaring a class bad practice? Or, is there some edge case that this is very useful? For example in my situation I have no need for a class since I am just creating helper functions and not an object.
Thanks in advance for any insight on this!
Ok. Instance methods vs class methods vs global methods.
(The term method and function are interchangeable. Method implies a function implemented by an object, so I tend to prefer the term method to the term function.)
An instance method is a method that is performed by instances of a class. You must have an instance of that class to talk to in order to invoke an instance method.
Instance methods have access to the instance variables of the object they belong to, so the object can save state information between calls. (In a networking class you could create multiple download objects, each of which manages an individual file download of a different file from a different URL, and each might have a different delegate it notifies when it's download is complete)
Class methods are invoked by the class itself, not by an instance. This can make it simple to invoke helper functions without having to manage an object to do that work for you. Since class methods don't talk to an instance of the class, they can't preserve different state information for each object. You might have a utilities class that performs localization functions on strings for example. The localization process is self-contained. You call a class function and pass in a string and the language you want it localized to, and it hands you back a result. No need to keep state between calls. Such a call might look like
let frenchString =
LocalizationUtils.localizeString("English String",
toLanguage: "French")
Global functions do not belong to any particular class. They are global to the entire module in which they are defined. They are similar to class functions, except that they are not specific to a particular class.
I agree with (and upvoted) #Duncan C's answer, but just thought I'd throw in a couple of other pros/cons.
I tend to like global functions over class methods because global functions don't clutter up my classes. I like to keep my classes lean and thin. The global functions can be kept in a separate file that I can copy and paste, or import, into a given project as I need them. So I might have a file in my project called AnimateHelperFunctions that is just global functions related to that class. A given project may only need a couple of them, or most of them, or those plus a couple more that I discover I need. I can delete the ones I don't use in a given project from the file so as to keep that file neat and trim.
I just think that global functions are more modular and encourage me to factor out single tasks for a single function - a good global helper function that does exactly one thing and does it perfectly can also sometimes be abstracted or made generic and used in other contexts as well. You might have a project sometime where you realize you don't need the class - you just need its helper function, and there it is.
I would prefer a hundred simple global functions that I can pick and choose from over a giant bloated class.
You can accomplish much the same thing with extensions, of course, and to some degree it is a matter of taste, as there is very little difference (any?) between class methods and global functions except that to use the class method you have to drag along the entire class.
Unlike global state, there isn't any danger in a global function. Sure, anyone can call it, but the same is true of class methods, and the global function can only operate on the arguments you pass to it.
For me, I use static or class methods to control class level properties or if I have to return customised instances of that particular class or struct. Like for example consider I have below struct.
struct Person {
let firstName: String
let lastName: String
}
Now if I am writing some test cases, where I need Person's instance initialized with a particular name John in many of my test classes, I can create a helper static method.
extension Person {
static func john() -> Person {
return Person(firstName: "John", lastName: "Appleseed")
}
}
let john = Person.john() // I could also create a static property instead, but it's a matter of personal choice and situation.
In above case, I could have made john as global function as well but for me, it will be very vague and not readable.
Another place I can think of where I prefer static method is returning count of cases for an enum.
enum Mood {
case happy
case angry
case lazy
case high
static func count() -> Int {
return 4
}
}
There are places, where I use global functions. I use global functions for logging.
func log(screenEvent name: String) {
let tracker = GAI.sharedInstance().defaultTracker
tracker.set(kGAIScreenName, value: screenName)
let builder = GAIDictionaryBuilder.createScreenView()
tracker.send(builder.build() as [NSObject : AnyObject])
}
Internally, the method is using a sharedInstance, creating a global method makes it easily accessible everywhere in the project just like a print function which logs output in console, but this is logging in some custom service.
Some other global functions which I usually include in my projects are GCD helpers.
func delay(delay:Double, closure: dispatch_block_t) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
func backgroundTask(closure: dispatch_block_t) {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), closure)
}
func mainThreadTask(closure: dispatch_block_t) {
dispatch_async(dispatch_get_main_queue(), closure)
}
These function don't need any information about a class so it makes sense to make them global instead of wrapping them inside a class.
Regarding instance methods, as answered by #Duncan C, they are called on instances, when you want to maintain a state. Below example shows usage of both static and instance methods.
enum TapType {
case water
case beer
}
struct Tap {
let tapType: TapType
//static method
static func unlimitedBeer() -> Tap {
let beer = Tap(tapType: .beer)
beer.turnOn(forDuration: Float.greatestFiniteMagnitude)
return beer
}
//instance method: will do operation on a particular instance of `Tap`.
func turnOn(forDuration duration: Float) {
//implementation
}
}
let unlimitedBeer = Tap.unlimitedBeer()
You can always use convenience initializer to initialize an object with custom behaviour, but again, it's a matter of choice. In above example, I couldn't think of any convenience initializer which would give me unlimited beer.
In Swift you've got many possible ways to declare a method. You can use the # and _ sign to enforce using parameter names and you can also change the external definition of a parameter.
Somehow the compiler creates an error message for the following method:
func createCoffee(withSugar sugar:Bool, andMilk milk:Bool){
}
// Where I want to call it like this:
createCoffee(withSugar:true, andMilk: true)
Enforcing me to declare the method as followed:
func createCoffee(# sugar:Bool, andMilk milk:Bool){
}
// Resulting in the following way to call it
createCoffee(sugar:true, andMilk: true)
A strange thing in this, declaring the method as followed will not result in this enforced com
func createCoffee(firstParam sugar:Bool, andMilk milk:Bool){
}
// Resulting in the following way to call it
createCoffee(firstParam:true, andMilk: true)
In which way does the compiler decide to allow a different external parameter name?
External parameter names are used for greater description. Having the external parameter name as "with_____" makes Swift and XCode see it as redundant. The first parameter technically would always be "with___ interal parameter name ". It is purely for syntactical reading ease.