I have 2 classes in Swift in different Swift files, and I'm trying to call a method from the other class, and pass an integer as an argument. I have the following:
Class 1:
Inschatting.wentBack(Punten)
Class 2:
class Inschatting : UIViewController {
var Punten:Int = 0;
#IBOutlet var inschattingAdvies: UILabel!
func wentBack(Punten:Int) {
self.inschattingAdvies.text = Punten
}
}
Given error: Cannot convert value of type "Int" to expected argument type 'Inschatting'
Bonus question: Class 2 also complaints about the fact I want to put down a String, but it's clearly an Int
When you want to call your wentBack()-Func like above you should declare it as a class function... otherwise you should create an instance of Inschatting.
the problem is that Inschatting should declare the function the following way:
static func wentBack(Punten:Int) {
self.inschattingAdvies.text = Punten
}
But the problem is that, that you have an instance value the wentBack function.
self.inschattingAdvies
Now what you need to do is to make a decision:
1. you should call the wentback function on a Inschatting instance.
In Class A:
let instance = Inschatting()
instance.wentBack(5)
2. You should remove the self.inschattingAdvies from wentBack.
Answer to your bonus question:
"Punten" does not seem to be an integer, or an enum value at all to me.
Since your Inschatting class is a UIViewController, I suspect you want to display the data from your 1st class in your UIViewController. If this is indeed true your mistake is that you are using a Class instead of an instance of the class.
If you indeed want to display the data from your 1st class in your 2nd class (The VC), you will need to create a class instance of your second class.
let inschattingVC = Inschatting()
this way you can use inschattingVC.wentBack(someRandInt) to call your function and set the text accordingly.
Secondly your Punten in Inschatting.wentBack(Punten) is also probably not a variable but again an instance (or you should rename it. Variables should start with lowercase letters!!!).
So if you are creating a class instance using Inschatting() you should be able to use .wentBack(12345) to set the text in your class instance.
First you say :
#IBOutlet var inschattingAdvies: UILabel!
so inschattingAdvies is a UILabel
Then you have a function :
func wentBack(Punten:Int) {
self.inschattingAdvies.text = Punten
}
where you have Punten which is an integer. And then you try to set the text property of your label to punten.
Your code should be :
func wentBack(Punten:Int) {
self.inschattingAdvies.text = String(Punten)
}
note the cast to a string.
Not sure if that's the error you were getting, but it's definitely also an error.
Related
I have two .swift files so I want one of them to modify the text of an IBoutlet label that is the other class.
Class 1:
class class1: UIViewController {
#IBOutlet var label1: UILabel!
}
Class 2:
class class2: SKScene {
var cool_variable = 1
func coolFunc () {
class1.label1.text = "\(cool_variable)"
}
}
by doing this I'm getting the following error message:
Instance member "label1" cannot be used on type "class2"
Thanks in advance!
The distinction and relationship between classes and instances is absolutely crucial to object-oriented programming. Thus, consider your proposed code:
func coolFunc () {
class1.label1.text = "\(cool_variable)"
}
The problem here is that class1 is the name of a class. (That would be more obvious if you just, please, follow the elementary rule that class names start with a capital letter.) But label1 is an instance property. Thus what you need here is the name of an instance of the class1 class — presumably a reference to the actual existing instance that is already part of the view hierarchy.
You never create an instance of class1 in class2 to access the variables.
My guess is that you are using Storyboards. In this case you wouldn't want to create an instance of class1. Instead you would use delegation (This would also be a good idea if you are not using Storyboards).
Delegation can be a complicated topic, so I will try to keep this simple.
First, you start with a protocol. Usually you name it something like <CLASS-NAME>DataSource, so you would do something like:
protocol class2DataSource: class {}
The class keyword is required for delegation protocols.
Then you would add the methods to it that you want called in other classes when you call a method in the class the protocol delegates for, so, for example, willCoolFunc:
protocol class2DataSource: class {
func willCoolFunc(with variable: Int)
}
You have the parameter so you can access the variable cool_variable as you are trying to.
Next, you need to create a a variable in class2 that is of type class2DataSource:
weak var dataSource: class2DataSource?
Make sure the variable is weak and an optional.
Next, call the method, you would do it in coolFunc:
func coolFunc () {
dataSource?.willCoolFunc(with: cool_variable)
}
Now you, to access cool_variable when the function is called, you need to implement class2DataSource on class1. Create an extension of class1 that implements class2DataSource and add the function willCoolFunc:
extension class1: class2DataSource {
func willCoolFunc(with variable: Int) {
}
}
Now you can access the variable cool_variable in class1! The reason why is because when you call class2.coolFunc(), the willCoolFunc method is called with cool_variable passed in. Any class that implements the class2DataSource can access cool_variable with the willCoolFunc method.
To finish of the method, here is what the extension would look like:
extension class1: class2DataSource {
func willCoolFunc(with variable: Int) {
self.label1.text = "\(variable)"
}
}
We are almost done, but not quite. We still have to set the class1 as the data source for class2DataSource. To do this, I will reference Nikolay Mamaev from this post:
Go to the Interface Builder.
Type "Object" in the search text field of the Objects Library and drag an 'Object' to your view controller containing that connects to
class1 (i.e. do the same as you add any view or view controller to
storyboard scene, with the exception you add not a view or view
controller but an abstract object).
In the left-side 'Scenes' panel of your storyboard, highlight just added Object; in right-side panel go to the 'Identity Inspector' and
type class2DataSource instead of pre-defined NSObject. In left side
panel ('Scenes'), 'Object' will be renamed to 'Class2 Data Source'
automatically.
In the left-side 'Scenes' panel of your storyboard, control-drag from your UIView [*not the controller*] to the 'Class2 Data Source';
in pop-up appeared, select dataSource outlet.
There! You now set class1's label1's text to the value of cool_variable when you call class2.coolFunc()!
I do not know the exact problem you're trying to solve, but I'm just going to consider the part that you want to access the variable in class1 in class2. There are two basic ways to go about this, one is Inheritance and the other one is by creating an object. These are basic Object Oriented Programming concepts which you need to be familiar with.
Swift does not support multiple inheritance. So that rules out inheritance for solving you problem, since you are inheriting two classes SKScene and UIViewController.
Create an object in the class1 and call the function coolFunc
class class1: UIViewController {
#IBOutlet var label1: UILabel!
func modifyLabel(){
let someObject = class2()
someObject.coolFunc()
}
}
Of course this solution might not be the one you're looking for. You will have to explain more about the problem you're facing if you need a solution that will work for you.
I have a custom swift class like this
class NichedHelper: NSObject {
private var _theController:UIViewController? = nil
var theController:UIViewController? {
get {
return self._theController
}
set {
self._theController = newValue
}
}...
it has an implementation function like this and _theController passing a Lobb class that inherit UIViewController
func DoPump(from: String, theBoard: CGRect, overide: Bool) {
let abil:AnyObject = _theController!
abil.bottomConst.constant = -80
}
it throw error 'AnyObject' does not have a member named 'bottomConst'.
since i don't know what the english word for this kind of technique, so that will be my first question.
my second question, is it possible if i am sure Lobb class (or other class) have a variable called bottomConst, how can i access it from class NichedHelper?
you have declared the _theController as private , remove that just declare as
var _theController:UIViewController!
// this is how we roll in swift ;) bye bye Objective-C
I don't know exactly what you are trying to do and why you have two UIViewController instances. So I'm not able to answer your first question but regarding your second one, you have to cast the object to a UIViewController object:
func DoPump(from: String, theBoard: CGRect, overide: Bool) {
let abil:AnyObject = _theController as! UIViewController
abil.bottomConst.constant = -80
}
This at least should make the compiling error away, if you have the bottomConst attribute declared as a variable of UIViewControllers in an extension (since they do not have this variable normally.
Well, i change from passing the UIViewController to NSLayoutConstraint
In Swift:
How can I assign a topmost myObject to the innerObj variable?
Does swift have some sort of namespace operator that lets me create an myObject from global namespace?
Consider the code below.
//my object that can init with a message=string
class MyObject {
init(message: String) {
println(message)
}
}
//here I define a global works fine
let global = myObject(message: "this works")
//other class
class ViewController: UIViewController {
//defines an inner class with same name
class MyObject {
func failsFunction(){
//cannot invoke initializer for type "ViewController.myObject" with an argument of type (String)
let innerObj = myObject("how can I refer to the topmost myObject here?")
}
}
}
My first answer would be "don't do that." It's technically legal because the two classes have unique scope, but it's confusing as all hell, and will come back to bite you 6 months from now when you are coming back to this code and don't remember that you have a global class and a child class of ViewController with the same name.
If you are going to ignore that advice, Lou provided your solution: Create a typeAlias at the top level and use that inside your ViewController class so that you can reference the global class inside ViewController.
Secondly, class names should start with an upper-case letter. So class myObject should be class MyObject. This is a documented convention of the language.
Thirdly, myObject is a dreadful name for a class. It doesn't give you any idea what the class is for. Even if this is a learning exercise, you should still follow good coding practices. It trains good habits, and test code has a way of finding itself in real projects, or posted as demo code somewhere, or whatever.
You need to alias it before you hide it with:
typealias GlobalMyObject = MyObject
One usual way is to bind your outer class into struct. This pattern is quite similar to creating a namespace. You could do it like this
struct MyNameSpace {
class myObject {
init(message: String) {
print(message)
}
}
}
//here I define a global works fine
let global = MyNameSpace.myObject(message: "this works")
//other class
class ViewController: UIViewController {
//defines a subclass with same name
class myObject {
func failsFunction(){
//cannot invoke initializer for type "ViewController.myObject" with an argument of type (String)
let innerObj = MyNameSpace.myObject(message: "how can I refer to the topmost myObject here?")
}
}
}
Then, you could use both the classes and the compiler determines the use cases differently for both.
I have the following closure:
class BISSettingController : XLFormViewController {
class func initializeForm() -> XLFormDescriptor {
var form : XLFormDescriptor
var section : XLFormSectionDescriptor
var row : XLFormRowDescriptor
form = XLFormDescriptor()
row = XLFormRowDescriptor(tag: "tag", rowType: XLFormRowDescriptorTypeButton, title: "Title")
row.action.formBlock = {[weak self](sender: XLFormRowDescriptor!) -> Void in
self?.deselectFormRow(sender)
...
}
}
}
I want to use self as weak reference inside the closure. But when I build the code I get the following error:
'weak' cannot be applied to non-class type 'BISSettingController.Type'
How can I solve this to make it work?
The problem is that this is a class method (class func). In a class method, self means the class. There is no need for memory management on a self representing the class; the class cannot "leak", because it persists for the life of the app anyway. Thus, you cannot describe a reference to a class as weak.
Based on the error message you're getting, it sounds like self is not an object, so you don't need the access list at all.
Can you post more information on the object that contains this code?
EDIT:
Looking at your updated question, it seems that the code you're using is in a class method, not an instance method. That code doesn't seem to make sense from a a class method however.
Here is a swift class file:
import Foundation
class DataPreparation {
// Variables
var userCountries = [String]() //Just 1 or 2 countries
var correspondingFullArrays = [[String]]()
//Get and set raw user countries from current image
func getUserCountries(countries: [String]) -> [String] {
userCountries = countries
return userCountries
}
func getCorrespondingFullArraysToUserCountries() {
println(userCountries) //Is empty
}
On a separate file viewController, the 2 methods lisOfCountries and getCorrespondingFullArraysToUserCountries are invoked independently one after the other:
DataPreparation().getUserCountries(otherArray[0])
DataPreparation().getCorrespondingFullArraysToUserCountries()
Problem is that second method can't access userCountries data set by first method because it is empty.
My guess, and you will correct me if i'm wrong, is that variables get destroyed after each method call.
So how are we supposed to handle small data persistance from one function to another, when they are called separatly ? I could of course regroup all in a single function, but is this the good way of doing ?
In each line of this code:
DataPreparation().getUserCountries(otherArray[0])
DataPreparation().getCorrespondingFullArraysToUserCountries()
you are creating a new instance of DatePreparation, and then calling a method on it. Since you do not assign the instance to a variable, the instance is destroyed as soon as it goes out of scope, which in this case corresponds to the same line where it is instantiated.
You should create an instance (and not 2), and assign to a variable. Then, you can call methods on that instance:
var dataPreparation = DataPreparation()
dataPreparation.getUserCountries(otherArray[0])
dataPreparation.getCorrespondingFullArraysToUserCountries()
When you are calling the function getCorrespondingFullArraysToUserCountries on DataPreparation() you are creating another instance each time.You are creating DataPreparation() instance each time. instead use
//create instance only first time
var dataPreparation:DataPreparation = DataPreparation()
//call methods on same instance
dataPreparation.getUserCountries(otherArray[0])
dataPreparation.getCorrespondingFullArraysToUserCountries()