I am trying to get my greet() method in my Dog class to initialize during the creation of a dog object in testing. I keep getting the message "Result of call to 'greet()' is unused". Can anyone help me, please?
class Dog {
private var name: String
init(name:String) {
self.name = name
self.greet()
}
func greet() -> String{
let greeeting = "the user's name is \(name)."
print(greeeting)
return greeting
}
}
The function greet() is defined with a String return type. But since you don't use the returned value in any way, the compiler tries to warn you that you might have forgotten something.
Try adding #discardableResult :
#discardableResult func greet() -> String{
let greeeting = "the user's name is \(name)."
print(greeeting)
return greeting
}
}
Related
I’m using the following to log some function calls.
func functionWasCalled(file: String = #file, function: String = #function) {
print("Function \(function) of file \(file) was called.")
}
When its caller is a method, I’d like functionWasCalled to also print the name of the class to which the caller belongs. Even when that method is static. And I don’t want to pass any explicit argument to functionWasCalled. What can I do?
I don't believe what you're specifically asking for is possible. There's no way I know of to evaluate something in your caller's context implicitly, except the provided #-literals.
That said, if you will change your syntax slightly, you can get the effect you want.
public class Logger {
public let caller: String
public init(for caller: Any) {
self.caller = "\(type(of: caller))"
}
public func info(_ message: String, file: String = #file, line: Int = #line, function: String = #function) {
print("Function \(function) of \(caller) in file \(file) was called.")
}
}
Now, in objects that use the logger, they just need to create their own with a consistent name like log. Make sure your Logger is stateless, so it's ok that they get created on demand.
class MyLoggingThing {
var log: Logger { Logger(for: self) }
func doSomething() {
log.info("Let's do this")
}
}
// Function doSomething() of MyLoggingThing in file MyPlayground.playground was called.
You can make this a little nicer with an extension, and handle static methods:
protocol Logging {}
extension Logging {
static var log: Logger { Logger(for: self) }
var log: Logger { Logger(for: self) }
}
class MyLoggingThing: Logging {
static func doSomethingStatic() {
log.info("Even static")
}
func doSomething() {
log.info("Let's do this")
}
}
Note that static methods will show the type as MyLoggingThing.Type. That's good or bad, depending on what you want. If you don't like the extra .Type, you can add an extra Logger.init like this:
public init(for staticCaller: Any.Type) {
self.caller = "\(staticCaller)"
}
That will cause types to be evaluated as themselves rather than as their metatypes.
If your logger is stateful or has a central configuration, or other situation where lots of loggers might be a problem, you should split apart the stateful "engine" part from this front-end. You can also make log a lazy var or otherwise initialize it in init when self is available.
In my personal Logging module, I also have a global "root" Logger called Log (with a leading capital). That makes it easier for functions that might not want to name themselves (such as top level functions or closures).
Try the following:
String(describing: self)
Like here:
class Foo {
func test () {
print(String(describing: self))
}
}
let f = Foo()
f.test()
Output:
Foo
For a class name, you can use self.classForCoder and for the filename, you can also use #fileID
func functionWasCalled(file: String = #file, function: String = #function, fileID: String = #fileID, callClass: AnyObject?) {
print("Function \(function) of file \(file) was called.")
print("File id", fileID)
print("Class is - ", callClass?.classForCoder ?? self.classForCoder)
}
In order to reduce cut-and-paste code in this app, I'm trying to pass class names around in order to tell a method which way it should process some data. I have something like the following:
class MyClass : NSObject {
var name : String = ""
}
class OneClass : MyClass {
override init() {
super.init()
self.name = "One"
}
}
class TwoClass : MyClass {
override init() {
super.init()
self.name = "Two"
}
}
class Thing : NSObject {
func doStuff(withClass cls: AnyClass) -> String {
let x = cls.init()
return x.name
}
}
let z = Thing()
print(z.doStuff(withClass: OneClass))
print(z.doStuff(withClass: TwoClass))
Passing withClass cls: AnyClass the parser pushed me to change let x = cls() to let x = cls.init(). But I've got an Expected member name or constructor call after type name error for the last two lines. The recommended fixes both cause other problems.
The first suggestion, adding the () constructor after the class name, causes new errors on those lines: Cannot convert value of type 'OneClass' to expected argument type 'AnyClass' (aka 'AnyObject.Type')
Taking the second suggestion and changing them to OneClass.self and TwoClass.self gets rid of the parser errors, but when I execute the code it just runs forever.. never erroring out, and never completing.
I found a recommendation elsewhere that suggests I should change the Thing.doStuff() parameters to expect MyClass instead of AnyClass, but that causes another set of new problems.
First, the parser starts complaining about the cls.init() call, and the series of fixes it suggests eventually lead to something that makes no sense: let x = cls.type(of:;; init)(). The parser ends up in a suggestion loop where it keeps adding more semi-colons in the middle of the statement.
Second, I'm back to type mismatch errors on the calls to doStuff() in the last two lines: Cannot convert value of type 'OneClass.Type' to expected argument type 'MyClass'.
There's obviously something I'm not getting here about passing types as arguments, but none of the googling I've done has landed me on something that explains the problems I'm seeing.
How about the generic Swift way.
The code constrains the generic type T to MyClass since it must have a name property.
class MyClass : NSObject {
var name : String
override required init() {
self.name = ""
super.init()
}
}
class OneClass : MyClass {
required init() {
super.init()
self.name = "One"
}
}
class TwoClass : MyClass {
required init() {
super.init()
self.name = "Two"
}
}
class Thing : NSObject {
func doStuff<T : MyClass>(withClass cls: T.Type) -> String {
let x = cls.init()
return x.name
}
}
let z = Thing()
print(z.doStuff(withClass: OneClass.self))
print(z.doStuff(withClass: TwoClass.self))
Or use a protocol.
protocol Nameable {
var name : String { get }
init()
}
class MyClass : NSObject, Nameable { ...
...
class Thing : NSObject {
func doStuff<T : Nameable>(withClass cls: T.Type) -> String {
let x = cls.init()
return x.name
}
}
To get this working, you must call init on cls after typecasting it to NSObject.Type. Also, x.name only works if cls Class type contains that particular property. This is the reason x is then typecasted to MyClass.
class Thing : NSObject
{
func doStuff(withClass cls: AnyClass) -> String?
{
let x = (cls as? NSObject.Type)?.init()
if let x = x as? MyClass
{
return x.name
}
return nil
}
}
Call doStuff with ClassType.self
print(z.doStuff(withClass: OneClass.self))
print(z.doStuff(withClass: TwoClass.self))
Let me know if you still face any issues.
I need a single function to resolve different dependencies in a class.
But there is a compilation error appears.
Is it possible to create that generic function or there are some compiler constraints in Swift?
import Foundation
protocol Client: class {
var description: String { get }
}
final class ImportantPerson : Client {
var description: String {
return "Important person"
}
}
protocol Order: class {
var description: String { get }
}
final class LastOrder : Order {
var description: String {
return "Last order"
}
}
final class A {
fileprivate func resolveDependency<T>() -> T {
return resolve() as T
}
private func resolve() -> Client {
return ImportantPerson()
}
private func resolve() -> Order {
return LastOrder()
}
}
let a = A()
let client: Client = a.resolveDependency()
let order: Order = a.resolveDependency()
print("Client: \(client.description)")
print("Order: \(order.description)")
EDIT: This question is not about if Swift allows to create two functions that differs only by return type. I know it's possible. I think there are some artificial constraints in the compiler but not in the fundamental logic that should allow to infer needed type from a context.
Let's put yourself into the compiler's shoes. Imagine that this was not causing an error and you had one signature with different outputs.
Whenever you call resolveDependency<T>() -> T, the compiler will return you a type T which is an instance conforming to a protocol in your case.
In your code you call this method with different instances conforming to the same protocol. At that stage the compiler has no idea about this. All it knows is that you have passed an instance of T and it needs to give you a result in shape of T
There is no problem until this point. As soon as you execute
return resolve() as! T
The compiler will be confused. I have a T but I don't know which resolve() I will call... All I know is that I have a T. How would I know if this is an Order or a Client ?
In order to prevent such confusions we have compiler-time errors. At least this is the case for Swift. (I don't know how this works in other languages)
You need to define different methods with different signatures and cast your type accordingly to get a similar result
fileprivate func resolveDependency<T>() -> T {
// check if this is an Order
resolveForOrder()
// check if this is a Client
resolveForClient()
}
private func resolveForOrder() -> Order {
return LastOrder()
}
private func resolveForClient() -> Client {
return ImportantPerson()
}
This is like trying to fix a space shuttle engine with a car mechanic. Yes, they both have an engine, they both run on fuel but the mechanic only knows how to fix your car's engine he is not a rocket scientist(!)
This code works fine:
import Foundation
protocol Client: class {
var description: String { get }
}
final class ImportantPerson : Client {
var description: String {
return "Important person"
}
}
protocol Order: class {
var description: String { get }
}
final class LastOrder : Order {
var description: String {
return "Last order"
}
}
final class A {
fileprivate func resolveDependency<T>() -> T {
if T.self == Client.self {
return resolve() as Client as! T
} else {
return resolve() as Order as! T
}
}
private func resolve() -> Client {
return ImportantPerson()
}
private func resolve() -> Order {
return LastOrder()
}
}
let a = A()
let client: Client = a.resolveDependency()
let order: Order = a.resolveDependency()
print("Client: \(client.description)")
print("Order: \(order.description)")
But I believe that compiler should resolve the if else clause himself, it's not so hard as I suppose.
Also there is some bug in the compiler when it tries to match types like that:
switch T.self {
case is Client:
return resolve() as Client as! T
default:
return resolve() as Order as! T
}
Is it possible that the variable which initializes my class is computed by a function inside that class?
I first initialize MyClass:
let MyClass = MyClass()
Second, this would be the code in the class:
class MyClass {
var myString = computeRandomString()
func computeRandomString() -> String {
piece of code
return(randomString)
}
}
Whenever I create an instance of MyClass I want the myString to be a randomString. In order for that I made a function within the same class.
There are two options.
First, if computeRandomString does not rely on knowing about anything about specific instances of this class, it could be converted to a class function, or simply moved outside of the class entirely.
For example:
class MyClass {
var myString = MyClass.computeRandomString()
class func computeRandomString() -> String {
return "random string"
}
}
or
func computeRandomString() -> String {
return "random string"
}
class MyClass {
var myString = computeRandomString()
}
The second option is to set it in the initializers (rather than giving it a default value), but you'll only be able to do this after all values (including this one) have been assigned a value.
For example:
class MyClass {
var myString: String
init() {
myString = ""
myString = computeRandomString()
}
func computeRandomString() -> String {
return "random string"
}
}
The reason we can't use an instance method to assign a default value for an instance variable is better explained by the warning generated when we try to use the instance method within an initializer before first giving it a value:
class MyClass {
var myString: String
init() {
myString = computeRandomString()
}
func computeRandomString() -> String {
return "random string"
}
}
On the myString =... line in init, we see the following error:
Use of 'self' in method call 'computeRandomString' before all stored properties are initialized.
This error, unfortunately, does not show up when we use it as the property's default value, as you're trying to do, but it does accurately describe the actual problem.
We cannot use self before our class is fully initialized, and that includes calling methods on self. And until all of our stored properties have valid values, our instance is not fully initialized, so we can never use an instance method to give a non-optional stored property its first value.
A possible solution is a lazy computed property.
The string is created when the property is accessed the first time
class MyClass {
lazy var computeRandomString : String = {
let alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXZY0123456789"
let alphaLength = UInt32(alphabet.characters.count)
var randomString : String = ""
for _ in 0..<20 {
let random = Int(arc4random_uniform(alphaLength))
let index = alphabet.startIndex.advancedBy(random)
randomString += String(alphabet[index])
}
return randomString
}()
}
for _ in 0..<10 {
print(MyClass().computeRandomString)
}
You have to do it like this:
class MyClass {
var myString: String
init() {
self.myString = MyClass.computeRandomString()
}
static func computeRandomString() -> String {
piece of code
return(randomString)
}
}
This will set myString to the results of computeRandomString() on initialisation (creating) of a MyClass-object.
I changed computeRandomString() to static because otherwise it could not be used before initialisation has finished, thanks to #nhgrif.
Why I can't see the output of println() when it is called inside an in statement? And how I can see this output in Xcode?
I have done this dummy test code:
public class TestClass {
public var testType: String = ""
public func test(test:((TestClass) -> Void)!){
testType = "TEST"
}
}
var request = TestClass()
request.test({(response: TestClass) in
println("Test: \(response.testType)")
})
In your example you are calling method test() takes as parameter function of type TestClass -> Void. However, in implementation of test() method you never call passed function, thus println() is never executed.
You could try
public func test(testFunction:((TestClass) -> Void)!){
testType = "TEST"
testFunction(self)
}
You don't call the closure inside TestClass.test
Change it to
public func test(test:((TestClass) -> Void)!){
testType = "TEST"
test(self)
}