Why Instance member 'getPerson' cannot be used on type 'GetPerson' - swift

I write code in a Cocoa framework and call the function in it from main project. But it fails always returning a message. I fix this in two ways.
First, in main project viewController:
import getPerson
override func viewDidLoad() {
super.viewDidLoad()
var person = GetPersons.getPerson(name: "Jack")
}
Returns:
Instance member 'getPerson' cannot be used on type 'GetPerson'; did you mean to use a value of this type instead
Second:
import getPerson
override func viewDidLoad() {
super.viewDidLoad()
let vc = GetPersons.self
var person = vc.getPerson(name: "Jack")
}
Returns:
Instance member 'getPerson' cannot be used on type 'GetPersons'
What's happening with this? How do I fix it?
In test framework :
import Fundation
public class GetPersons {
public struct Person {
public var name : String = ""
public var age : Int = 0
}
public func getPerson(name : String) -> Person {
var person = Person()
return person
}
}

In your first example, it's telling you that you defined getPerson(name: String) as an instance method. (Presumably because it operates on instance properties.)
You are calling it here as if it were defined as:
static func getPerson(name: String) { ...
The second is saying much the same thing, without guessing what you want to do.
If I understand what you want to do, I think it goes something like this:
class GetPersons {
struct Person {
public var name : String = ""
public var age : Int = 0
}
func getPerson(name : String) -> Person {
var person = Person()
return person
}
}
Then, in your view controller define a property for the instance of GetPersons:
let gp = GetPersons()
then in viewDidLoad:
let person = gp.getPerson(name: "Jack")
Also, is GetPersons in an actual framework, or is it simply a class defined (as it should be) in a separate file?

Related

Using an overriden static property during initialization

I would like to create a class with a static property that subclasses can override, which would be used to initialize instances. So far, I've tried to accomplish this like this:
import Cocoa
class A: NSObject {
class var staticProperty: String {
return "A"
}
var property: String = A.staticProperty
}
class B: A {
override class var staticProperty: String {
return "B"
}
}
This does not work, since B().property still returns "A". How could I change this code so that property contains the value specified by the subclass? Any help would be appreciated!
Edit
I would like to initialize property with the value of staticProperty, so this could also look like this:
var property: SomeClass = SomeClass(A.staticProperty)
But then, this initialization should still use "A" for class A, and "B" for class B.
Edit 2 (After #RakeshaShastri's comment)
For my specific use-case, I need property to be stored (so not computed) and non-lazy.
Edit 3
In short, I'm trying to build a Realm model class which has a few to-many relationships to other models. For these models (which are quite similar), I'm trying to create a superclass which contains the shared functionality, amongst which is also the inverse relationship. Therefore, I want to have a static property which contains the key in the first model to either of the other models, and then initialize a LinkingObjects property using this key name. Since Realm does not allow this to be lazy or computed, I cannot use these functionalities here.
If you inherit from NSObject why not using it ?
import Cocoa
class A: NSObject {
var property: String
public override init() {
let str = type(of: self).perform(#selector(getter: type(of: self).staticProperty))?.takeUnretainedValue() as! String
property = str
}
#objc class var staticProperty: String {
return "A"
}
}
class B: A {
override class var staticProperty: String {
return "B"
}
}
You can do this with this aproach
class A {
var prop: String{
return "A"
}
}
class B: A {
override var prop: String{
return "B"
}
}
print(A().prop) // "PRINTS A"
print(B().prop) // "PRINTS B"
A.staticProperty will use static dispatch and will always point to A's class property. You need dynamic dispatch here, aka type(of: self).
However, self needs an instance to work with, thus var property: String = type(of: self.staticProperty won't compile.
However, lazy properties can work around this limitation, so you could declare property as a lazy one:
class A: NSObject {
class var staticProperty: String {
return "A"
}
private(set) lazy var property: String = { type(of: self).staticProperty }()
}
class B: A {
override class var staticProperty: String {
return "B"
}
}
print(B().property) // B
P.S. the private(set) part is just something I usually do, I rarely allow extrinsic factors to change my object.
Update As #MartinR has pointed out, lazy is not a choice for the OP. An alternative solution that doesn't use a lazy var is to use a "shadowing" property:
class A: NSObject {
class var staticProperty: String {
return "A"
}
private var _property: String?
var property: String {
get {
return _property ?? type(of: self).staticProperty
}
set {
_property = newValue
}
}
}
class B: A {
override class var staticProperty: String {
return "B"
}
}
let b = B()
print(b.property) // B
b.property = "B'"
print(b.property) // B'

Pass a class type for use inside a method

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.

Get object type from optional?

Is it possible to get the object type from an optional?
For example, if I have a class that has a property that is an optional string, can I somehow just get back the string type?
The exact use case I have is I have many custom classes all of which have a property that is storing another custom class as an optional value. I would like to write a generic function that will create an instance of the object class stored in the optional.
Here is an example of what I am looking for, although .dynamicType does not work since it is an optional:
class Class1 {
}
class Class2 {
var myOp: Class1?
}
var c = Class2()
c.myOp = c.myOp.dynamicType()
Since you wanted to use this with Generics I tried it for you. It works, but it may not be so useful.
First some setup:
This is a helper protocol to make sure our Generic type will have a known init method.
protocol ZeroParameterInit {
init()
}
This is an extension to get the type from an optional:
extension Optional {
var dynamicWrappedType : Wrapped.Type {
return Wrapped.self
}
}
Implemented in your code:
class Class1 : ZeroParameterInit {
required init() {}
}
class Class2 {
var myOp: Class1?
}
var c = Class2()
c.myOp = c.myOp.dynamicWrappedType.init()
Generic implementation:
class Class1 : ZeroParameterInit {
required init() {}
}
class Class2<T where T : ZeroParameterInit> {
var attribute: Optional<T>// used long syntax to remind you of : Optional<Wrapped>
init(attr:T) {
attribute = attr
attribute = nil
}
}
The function to create the instance:
func myFunc<T>(instance: Class2<T>) -> T {
return instance.attribute.dynamicWrappedType.init()
}
Some tests:
let alpha = Class1()
let beta = Class2(attr: alpha)
beta.attribute = myFunc(beta)
The issue:
You can't create an instance of Class2 without informing it about the type of it's generic attribute. So you need to pass it some object/type and that complicates things again.
Some extra methods that might improve how it all works:
init() {
}
let delta = Class2<Class1>()
delta.attribute = myFunc(delta)
init(type:T.Type) {
}
let epsilon = Class2(type: Class1.self)
epsilon.attribute = myFunc(epsilon)
You just need to check if the optional exist:
func myFunc(c: Class2) -> Class1? {
if let c1 = c.myOp{
return c1.dynamicType()
}
return nil
}
OR
func myFunc(c: Class2) -> Class1? {
if c.myOp != nil{
return c.myOp!.dynamicType()
}
return nil
}
Note the your return type need to be optional as well.
Tried this in simulator, seems like doing the right thing, if I understood you
class Class1 {
}
class Class2 {
var myOp: Class1?
}
func myFunc(c: Class2) -> AnyObject {
if let c1 = c.myOp{
return c1.self
}
return c
}
var object = Class2()
object.myOp = Class1()
myFunc(object) // Class1

Accessing class objects in different classes

There are a total of 3 classes in all.
In the first class, it will do all init to manage the strings.
In the second class, it creates an array of class objects for first class.
In the third class, it will access the data stored in the second class. (This is where I need to know.)
FirstClass.swift
class Person{
var name : String
var description : String
init(name: String, description: String){
self.name = name
self.description = description
}
SecondClass.swift
class StoreData: UIViewController {
var personList = [Person]()
override func viewDidLoad() {
super.viewDidLoad()
self.personList.append(Person(name: "John", description: "123"))
self.personList.append(Person(name: "Mary", description: "456"))
}
ThirdClass.swift
So in this class, I need to access the data that is stored in SecondClass.swift. Say I wat to store in a string array of names. I want to extract where var names = personList[0].name How do I do so?
The easiest way in your case to make it work is like this:
class StoreData: UIViewController {
static var sharedData = StoreData()
var personList = [Person]()
override func viewDidLoad() {
super.viewDidLoad()
self.personList.append(Person(name: "John", description: "123"))
self.personList.append(Person(name: "Mary", description: "456"))
}
}
class ThirdClass {
func someFunc() {
let person1 = StoreData.sharedData.personList[0]
print(person1)
}
}
But it's not the best way, but you can't explain what you need. Hopes you understand, that this code makes singleton from StoreData. And it will work for you task.

Swift Get value from function

I have two class and i would like to get a variable with the value (the variable is in a function) to my second class :
public class StreamPlayer {
class var sharedInstance : StreamPlayer{
struct Static {
static let instance : StreamPlayer = StreamPlayer()
}
return Static.instance
}
public var intermediate = NSString()
func metaDataUpdated(metaData : NSString){
var result : String = ""
var listItems = metaData.componentsSeparatedByString(";") as [String]
if (listItems.count > 0){
var containerName = listItems[0]
result = "StreamTitle=\'([^\"]*)\'".matchesForRegexIn(containerName, atRangeIndex: 1)
self.intermediate = result
}
}
}
and the second class
class RadioViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
println(test + StreamPlayer.sharedInstance.intermediate)
}
}
The problem is that the var intermediate doesn't change and don't get the value of result (in my first class)
I've copied your StreamPlayer class code into a playground. I've just commented out the matchesForRegexIn method as it seems it's your String extension so my code looks like this:
public class StreamPlayer {
class var sharedInstance : StreamPlayer{
struct Static {
static let instance : StreamPlayer = StreamPlayer()
}
return Static.instance
}
public var intermediate = String()
func metaDataUpdated(metaData : NSString){
var result : String = ""
let listItems = metaData.componentsSeparatedByString(";") as [String]
if (listItems.count > 0){
// var containerName = listItems[0]
result = "StreamTitle=\'([^\"]*)\'" //.matchesForRegexIn(containerName, atRangeIndex: 1)
intermediate = result
}
}
}
// calling the method to make sure intermediate gets updated
StreamPlayer.sharedInstance.metaDataUpdated("asd")
// check if it got updated
print(StreamPlayer.sharedInstance.intermediate)
The last line prints StreamTitle=\'([^\"])\'* so all is good. Just make sure to call StreamPlayer.sharedInstance.metaDataUpdated before checking intermediate
PS. I'm really not sure what you're trying to achieve by sharing intermediate results from a function to the outside world but it feels off. Think about splitting metaDataUpdated method into two methods maybe?
PPS. metaDataUpdated is a really bad name for a function
PPPS. If I were you I'd declare intermediate as String?
self.intermediate is a NSString while result is a String
Try
self.intermediate = result as NSString