How to call instance method inside class using Swift - swift

I am having an issue with calling an instance method within the class itself. If someone can provide me some insight it would be greatly appreciated.
My current code looks like this:
class Rect
{
func printthis() -> String {
return "this is working or what"
}
var toPrint:String = self.printthis()
}
The error I am getting in Xcode is: Use of unresolved identifier 'self'.
What am I missing here?

You can't call an instance method without an instance. The class is merely the template for instances. So i don't what you are trying to do here...
But the answer is no, you cannot call an instance method form the class definition because there is no instance yet.
Perhaps you want to delcare a class method and use that to set an instance variable on creation? If so, you might do that like this:
class Rect {
class func printthis() -> String {
return "this is working or what"
}
var toPrint:String
init() {
toPrint = Rect.printthis()
}
}
var r = Rect()
println(r.toPrint) //-> this is working or what

An instance of a class is not initialized and able to be referenced (even as 'self') until all of its variables have been assigned values.
An option that may work for you is to declare your variable as an implicitly-unwrapped optional, which is assigned nil by default. Then in the class's init method, since all of the variables have been assigned values, you are able to start calling methods on your instance.
class Rect {
var toPrint: String!
init() {
toPrint = printthis()
}
printthis() -> String {
return "this will work"
}
}

the problem is that swift is strict about initing all properties.
you may as a workaround
class Rect
{
func printthis() -> String {
return "this is working or what"
}
var toPrint:String = ""
init() {
toPrint = printthis()
}
}

Related

How to use an array from another class Swift

having a bit of a dilemma here. My method GetData() stores an array in jsondata1. How would I use that array in another class? I already set it as a subclass of Data. Thanks!
class Data {
let parameters = ["test": ViewController().myinfo]
func GetData() {
AF.request("my url", parameters: parameters).responseDecodable(of: Array<JsonData>.self ) { (response) in
let jsondata1 = response.value
// debugPrint(response)
print(jsondata1)
}
}
}
class Testing : Data {
func AnnualTesting() {
//How would I reference jsondata1 here?
debugPrint(jsondata1)
}
}
A few things...see comments.
class Data {
// This kind of thing is the source of more bugs than I can count.
// Are you *sure* you want to create a brand new ViewController that's connected to nothing?
let parameters = ["test": ViewController().myinfo]
// Declare an instance variable so it's visible to the subclass
// (Not sure what data type you want to use here. I'm calling it a String for convenience.)
var jsondata1: String?
func GetData() {
AF.request("my url", parameters: parameters).responseDecodable(of: Array<JsonData>.self ) { (response) in
// Note that this is filled in asynchronously,
// so isn't available as soon as the function is called.
// Currently you have no way of knowing in other code when the result *is* available.
self.jsondata1 = response.value
// debugPrint(response)
print(jsondata1)
}
}
}
class Testing : Data {
func AnnualTesting() {
//How would I reference jsondata1 here?
debugPrint(jsondata1 ?? "Nothing to see here")
}
}
Your declaration of jsondata1 is in scope of some block.
It is not visible from outside.
You have to declare it in interface of class,
just like you did with variable "parameters".
In general you can access variable from another class if it's declared in interface. It can be declared as instance variable or static (class) variable. And you should have instance of class to access instance var and should not have instance to access class / static variable.
Or as you did, via inheritance.

Weird ambiguity for class func() in inherited classes [Swift]

I have a simple class hierarchy like this in Swift.
class Parent {
var name:String = "Unnamed"
class func all() -> [Parent] {
return Dad.all() + Mom.all()
}
}
class Dad:Parent {
static var AllDads:[Dad] = []
class func all() -> [Dad] {
return AllDads
}
}
class Mom:Parent {
static var AllMoms:[Mom] = []
class func all() -> [Mom] {
return AllMoms
}
}
Mom.all().forEach { mom in
print(mom.name)
}
If I put this in a workspace, everything is good until I hit the run button. At which point it tells me that the last expression Mom.all() is ambiguous. Why is this? Is there not a way to have a class func which refines in the subclass for the subtype, and keep them unambiguous?
The reason is that the all on Parent and the all on Mom have different signatures. Thus, the all on Mom cannot be an override for that on Parent (also shown by the fact that the compiler does not require the override keyword). What this means is that two class functions named all exist on the Mom type. Furthermore, the closure you are passing to forEach does not specify a parameter type, so it is impossible to be sure of which of the two functions is being referenced. Assigning a type to the mom parameter in the forEach will solve this problem.
Until you instantiate a Mom, and call it on that instance of Mom, it will be ambiguous.

Xcode 9: method parameter not available in debugger?

