Class as function parameter in Swift - ios

In my app there are many classes for different ViewControllers.
I am searching way to give class name as function parameter so i can use it in function.
Example
func myFunc (var1: String, var2 : Int, var3 : myClass) {
var example = myClass();
example.name = var1;
example.age = var2;
}
i saw this thread Class conforming to protocol as function parameter in Swift but i didn't understand how can i solve my problem with it.

You can do this without the need to pass an instance of your view controller:
import Cocoa
protocol MyViewControllerType : class {
var name : String { get set }
var age : Int { get set }
}
class FirstViewController : NSViewController, MyViewControllerType {
var name = ""
var age = 0
}
class SecondViewController : NSViewController, MyViewControllerType {
var name = ""
var age = 0
}
func myFunc<VC : NSViewController where VC : MyViewControllerType>(viewControllerType: VC.Type, name: String, age: Int) -> VC {
let viewController = VC()
viewController.name = name
viewController.age = age
return viewController
}
let first = myFunc(FirstViewController.self, name: "Bob", age: 20)
let second = myFunc(SecondViewController.self, name: "Paul", age: 30)

Related

Swift Inheritance(Extending classes)

i have two classes ClassA,ClassB,ClassC and ClassC is extended from ClassA
open class classA: NSObject{
var firstName = String()
var lastName = String()
}
open class classB: NSObject{
public func getObject(dictionary : Dictionary<String,Any>) -> Dictionary<String,Any>{
var Dict : [String: Any] = [:]
var ListArray = Array<Any>()
let tempArray = dictionary["data"] as! Array<Any>
for item in 0..<tempArray.count{
let dict = tempArray[item] as! NSMutableDictionary
let myclass = classA()
if let val = dict["firstName"] as? String{
myclass.firstName = val
}else if let val = dict["lastName"] as? String{
myclass.lastName = val
}
ListArray.append(myclass)
}
Dict["data"] = ListArray
return Dict
}
}
if i extend the ClassC like this
public ClassC : ClassA{
var age = String()
var address = String()
}
Is there any way to use this ClassC variables in class B function getObjects ?
i can't move ClassC variables to ClassA.
Can any one help me to achieve this.
Thanks in Advance.
You can use the type as value and pass it as a parameter:
class ClassB {
func someFunc(A: ClassA.Type) {
let classA = A.init(f: "firstName", l: "lastName")
print(classA)
}
}
You'll have to pass the type like this:
let b = ClassB()
b.someFunc(A: ClassA.self)
Swift's polymorphism applies here which means even if you pass ClassC, it'll be permitted:
let b = ClassB()
b.someFunc(A: ClassC.self)
You'll have to have a required initializer for the subclasses:
open class ClassA: NSObject{
var firstName: String?
var lastName: String?
required public init(f: String = "", l: String = "") {
self.firstName = f
self.lastName = l
}
}
class ClassC : ClassA {
var age = String()
var address = String()
}

Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) in project

