Call Function of custom Swift Framework - ios

I'm trying to create a simple framework that has a function that returns "hello name" name being a passed argument. Below is the framework and code trying to call it.
Framework:
public class Greeter {
public init () {}
public static func greet(name: String) -> String {
return "Hello /(name)."
}
}
Code:
import Greeter
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let greetingString: String = Greeter.greet("Bob")
print(greetingString)
}
}
When I try typing out "greet("Bob")", what autocompletes is "(name: String) -> String greet(self: Greeter)". And when I manually type "greet("Bob")", I get the error: Instance member 'greet' cannot be used on type 'Greeter'; did you mean to use a value of this type instead?

You need to create an instance of Greeter class first and then call it's method.
let greeter = Greeter()
let greetingString: String = greeter.greet(name: "Bob")
print(greetingString)
Update: You don't need : String it's redundant here. So you can modify that line to:
let greetingString = greeter.greet(name: "Bob")

Related

Swift - Passing custom objects as a parameter

I started learning Swift today and in my first test app I am getting this error:
TestClass is not convertible to AnotherClass
The following is the TestClass:
class TestClass : NSObject {
var parameter1 : String = ""
var parameter2 : String = ""
override init() {
super.init()
}
func createJob(parameter1: String, parameter2: String) -> TestClass {
self.parameter1 = parameter1
self.parameter2 = parameter2
return self;
}
}
And this is the AnotherClass:
class AnotherClass: NSObject {
private struct internalConstants {
static let test1 = "testData"
static let test2 = "testData2"
}
var current : String
override init() {
self.current = internalConstants.test1
super.init()
}
func executeTask(testClass : TestClass) {
if testClass.parameter1 == "abc" {
return;
}
}
}
And this is the ViewController where I am getting the compiler error:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let obj = TestClass()
AnotherClass.executeTask(obj)
}
}
AnotherClass.executeTask line is giving the compiler error.
The obj variable sent as a parameter on this line is highlighted by Xcode with the error
"TestClass is not convertible to AnotherClass".
In C# or Objective C it is allowed to pass custom objects as a parameter to another methods. How can I do it in Swift?
Let's correct first the TestClass. This is how you should init a class like that:
class TestClass : NSObject {
....
init(parameter1: String, parameter2: String) {
....
}
}
Much simpler. Now, going back to your problem,
"TestClass is not convertible to AnotherClass".
Take a look at it again. The line you've mentioned in your question. You are trying to do this:
let obj = TestClass()
AnotherClass.executeTask(obj)
This line, AnotherClass.executeTask(obj), is giving you an error because indeed executeTask() is an instance method. You could do three ways for that.
add static keyword to the func executeTask... So it becomes like this: static func executeTask(testClass : TestClass) {
Instead of static keyword, you could add class. It becomes like so: class func executeTask(....
OR, better if you just instantiate the AnotherClass. Make a new object of AnotherClass. How to instantiate? You tell me. But here:
let anotherClass = AnotherClass()
Either implement executeTask as a class function
class func executeTask(testClass : TestClass) {
if testClass.parameter1 == "abc" {
return;
}
}
or instantiate AnotherClass in vieweDidLoad
let obj = TestClass()
let another = AnotherClass()
another.executeTask(testClass: obj)
Note the slightly different call to executeTask with the argument name.
And there is really no reason for you to subclass NSObject as I see it.
I think it's best to keep is simple. Create an instance of AnotherClass inside of ViewController.
class ViewController: UIViewController {
// Create an instance of AnotherClass which lives with ViewController.
var anotherClass = AnotherClass()
override func viewDidLoad() {
super.viewDidLoad()
let obj = TestClass()
// Use the instance of AnotherClass to call the method.
anotherClass.executeTask(testClass: obj)
}
}

How to use custom initializer on an Realm object inside a class with generic type?

I have a class called ObjectManager which has generic type O: Object, Persistable. This way I can have one class that can operate with multiple different subclasses of realm Object. But the problem is in the last line cache = O(message: "hello world") the error is: Incorrect argument label in call (have 'message:', expected 'value:')
When typing it suggests me that I can use initializer of Persistable protocol, but complain during the compiling, that it expect an initializer from Object class. Is it possible to cast Persistable initializer?
protocol Persistable {
init(message: String)
}
class CustomObject: Object, Persistable {
dynamic var message: String = ""
required convenience init(message: String) {
self.init()
self.message = message
}
}
class ObjectManager<O>: NSObject where O: Object, O: Persistable {
var cache: O?
func didReceive(message: String) {
cache = O(message: "hello world")
}
}
If you make your CustomObject class final, and replace your initializer with a factory method, you will get code which does what you want. Unfortunately, the Swift compiler error messages are so cryptic in this case as to be completely unhelpful.
protocol Persistable {
static func factory(message: String) -> Self
}
final class CustomObject: Object, Persistable {
dynamic var message: String = ""
static func factory(message: String) -> CustomObject {
let x = CustomObject()
x.message = message
return x
}
}
class ObjectManager<O>: NSObject where O: Object, O: Persistable {
var cache: O?
func didReceive(message: String) {
cache = O.factory(message: "hello world")
}
}

Get Swift class name in "class func" method

I have a static method in Swift
class BaseAsyncTask: WebServiceClient {
class func execute(content : [String:AnyObject], cancelled:CustomBool)
{
// Print class name (BaseAsyncTask) here
}
}
And I want to know how to get the class name inside that method. I tried
self.dynamicType
but that gives error (I suppose because of the self inside a class function)
There are different methods to do that, if your method inherits from NSObject you can expose it to objective-c and do something like that.
#objc(BaseAsyncTask)
class BaseAsyncTask: WebServiceClient {
class func execute(content : [String:AnyObject], cancelled:CustomBool)
{
println("Class \(NSStringFromClass(self))")
}
}
For pure SWIFT introspection check here about MirrorType
I've found also this extension credits to ImpactZero
public extension NSObject{
public class var nameOfClass: String{
return NSStringFromClass(self).components(separatedBy: ".").last!
}
public var nameOfClass: String{
return NSStringFromClass(type(of: self)).components(separatedBy: ".").last!
}
}
[Xcode 8]
Alex suggested me that in the Xcode 8 version this code shows a warning. To avoid that we should prefix the method like that:
#nonobjc class var className: String{
return NSStringFromClass(self).components(separatedBy: ".").last!
}
You can use string interpolation to print self:
let className = "\(self)"
Sample code:
class BaseAsyncTask: WebServiceClient {
class func execute(content : [String:AnyObject], cancelled: CustomBool)
{
let className = "\(self)"
print(className)
}
}
class AnotherAsyncTask : BaseAsyncTask {
}
BaseAsyncTask.execute([:], cancelled: true) // prints "BaseAsyncTask"
AnotherAsyncTask.execute([:], cancelled: true) // prints "AnotherAsyncTask"
Another way to do this, when you don't have an instance of the class is this.
Swift 4
print(String(describing:BaseAsyncTask.self))
Swift 2
print(String(BaseAsyncTask))
Inspired here.
Get class name of object as string in Swift

Swift nested class as mocks

I would like to use nested classes in Swift for mocking purposes. Imagine bar() method of following Foo class is under the test:
class Foo: NSObject {
func baz() -> String {
return "baz"
}
func bar() -> String {
return self.baz().stringByReplacingOccurrencesOfString("z", withString: "r")
}
}
I want to mock baz() method and verify that bar() depends on it with following test:
class FooTests: XCTestCase {
func testBar() {
class FooMock: Foo {
override func baz() -> String {
return "zzz"
}
}
let mock = FooMock()
let result = mock.bar()
XCTAssertEqual("rrr", result)
}
}
I have Foo class added to both application and test targets to bypass access modifiers issue with test target.
The application fails to compile with below error:
Global is external, but doesn't have external or weak linkage!
%4* (%0*, i8*)* #_TToFCFC13TestTestTests8FooTests7testBarFS0_FT_T_L_7FooMock3bazfS1_FT_SS
invalid linkage type for function declaration
%4* (%0*, i8*)* #_TToFCFC13TestTestTests8FooTests7testBarFS0_FT_T_L_7FooMock3bazfS1_FT_SS
LLVM ERROR: Broken module found, compilation aborted!
After moving FooMock to separate source file it compiles and works just fine.
When using nested class to mock any methods from iOS standard frameworks it works just fine:
func testMockDefaults() {
class NSUserDefaultsMock: NSUserDefaults {
override func objectForKey(defaultName: String) -> AnyObject? {
return "Super secret!"
}
}
let defaults = NSUserDefaultsMock(suiteName: "SuiteName")!
defaults.setObject("Test", forKey: "Test")
let result = defaults.objectForKey("Test") as String
XCTAssertEqual("Super secret!", result)
}
Could you please explain me what am I missing and what is the reason behind this?

Missing argument for parameter #1 in call error for function with no params. Swift

I am using xcode 6 beta 6 and I get this weird error for a function that has no params.
Here is the function
func allStudents ()-> [String]{
var appDel:AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
var context:NSManagedObjectContext = appDel.managedObjectContext!
var request = NSFetchRequest(entityName: "Student")
request.returnsObjectsAsFaults = false
//Set error to nil for now
//TODO: Give an actual error.
var result:NSArray = context.executeFetchRequest(request, error: nil)
var students:[String]!
for child in result{
var fullname:String = child.valueForKey("firstName") as String + " "
fullname += child.valueForKey("middleName") as String + " "
fullname += child.valueForKey("lastName") as String
students.append(fullname)
}
return students
}
and here is the call
var all = StudentList.allStudents()
Is this a bug or am I doing something wrong here?
Assuming StudentList is a class, i.e.
class StudentList {
func allStudents ()-> [String]{
....
}
}
Then an expression like this
var all = StudentList.allStudents()
will throw the said exception, because allStudents is applied to a class instead of an instance of the class. The allStudents function is expecting a self parameter (a reference to the instance). It explains the error message.
This will be resolved if you do
var all = StudentList().allStudents()
Swift has Instance Methods and Type Methods. An instance method is a method that is called from a particular instance of a class. A Type Method is a static method that is called from the class itself.
Instance Methods
An instance method would look something like this:
class StudentList {
func allStudents() -> [String] {
....
}
}
In order for the allStudents method to be called, the StudentsList class needs to be initialized first.
let list = StudentsList() // initialize the class
let all = list.allStudents() // call a method on the class instance
Trying to call an instance method on the class itself gives an error.
Type Methods
Type Methods are static methods that belong to the class, not an instance of the class. As was alluded to in the comments to #AnthodyKong's answer, a Type Method can be created by using the class or static keywords before func. Classes are passed by reference and Structs are passed by value, so these are known as reference type and value type. Here are what they would look like:
Reference Type
class StudentList {
class func allStudents() -> [String] {
....
}
}
Value Type
struct StudentList {
static func allStudents() -> [String] {
....
}
}
Call with
let all = StudentList.allStudents()
Because allStudents is a Type Method, the class (or struct) doesn't need to be initialized first.
See also
Method documentation
Instance Methods and Type Methods in Swift

Resources