How to use the delegate Swift from the Objective-C? - ios

I have a viewcontroller in Swift that works well, and I would like to use it from an Objective-C class. My problem is that I don't know how to use it.
I try to add the delegate in the header of my main Objective-C class.
#interface MainViewController : UIViewController <PlanningSearchDelegate>
But I think as it is a swift class, it doesn't work. The error is:
Cannot find protocol declaration for PlanningSearchDelegate
Then, I tried to add the #objc word in the swift class.
import UIKit
#objc protocol PlanningSearchDelegate
{
func planningSearchDidSelectResult(_ result:DALSearchResult)
}
class PlanningSearchViewController: UIViewController
{
}
extension PlanningSearchViewController: UITableViewDelegate
{
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let result = _results[indexPath.row]
delegate?.planningSearchDidSelectResult(result)
}
}
But I have an error message:
Method cannot be a member of an #objc protocol because the type of the parameter cannot be represented in Objective-C.
I put the delegate = self in the prepareForSegue of the main Objective-C class without success :
else if ([segue.identifier isEqualToString:#"showSearchViewSegue"])
{
PlanningSearchViewController *searchViewController = segue.destinationViewController;
searchViewController.delegate = self;
}
The error message is:
Property 'delegate' not found on object of type "PlanningSearchViewController *'
Here is the DALSearchResult Class :
import Foundation
class DALSearchResult
{
var contactId: Int
var firstname: String
var lastname: String
var email: String
var phone: String
var city: String
var registrationId: Int?
var slotId: Int?
var vehicleId: Int?
var startDate: Date?
var vehicleName: String?
init(contactId:Int, firstname:String, lastname:String, email:String, phone:String, city:String)
{
self.contactId = contactId
self.firstname = firstname
self.lastname = lastname
self.email = email
self.phone = phone
self.city = city
}
convenience init(registrationId:Int, slotId:Int, vehicleId:Int, contactId:Int, firstname:String, lastname:String, email:String, phone:String, city:String, startDate:Date, vehicleName: String)
{
self.init(contactId: contactId, firstname: firstname, lastname: lastname, email: email, phone: phone, city: city)
self.registrationId = registrationId
self.vehicleId = vehicleId
self.slotId = slotId
self.startDate = startDate
self.vehicleName = vehicleName
}
}
Anyone has an idea ?
Thanks in advance.

Make DALSearchResult class Objective-C compatible. If your DALSearchResult does not extend from NSObject, you can extend it form NSObject.

Can you share how the declaration of DALSearchResult looks like? Maybe it's an enum which cannot be translated to Obj-C. In this case you might need to pass the result in a different way.

To access swift from objective-C you have to import the swift.h always in your class that you want to use it like so
#import "Yourprojectname-Swift.h"

Related

How do I implement abstract methods with different parameters/return types

I have parent class called "Item", and child class called "YTListItem". I want to have a functions called instantiate() which will be implemented in each child class, and return a view controller. The type of the view controller will be different depending on which child class is calling the instantiate() method. My issue is that swift does not seem to recognize me overriding the function if it has different parameters or return types.
The error occurs when I override the function, I get the error "Method does not override any method from its superclass".
class Item {
var name: String
var description: String
init(name: String = "Test text", description: String = "Test description of the item") {
self.name = name
self.description = description
}
func instantiate() {}
}
class YTListItem: Item {
var address: String
init(name: String = "Test text", description: String = "Test text", address: String = "SivTGfXxYz0") {
self.address = address
super.init(name: name, description: description)
}
override func instantiate(storyboard: UIStoryboard) -> YTDescViewController? {
let vc = storyboard.instantiateViewController(identifier: "desc") as? YTDescViewController
return vc
}
}
Is there a way to do this? I've seen mentions of protocols when searching how to make it work but I'm new to swift so I'm hoping to be able to get through it using methods I've already learned.
First of all I don't think you should be instantiating a ViewController from you model class. Instead you should be injecting your model to the ViewController. But for your particular scenario you can just return a UIViewController from instantiate function rather than it's subclass (YTDescViewController). And I think you should use protocols for your scenario something like this:
protocol Item {
var name: String {get set}
var description: String {get set}
var storyboard : UIStoryboard {get set}
func instatntiate() -> UIViewController
}
extension Item {
var viewControllerID : String {
return "desc"
}
}
struct YTListItem: Item {
var name: String
var description: String
var storyboard: UIStoryboard
func instatntiate() -> UIViewController {
return storyboard.instantiateViewController(identifier: viewControllerID)
}
}
You can also use associatedType to customize the return type of instantiate (or the parameters) in Item protocol. But in that case you would need to implement type erasures to hold generic reference to class/struct objects that implement Item protocol.

Calling setValuesForKeys fails in my Swift 4 code

I'm having this problem, im trying to retrieve data from the firebase database, but it's saying the profilepic isn't a key, but it is. This is the object class.
class User: NSObject {
var firstname: String?
var lastname: String?
var username: String?
var profilepic: String?
}
and this is me trying to retrieve
func getusers(){
ref.child("Friends").child(currentuser!).observe(.childAdded, with: { (snapshot) in
print(snapshot)
if let dic = snapshot.value as? [String: AnyObject]{
let user = User()
user.setValuesForKeys(dic)
print(user.firstname, user.lastname)
DispatchQueue.main.async {
self.tableview.reloadData()
}}
}) { (error) in
print(error.localizedDescription)
}
}
and the crash is here user.setValuesForKeys(dic).
Anyone has any idea why isn't working?
Try this instead:
#objcMembers
class User: NSObject {
...
}
The setValuesForKeys API is implemented by the Foundation framework and requires Objective-C compatibility.
The rules for exposing Swift code to Objective-C have changed considerably in Swift 4. Please check the evolution proposal for further information.
User class design. If any of the four properties can be missing from Firebase than your class design might be a good fit. Otherwise, consider declaring the fixed properties as non-optional and creating an initializer instead.
Change your User declaration to this:
class User: NSObject {
#objc var firstname: String?
#objc var lastname: String?
#objc var username: String?
#objc var profilepic: String?
}
In Swift 4, Objective-C cannot see your instance properties unless you expose them explicitly.

Swift: Using Protocols to create private class instance

I am really new to Swift, and trying to understand how to work things out with protocol extensions. So here is my protocol:
public protocol User: class {
var name : String {get}
}
private class MyUser: User {
var name : String
init(name: String) {
self.name = name
}
}
extension User where Self:User {
func createUser(name: String) -> User {
return MyUser(name)
}
}
How do I call this function createUser from a totally different class/protocol, where I want to create an instance of User?
You could remake the function in whatever class you need it for
func createUser(name: String) -> User {
return MyUser(name)
}
then say
let newUser = createUser("WhateverName")
or you could do:
let newUser = User().createUser("WhateverName")

How to use struct in custom framework in ios/swift?

I need to use struct in my custom framework, how can the following be done?
Here my framework:
MyFramework.framework
public class SomeClass : NSObject {
public struct myDetails {
public var firstName: String?
public var lastName: String?
public init(fName: String? LastName lName: String?) {
self.firstName = fName
self.lastName = lName
}//init end
}// struct end
public func fillStruct(inout myStruct: myDetails) {
myStruct.firstName = "John"
myStruct.lastName = "Devid"
}
}// class end
Here's my Application:
// ViewController.swift
import MyFramework
var refObj: SomeClass?
override func ViewDidLoad() {
refObj = SomeClass()
let tempStruct = refObj.myDetails(fName: nil LastName lName: nil) // I CANT ABLE ACCESS LIKE THIS.
refObj.fillStruct(&tempStruct)
}
What I want, is my application to send the data to the struct and my framework to fill the struct and finish the function.
How can this be achieved?

Class as function parameter in Swift

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)

Resources