I just started Swift and I am having problems.
I want pagination, and I coded this.
model:
struct MoreListAppand {
var MoreNoticeListModel : [MoreNoticeListModel] = []
mutating func addTask(task: MoreNoticeListModel){
MoreNoticeListModel.append(task)
}
}
struct MoreNoticeListModel {
var pageInfo : PageInfoFragmentModel? = nil
var totalCount : Int = 0
var edges: [NoticeInfoModel] = []
mutating func map(MoreNoticeListModel item: NoticeList){
self.pageInfo = nil
let pageData = item.pageInfo
var pageModel = PageInfoFragmentModel()
pageModel.map(item: pageData.fragments.pageInfoFragment)
self.pageInfo = pageModel
self.totalCount = item.totalCount
print("NoticeList totalCount == ", self.totalCount)
self.edges.removeAll()
for edge in item.edges! {
var edgeModel = NoticeInfoModel()
edgeModel.map(NoticeInfoModel:(edge?.fragments.edgesInfoFragment)!)
self.edges.append(edgeModel)
}
}
}
struct PageInfoFragmentModel {
// var hasNextPage : Bool << If I do not comment, an error will appear.(Missing argument for parameter 'hasNextPage' in call)
// var hasPreviousPage : Bool
var startCursor : String = ""
var endCursor : String = ""
mutating func map(item:PageInfoFragment) {
// self.hasNextPage = item.hasNextPage
// self.hasPreviousPage = item.hasPreviousPage
self.startCursor = item.startCursor
self.endCursor = item.endCursor
}
}
struct NoticeInfoModel {
var cursor : String = ""
var id : String = ""
var type: noticeType = .URGENT
var title: String = ""
var createdAt: String = ""
mutating func map(NoticeInfoModel item: EdgesInfoFragment){
self.cursor = item.cursor
self.id = item.node.id
self.type = noticeType(rawValue: item.node.type.rawValue)!
self.title = item.node.title
self.createdAt = item.node.createdAt
print("NoticeList title == ", self.title)
print("NoticeList type == ", self.type)
}
}
and
#objc func myAction(_ sender : AnyObject) {
//sever connect
MoreAPI.shared.getNoticeList(first: 10, last: 0, offset: 0, after: "MjAxNy0xMi0wNVQxNzo1MDozMVo=", before: ""){
[unowned self] (noticeItemLists) in
self.noticeAddListDataModel?.addTask(task: noticeItemLists)
let indexPath:IndexPath = IndexPath(row:((self.noticeAddListDataModel?.MoreNoticeListModel.count)!), section:0) << this is error line
self.noticeListTable.reloadData()
}
}
self.noticeAddListDataModeldefined here
class MoreNoticeViewController: UIViewController {
var noticeAddListDataModel : MoreNoticeListModel? = nil
}
why PageInfoFragmentModel want "hasNextPage" parameter argument..?
I got error
"let indexPath:IndexPath = IndexPath(row:((self.noticeAddListDataModel?.MoreNoticeListModel.count)!), section:0)" line.
I do not know why I get this error....
The error Missing argument for parameter 'hasNextPage' in call states that you have a variable defined in the struct and not initialized. Since it is not initialized, you have to pass its value in the constructor call,i.e. where you are calling PageInfoFragmentModel(), you have to call PageInfoFragmentModel(hasNextPage: ). This constructor is defined by default by swift, if no constructor is defined. So to remove the bug, either you give it a value or make it an optional or pass its value in initialization. Read this : https://docs.swift.org/swift-book/LanguageGuide/Initialization.html for more info.
Follow naming convention, which is for variables camelCase.
struct MoreListAppand {
var MoreNoticeListModel : [MoreNoticeListModel] = []
mutating func addTask(task: MoreNoticeListModel){
MoreNoticeListModel.append(task)
}
}
here var var MoreNoticeListModel is Struct name, change it to var moreNoticeListModel.
1. why PageInfoFragmentModel want "hasNextPage" parameter argument..?
That is a model written by someone who added that variable that is why it is there, we won't be able to tell about that. If there is no use of those variables comment them.
2.
noticeAddListDataModel doesn't have any reference to MoreNoticeListModel instead it is of same type, you can't get count property from a model.
Maybe this is what you need ? self.noticeAddListDataModel?.totalCount or self.noticeAddListDataModel?.edges.count.

Unrecongnized Selector name

