Swift.... Class method vs. Instance method - swift

Thanks in advance for help!!
I'm trying to call a func from within my Class and I keep getting an error saying that:
Missing parameter for argument #1.............Read a few posts saying it's an instance vs class problem? I don't get it..I'm calling the method from within the Class??? There has to be an instance of the class if the method is being called????? right? Here is my code...Thanks
import Foundation
import Parse
class TestViewController {
let photos = getWallImages() //-----This is the line requesting an argument
func getWallImages() -> [WallPost] {
let query = WallPost.query()!
query.findObjectsInBackgroundWithBlock { objects, error in
if error == nil {
if let objects = objects as? [WallPost] {
return objects
println("We have \(objects.count)")
}
} else if let error = error {
println(error)
}
}
}
}

So the "crime" you are committing is the fact that the method is applied in an instance of the class and not as a class method. The function is expecting a self parameter (a reference to the instance). That explains the error message.
Now to fix that you have two quick options:
1. Make it a class function and call it that way too:
class TestViewController {
let photos = TestViewController.getWallImages()
class func getWallImages() -> [WallPost] {
// mumbo jumbo
}
}
This approach is problematic in case you would want to do some instance specific operations, because class func is static method and doesn't provide you with some of the object benefits.
2. Instantiate the object you are calling the method on:
class TestViewController {
let photos = TestViewController().getWallImages()
func getWallImages() -> [WallPost] {
// mumbo jumbo
}
}
This approach isn't correct with your given structure - it doesn't make sense to instantiate another view controller, but if you take the method and put it in a separate class, maybe it would then make sense.
Then of course you have multiple other ways of changing your code to make it work. Maybe you could initialize it with lazy parameter, maybe you could initialize it in the init method. Whatever suits you best. My answer is simply explaining where you've gone wrong.

There are a few ways you can set your property appropriately. You can make getWallImages() a type method:
class TestViewController {
let photos = TestViewController.getWallImages()
class func getWallImages() -> [WallPost] {
....
}
}
Or, you can keep your method an instance method and set your property upon initialization:
class TestViewController {
let photos: [WallPost]!
init() {
super.init()
photos = getWallImages()
}
func getWallImages() -> [WallPost] {
....
}
}