I've got an issue where I'm calling a method with generic a generic parameter that works properly (at runtime, the parameter is visible to the method), however in the Xcode debugger, the parameter is "not there").
The definition of the method looks like this:
func updateCacheObject<T: PLObjectCacheable>(newCacheObject: T) throws -> T {
NSLog("CacheObject.cacheId: \(newCacheObject.cacheId)")
let cachedObject: T? = try self.getCacheObject(id: newCacheObject.cacheId)
...
Where the PLObjectCacheable is defined as:
protocol PLObjectCacheable {
var cacheId: String { get }
var isFullObject: Bool { get }
func mergeWithOldObject(_ oldObject: Self?) -> Self
static func getCacheIdForString(id: String) -> String
var cacheDate: Date { get }
}
and an implementation of a class that implements PLObjectCacheable is this:
struct FullTrack: PLObjectCacheable {
let id: String
var cacheId: String {
return self.id
}
var isFullObject: Bool {
return true
}
...
}
So, going back to the updateCacheObject method, when it's called, the first line dumps out the newCacheObject parameter's cacheId member variable.
This works fine.
However, if I place a breakpoint in the Xcode debugger anywhere in the method, Xcode can't "see" the newCacheObject parameter.
See the image:
Note that the Blue/Cyan square shows that the newCacheObject.cacheId was successfully logged.
The Red and purple squares show that the debugger can't find the newCacheObject variable.
Is it because it's a generic parameter? I'm confused.
Thanks.

Swift protocol settable property through a read-only property [duplicate]

This question already has an answer here:
Swift: Failed to assign value to a property of protocol?
(1 answer)
Closed 6 years ago.
Can someone please tell me why Swift has to call the setter of a property when it's only being used to access an object (a protocol) in order to set one of its properties? This first example shows the error I get if I don't declare the indirect object as settable:
protocol AProtocol {
var name: String { get set }
}
class AnImplementation: AProtocol {
var name = ""
}
class AParent {
var test = AnImplementation()
}
class AChild {
var parent: AParent!
var test: AProtocol {
get { return parent.test }
// Note: Not settable
}
}
var parent = AParent()
var child = AChild()
child.parent = parent
child.test.name = "Hello world!" // Error: Cannot assign to property : 'test' is a get-only property
print(child.test.name)
If I give it a setter, it compiles and works but it calls the setter:
protocol AProtocol {
var name: String { get set }
}
class AnImplementation: AProtocol {
var name = ""
}
class AParent {
var test = AnImplementation()
}
class AChild {
var parent: AParent!
var test: AProtocol {
get { return parent.test }
set(newTest) { print("Shouldn't be here!") }
}
}
var parent = AParent()
var child = AChild()
child.parent = parent
child.test.name = "Hello world!"
print(child.test.name)
Output is:
Shouldn't be here!
Hello world!
I'm not sure what I'm not understanding here. I assume I can just give it an empty setter, but I'd like to understand the reason for it.
Any information is much appreciated!
Change your protocol declaration to this:
protocol AProtocol:class {
var name: String { get set }
}
Otherwise, it is taken by default as a value type. Changing a value type's property replaces the value type instance (as shown by the setter observer). And you can't do that if the reference is a let reference.
This is probably caused by the fact that the compiler doesn't know whether AChild.test is a class or a value type. With classes there is no problem but with value types assigning to name would also create an assignment to test (value-copy behavior). Marking APProtocol as class protocol will fix the problem.
To expand, when the compiler is not sure whether test is a value or a class type, it will use the following rewrite of child.test.name = "Hello world!":
var tmp = child.test
tmp.test = "Hello world!"
child.test = tmp
because that will work for both class and value types.

Swift error when a method has not been called previously

Hi I would like to ask if it is any way to get an error on xCode at compiling, when you are using a class method that needs to call first to another method?
I explain:
class MyClass {
func initializeClass(){
}
func loadConfig() {
}
}
var myClass = MyClass()
myClass.loadConfig() --> Throw Error while coding, the same as you get when you don't implement a required protocol function
Correct way :
myClass.initializeClass().loadConfig()
One way to approach this situation is by using the Proxy Design Pattern. Rather than adding both methods to MyClass, make loadConfig() an instance method of MyClassInitProxy:
public class MyClass {
public class MyClassInitProxy {
let owner:MyClass
public func loadConfig() {
// Do the config work using owner to access MyClass
}
private init(owner:MyClass) {
self.owner = owner
}
}
public func initializeClass() -> MyClassInitProxy {
// Do preparation, then
return MyClassInitProxy(owner:self)
}
}
Now the only way one could call loadConfig is by obtaining MyClassInitProxy through initializeClass() call:
var myClass = MyClass()
myClass.initializeClass().loadConfig()
The short answer is - No, you can't have a compile-time error using this approach.
However if you want to make it impossible for anyone to instantiate your class without having configuration prepared, then just require the configuration as an argument in the initializer. E.g.
class MyClass {
init(config: YourConfigType) {
// do something with the config parameter
}
}
... read config from somewhere and create config variable ...
let x = MyClass(config: config)
And then you have a "compile time error" whenever someone wants to use your class without having config setup initially.