Unrecognized Selector to instance name.
I want to create partion array from section. I am trying to do this in swift 2, but I am not able to get it to work.
var currentCollation : UILocalizedIndexedCollation!
var sections: [Section] {
let selector: Selector = "name"
let users: [User] = array.map { name in
let a = name["fullName"] as? String
let b = name["email"] as! String
let c = name["mobile"] as! String
let d = name["img"] as! String
let user = User(name: a! )
user.email = b
user.mobile = c
user.img = d
user.section = UILocalizedIndexedCollation.current().section(for: user, collationStringSelector:"name")
return user
}
var sections = [Section]()
for _ in 0..<currentCollation.sectionIndexTitles.count {
sections.append(Section())
}
for user in users {
sections[user.section!].addUser(user: user)
}
print(sections)
for section in sections {
print(section.users)
var user = section.users as? User
print(user?.name)
section.users = self.currentCollation.sortedArray(from: section.users, collationStringSelector: "name") as! [User]
}
return sections
}
#objc class User: NSObject {
let name: String
var section: Int?
var img: String?
var email: String?
var mobile : String?
init(name: String) {
self.name = name
}
}
class Section {
var users: [User] = []
func addUser(user: User) {
self.users.append(user)
}
}
Don't use strings for selectors in Swift. Use the #selector construct:
let selector: Selector = #selector(name)
However, that will only work if the current class is an NSObject and has an Objective-C function "name" that has no parameters:
class Foo: NSObject {
#objc func name() {
print("In \(#function)")
}
}
(Actually, you can create a selector to an object that doesn't inherit from NSObject, but you can't use functions like perform() on such a selector, so it isn't very useful)
You don't appear to have a function named "name" in your class, of type #objc or not.

How to get a type property through a matching property of it?

I have this class:
class AClass {
var name = "Name"
var value = 0
static var A = AClass(name: "A", value: 1)
static var B = AClass(name: "B", value: 2)
}
I have a function that returns the name of A and B, how do I get A and B as AClass instances WITH string A and B, like this?
func someMethod(name: String) -> AClass
// func("A") will return A: AClass
UPDATE:
I have many type properties in my actual project, so I'm looking for a convenient way to get 'em all without having to create a value of each type property.
class AClass {
var name = "Name"
var value = 0
static var A = AClass(name: "A", value: 1)
static var B = AClass(name: "B", value: 2)
init(name:String, value:NSInteger){
self.name = name
self.value = value
}
}
Get it like this:
let aObj = AClass.A
let bObj = AClass.B
print(aObj.name)
print(bObj.name)
Try this:
class AClass
{
var name = "Name"
var value = 0
init(name : String, value : Int)
{
self.name = name
self.value = value
}
static var A = AClass(name: "A", value: 1)
static var B = AClass(name: "B", value: 2)
}
To get A and B as AClass instances use:
let objA = AClass.A
print(objA.name)
let objB = AClass.B
print(objB.name)
I guess this is what you are looking for
class AClass {
var name = "Name"
var value = 0
static var dataDict = [String: AClass]()
init(name: String) {
self.name = name
}
static func someMethod(name: String) -> AClass {
if let obj = AClass.dataDict[name] {
return obj
} else {
AClass.dataDict[name] = AClass(name: name)
return AClass.dataDict[name]!
}
}
}
Get object of AClass like:
let obj = AClass.someMethod(stringReturnValue) // AClass.someMethod("A")
// here if already AClass object exist with this key in AClass.dataDict then it will return that object else created one and store it in dataDict.

Swift 2 Correct way to get level of any object game, protocol? struct? extension?

This is my first game, and I'm new on swift and sprite kit.
I must have a level for each class that needs get level. Like car lev1 car lev 2 etc. I have read about protocol extension etc, witch is the best way to approach level management?
I have tried to use LevelTraker as extension of this protocol:
protocol LevelTracker {
typealias TypeUnit: TypeGame
var nameClass: String! {get set}
var currentLevel : Int {get set}
mutating func levelIncreases()
}
but with extension, i must write 3 var each class that needs level.
i try the same extension LevelTraker with struct LevelTraker:
func getClassName (theClass:AnyObject) -> String {
let name = _stdlib_getDemangledTypeName(theClass); return name}
protocol TypeGame {}
enum transportType : TypeGame {
case ground, sea, air
}
struct LevelTracker {
var sender: AnyObject
var TypeUnit: TypeGame
private func getSaveFileWhitName() -> String {
let saveWithName = getClassName(sender) + "." + String(TypeUnit)
return saveWithName
}
var currentLevel : Int {
get {
let stringName = getSaveFileWhitName()
let returnValue : Int = dataBase.read(stringName) as? Int ?? 1 //Check for first run of app, if = nil, set = 1
return returnValue
}
set (newValue) {
let stringName = getSaveFileWhitName()
let level : Int = self.currentLevel
let val = newValue
if (newValue > level) {dataBase.write(val, key: stringName)}
}
}
mutating func levelIncreases() {self.currentLevel++}
///SERVE SOLO PER SVILUPPO
mutating func RESETLEVEL() {dataBase.write(1, key: getSaveFileWhitName())}
}
To use: (thanks #Krzak)
class car {
init () {
let level = LevelTracker(sender: self, TypeUnit: transportType.ground).currentLevel
}
}
But I don't want modify all init object that use level, and the super super class in common, some class don't have propriety level.
The reason why you have compiler error is in your last line. You're missing the .ground
I'm not sure how you're thinking though that this will work, shouldn't it be var?
var level = LevelTracker(sender: self, TypeUnit: transportType.ground).currentLevel
What I am reading it sounds like you are doing this:
class Level : AnyObject
{
private func getSaveFileWhitName() -> String {
let saveWithName = getClassName(sender) + "." + String(TypeUnit)
return saveWithName
}
var currentLevel : Int {
get {
let stringName = getSaveFileWhitName()
let returnValue : Int = dataBase.read(stringName) as? Int ?? 1 //Check for first run of app, if = nil, set = 1
return returnValue
}
set (newValue) {
let stringName = getSaveFileWhitName()
let level : Int = self.currentLevel
let val = newValue
if (newValue > level) {dataBase.write(val, key: stringName)}
}
}
mutating func levelIncreases() {self.currentLevel++}
///SERVE SOLO PER SVILUPPO
mutating func RESETLEVEL() {dataBase.write(1, key: getSaveFileWhitName())}
}
class car : Level
{
init () {
let level = self.currentLevel
}
}
I found a solution, I'm happy to have some comment.
protocol TypeGame {}
enum transportType : TypeGame {
case car, bus, trak
}
protocol LevelTracker {
var nameClass: String! {get}
var currentLevel : Int {get set}
mutating func levelIncreases()
}
extension LevelTracker {
var currentLevel : Int {
get {/*set to DB*/ return 1}
set (newValue) {/*set to DB*/}
}
mutating func levelIncreases() {self.currentLevel++}}
A protocol only for transport object:
protocol Transport : LevelTracker {}
Ok, now my (simplified) class are:
class AllNode {//SKSpriteNode
init(){}
}
class TransportGame:AllNode, Transport {
var nameClass : String! = "Transport"
override init() {
super.init()
self.nameClass = nameClass + "." + getClassName(self)}
}
class Car : TransportGame {}
class miniCar : Car {}
class Bus: TransportGame {}
class Tree: AllNode {}
var carOne = Car()
let levelCar = carOne.currentLevel
var busOne = Bus()
let levelBue = busOne.currentLevel
var treeOne = Tree()
tree.currentLevel //ERROR YUPPI!!!! :)
Now the tree class can't access to level!
What do you think about this solution?

Resources