If you're asking a question you should reduce your code to a minimum, discarding unnecessary details.
You probably want something like this:
class MyClass {
let x = MyClass.getStuff()
static func getStuff() -> Int {
return 0
}
}
However your method getWallImages() can't do something like this, because it's returning the result asynchronous, which means you get the result much later after the function has returned.
You could do something like this though (this is how I'd be doing it):
class MyClass {
var x : Int? {
didSet {
if let x = x {
// Do something with x, here it's assigned
} else {
// x was set to nil, something failed
}
}
}
init() {
getStuffAsynchronous()
}
func getStuffAsynchronous() {
// Do your query stuff here, assign x to your objects to invoke the didSet
x = 0
// If it fails somehow, assign set x to nil
// if fail {
// x = nil
// }
}
}

Related

Testing Delegation in Playground giving 'nil'

I have the following code in Playground -I'm learning delegation-...
import UIKit
protocol FollowThisProtocol {
func passingTheValue(aValue: String)
}
class IPassTheValues{
var aDelegate: FollowThisProtocol!
func runThisFunc(){
aDelegate.passingTheValue(aValue: "I like this game")
}
}
class IReceiveTheValues: FollowThisProtocol{
var localString: String!
var instanceOfClass: IPassTheValues!
func runReceivefunc(){
instanceOfClass.aDelegate = self
}
func passingTheValue(aValue: String) {
localString = aValue
}
}
When I attempt to
print(IReceiveTheValues().localString)
it's giving me nil
It also gives me nil if I run the following lines before attempting to print(IReceiveTheValues().localString)...
IPassTheValues()
IReceiveTheValues()
could you please help me understand why the value is not being passed from the 1st class to the 2nd..?
Or if you can spot something in my code that is contradicting itself, could you please point it out..?
Appreciate your time and help.
You need to create the IPassTheValues object before assigning yourself as the delegate, and then call runThisFunc() on the instance:
func runReceivefunc(){
instanceOfClass = IPassTheValues()
instanceOfClass.aDelegate = self
instanceOfClass.runThisFunc()
}
Then test:
// Create the `IReceiveTheValues` object
let irtv = IReceiveTheValues()
// Run the method
irtv.runReceivefunc()
// Get the resulting string
print(irtv.localString)
I suggest 2 other changes. Make your delegate weak so that you don't get a retain cycle which makes it impossible to delete either object. In order to do that, you will need to add : class to your protocol declaration because only reference objects (instances of a class) can be weak.
Here's the modified code. Try it and see what happens when you delete weak.
protocol FollowThisProtocol: class {
func passingTheValue(aValue: String)
}
class IPassTheValues{
weak var aDelegate: FollowThisProtocol!
func runThisFunc(){
print("Calling delegate...")
aDelegate.passingTheValue(aValue: "I like this game")
}
deinit {
print("IPassTheValues deinitialized")
}
}
class IReceiveTheValues: FollowThisProtocol{
var localString: String!
var instanceOfClass: IPassTheValues!
func runReceivefunc(){
instanceOfClass = IPassTheValues()
instanceOfClass.aDelegate = self
instanceOfClass.runThisFunc()
}
func passingTheValue(aValue: String) {
print("Receiving value from helper object...")
localString = aValue
}
deinit {
print("IReceiveTheValues deinitialized")
}
}
func test() {
let irtv = IReceiveTheValues()
irtv.runReceivefunc()
print(irtv.localString)
}
test()

Swift 3: Any way to declare a static class function to restrict closure type to Self?

I'm trying to create a static method on a generic class which takes in a closure as parameter and creates an instance of the class and passes it the closure. The catch is that I want to subclass this and ensure that the closure conforms to any subclass I use.
I know that you can use "Self" as a return type for a static method, but when I try to use it in the method header, I get the following error:
"'Self' is only available in a protocol or as the result of a method
in a class"
I'd like to do something like this:
class GenericClass: NSObject {
required override init() {
super.init()
}
static func createAndExecuteAsync(block: (Self) -> Void) {
DispatchQueue.global().async {
let instance = self.init()
block(instance)
}
}
}
class OtherClass: GenericClass {
// ...
}
Somewhere else...
OtherClass.createAndExecuteAsync { (instance: OtherClass) in
// Do stuff to instance
}
UPDATE:
Thanks to Hamish's solution in this post, I'm closer to a solution. I can use Self in the desired way if I first create a protocol for my generic class. However that forces me to make OtherClass final, which isn't desirable for my situation.
Without making OtherClass final, I get the following error:
Protocol 'GenericClass' requirement 'createAndExecuteAsync(block:)'
cannot be satisfied by a non-final class ('OtherClass') because it
uses 'Self' in a non-parameter, non-result type position.
Here's what it would look like:
protocol GenericClass {
init()
static func createAndExecuteAsync(block: #escaping (Self) -> Void)
}
extension GenericClass {
static func createAndExecuteAsync(block: #escaping (Self) -> Void) {
DispatchQueue.global().async {
let instance = self.init()
block(instance)
}
}
}
final class OtherClass : GenericClass {
var myProperty = 1
required init() { }
}
// Somewhere else...
OtherClass.createAndExecuteAsync { (instance) in
instance.myProperty = 2
}
Perhaps you could use a global generic function with a slightly different usage syntax.
for example:
func createAndExecuteAsync<T:GenericClass>(_ objectType:T.Type, _ block:#escaping (T) -> Void)
{
DispatchQueue.global().async
{
let instance = T.init()
block(instance)
}
}
createAndExecuteAsync(OtherClass.self){ $0.myProperty = 2 }
// instead of OtherClass.createAndExecuteAsync{ $0.myProperty = 2 }

Calling a function/passing data from outside a TableViewController (and others) in Swift

In my app I have one screen divided between two ViewControllers - LadderViewController and GameHistoryTableViewController, which lies in a container. I want user to be able to filter the data in the table by tapping on something in the LadderView. I tried to solve this using delegates:
LadderViewController:
delegate = GameHistoryTableViewController()
func imageTapped(imageIndex: Int) {
delegate?.selectedHeroNumber(imageIndex)
}
GameHistoryTableViewController: (conforms to the delegate protocol and implemets a function from it)
func selectedHeroNumber(heroNumber: Int) {
let filteredGames = filterGamesFromHeroNumber(heroNumber)
tableDataSource = filteredGames
self.tableView.reloadData()
}
That doesn't work, though, because the delegate I declare in LadderViewConroller is another instance of GameHistoryTableViewController, not the (to the user) shown one. I don't know how to access the "visible" instance (table) of GameHistoryTableViewController though... So, how should be delegating used here? Or should I use another approach (and if so, what kind)? I basically need to change the table's data source according to on what the user taps, one can say "from outside" (dataSource is a property in my GameHistoryTableViewController class).
Here is an example with delegation like you want to do. It's a better solution than singleton in this case ;)
declare a new protocol call HeroInfo:
protocol HeroInfo: class {
func selectedHeroNumber(heroNumber: Int);
}
LadderViewController:
//create the delegation
weak var delegate:HeroInfo?
func imageTapped(imageIndex: Int) {
//call the delegate method
delegate?.selectedHeroNumber(imageIndex)
}
GameHistoryTableViewController:
// Here get the protocol HeroInfo inheritance
class userTableViewController: UITableViewController, HeroInfo {
override func viewDidLoad() {
super.viewDidLoad()
//Here get your Ladder view in a splitView
if let split = self.splitViewController {
let controllers = split.viewControllers
self.ladderViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? ladderViewController
//register it to delegate
self.ladderViewController?.delegate = self
}
}
...
// Here is your method of your protocol that you must conform to
func selectedHeroNumber(heroNumber: Int) {
let filteredGames = filterGamesFromHeroNumber(heroNumber)
tableDataSource = filteredGames
self.tableView.reloadData()
}
...
}
There are a few ways to achieve this, I have a similar setup for which I use a model class with a singleton to store the relevant data.
For instance you could have the following
class dataModel {
static let sharedInstance = dataModel()
private var _heroNumber = Int()
private init() {}
var heroNumber: Int = {
return _heroNumber
}
func setHero(hero: Int) -> Int {
return _heroNumber
}
}
}
You can then can access this model from each of your controllers using dataModel.sharedInstance.heroNumber etc...

How do I share variables inside a singleton class

I am trying to create a common class for storing and retrieving data in Parse. I made the ParseProcessing class a singleton class. From my main View Controller I load the data and store it into a dictionary in the ParseProcessing. I do this by creating a shared instance of the ParseProcessing class. From another view controller I try to access the data from the dictionary. I assumed that because ParseProcessing is a singleton class that I have a single copy of the dictionary. This does not appear to be correct. How should I declare the variables inside the ParseProcessing so that they are shared? The code is shown below:
import UIKit
var gSep = ","
class QwikFileViewController: UIViewController {
var loadData = ParseProcessing.sharedInstance
override func viewDidLoad() {
super.viewDidLoad()
// load data from Parse
loadData.loadCategorySubcategoryData()
loadData.loadRecordsFromParse()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
ParseProcessing Singleton Class
import UIKit
import Parse
class ParseProcessing: Parse {
var dictMenuList = [String:String]()
var noteTitle = [String]()
var notes = [String]()
var thumbnailFiles = [PFFile]()
var objectIds = [String]()
var noteImage = UIImage()
class var sharedInstance:ParseProcessing {
struct singleton {
static let instance:ParseProcessing = ParseProcessing()
}
return singleton.instance
}
// Load Category/Subcategory data from Parse Data Base
func loadRecordsFromParse () -> Bool{
var tmpFile = [PFFile]()
var loadComplete = false
var query = PFQuery(className:"Record")
query.findObjectsInBackgroundWithBlock {
(objects, error) -> Void in
if error == nil {
// The find succeeded.
println("Successfully retrieved \(objects!.count) items.")
for object in objects! {
self.noteTitle.append(object["title"] as! String)
self.notes.append(object["notes"] as! String)
self.thumbnailFiles.append(object["thumbnail"] as! PFFile)
self.objectIds.append(String(stringInterpolationSegment: object.objectId))
}
} else {
println("\(error)")
}
loadComplete = true
}
return loadComplete
}
// Load Category/Subcategory data from Parse Data Base
func loadCategorySubcategoryData () // -> Dictionary <String,String>
{
var success : Bool = false
var d : Dictionary <String,String> = ["":""]
var menu = PFQuery(className: "Classification")
println("ParseProcessing: loadCategory...")
menu.findObjectsInBackgroundWithBlock {
(objects, error) -> Void in
if error == nil {
var category = ""
var subcategory = ""
for object in objects! {
category = object["category"] as! String
println("ParseProcessing: category = \(category)")
subcategory = object["subcategory"] as! String
println("ParseProcessing: subcategory = \(subcategory)")
d[category] = subcategory
}
success = true
self.dictMenuList = d
return
} else {
println("ParseProcessing: error = \(error)")
success = false
}
}
return
}
}
Another View Controller to examine the data
import UIKit
class TestViewController: UIViewController {
var dictMenuList = [String:String]()
var loadData = ParseProcessing.sharedInstance
override func viewDidLoad() {
super.viewDidLoad()
dictMenuList = loadData.dictMenuList
println("dictMenuList: \(dictMenuList)")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
The problem is that findObjectsInBackgroundWithBlock is asynchronous method (i.e. it returns immediately but the closure is called later when the query is done). So you cannot return loadComplete in loadRecordsFromParse, for example. This background request will almost certainly never be done by the time loadRecordsFromParse returns.
Instead, you probably want to adopt the completionHandler pattern. For example, this sample loadRecords doesn't try to return anything immediately, but rather will call the completionHandler when the request is done.
func loadRecords(completionHandler:([SomeObject]?, NSError?) -> ()) {
let query = PFQuery(className: "SomeClass")
query.findObjectsInBackgroundWithBlock { objects, error in
// build some model object
completionHandler(objectArray, error)
}
}
And you'd call it like so:
loadData.loadRecords() { objects, error in
// use `objects` (and make sure `error` is `nil`) here
}
// but do not use those variables here, as the above closure probably has not run yet!
Frankly, I'd be inclined to get rid of those properties in your singleton altogether. When you're dealing with asynchronous code, to have public properties that are updated asynchronously is going to be a source of heartache. You can do it, but it wouldn't be my first choice.
For example, when TestViewController is presented, you cannot assume that the asynchronous fetch associated with dictMenuList is done yet. I look at this and wonder if it makes sense for TestViewController to initiate the fetch itself and then use dictMenuList in the completion handler. That's going to be easiest.
If you must initiate the asynchronous request from one view controller and then have another view controller be informed when that asynchronous request is done, then you might have to use some other pattern, such as notifications (e.g. use NSNotificationCenter, and have the singleton post notifications when the various requests are done, and then any view controller that needs to be informed of this fact can add themselves as observers for that notification).

Swift - Generic Functions

The Goal
I want to call the instantiateViewControllerWithIdentifier method on a Storyboard to get a view controller. But I want to do it with generics for code reuse and simplicity.
The Non-Compiling Code
let viewController = StoryboardHelper.viewControllerFromStoryboard<ChooseProviderViewController>()
class func viewControllerFromStoryboard<T>() -> T {
let storyboard = mainStoryboard()
let viewController = storyboard.instantiateViewControllerWithIdentifier(resolveViewController(T)) as T
return viewController
}
private class func resolveViewController<T>() -> String {
if T is ChooseProviderViewController {
return chooseProviderViewControllerIdentifier;
}
return ""
}
Now, the above code is what I have at the moment, and how I would like the API to be. It would be nice to say "StoryboardHelper, here is the type of the view controller I want, go get the view controller instance for me".
So, in the end, I would like some way to do this:
let instanceOfXViewController = StoryboardHelper.viewControllerFromStoryboard<XViewController>()
let instanceOfYViewController = StoryboardHelper.viewControllerFromStoryboard<YViewController>()
I have a answer for you but it will only work with Swift 1.2 (+), in 1.1 it will return a intance of the wrong (super) type. I changed it to a more general situation/naming but it is effectly the same problem. First since you only want to manage UIViewControllers you should restrict T. Like <T:UIViewController> . Secondly you should/can pass the Type as an argument and create an instance of it.
import Foundation
class Helper {
class func instanceFromT<T:R>(T.Type) -> T {
return T.self()
}
}
class R {
required init () {
}
func me() -> String {
return "me is R"
}
}
class B : R {
override func me() -> String {
return "me is B"
}
}
class A : R {
override func me() -> String {
return "me is A"
}
}
let my = Helper.instanceFromT(A.self)
println(my.me()) // "me is A"