TSTableView swift - "Unrecognized selector sent to instance XXXX" - ios

I am trying to set up a multi column table inside a Swift application using the library written in Obj C called TSUIKit which defines its own table TSTableView.
I have added the files to my project and to my bridging header and xcode recognizes correctly the classes...
Every time I execute the code, the tables shows the rows and columns correctly but when I touch any cell, an error appears which says the following:
2014-11-05 09:39:54.811 probarTabla[1584:20072] -[TSTableView numberOfColumns]: unrecognized selector sent to instance 0x7ffbc3654920
2014-11-05 09:39:54.937 probarTabla[1584:20072] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[TSTableView numberOfColumns]: unrecognized selector sent to instance 0x7ffbc3654920'
*** First throw call stack:
Here is the code in the controller of the view, the test project only has a unique view with a TSTableView added which corresponds with "tabla" in the code of the ViewController
#import <Foundation/Foundation.h>
#import "TSTableView.h"
#import "TSTableViewDelegate.h"
#import "TSTableViewDataSource.h"
#import "TSTableViewHeaderSectionView.h"
#import "TSTableViewModel.h"
ViewController code:
import UIKit
class ViewController: UIViewController, TSTableViewDelegate {
#IBOutlet var tabla: TSTableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tabla.delegate = self
tabla.autoresizingMask = UIViewAutoresizing.FlexibleBottomMargin | UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight
var pruebaColumna : NSArray = [
["title" : "Probando Columna 1"],
["title" : "Probando Columna 2"],
["title" : "Probando Columna 3"]
]
var model : TSTableViewModel = TSTableViewModel(tableView: tabla, andStyle: kTSTableViewStyleDark)
var pruebaFila : NSArray = [
["cells" : [
["value": "valor1"],
["value": "valor2"],
["value": "valor3"]
]
]
]
model.setColumns(pruebaColumna, andRows: pruebaFila)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: TSTableView!, didSelectRowAtPath rowPath: NSIndexPath!, selectedCell cellIndex: Int) {
println("Has hecho click en la celda")
}
}
Thanks in advance

It is important you keep a strong refererence to your model, as this is the datasource.
Once you keep a strong reference to it, your problem will be solved.

Related

"No visible #interface for 'MySwiftFile' declares the selector '****'" in iOS framework

I've been having trouble with using Swift in an ObjC framework in iOS. My framework has Objective-C code, which I want to call Swift code from.
I think I have created the bridging properly, I'll show below what I've done.
MySwiftFile.swift :
open class MySwiftFile: NSObject {
var varDummy : RandomType? = nil
open func setupDummy(param1 : RandomType1) {
varDummy = RandomType(p: param1)
}
}
MyObjCFile.m :
#class MySwiftFile;
#import "MyFramework/MyFramework-Swift.h"
#interface A : NSObject<...>
#property(atomic) MySwiftFile *mySwiftFile;
.....
#end
#implementation Aclass
......
#end
#interface B ()
....
#property(readonly, nonatomic) A *refA;
#end
#implementation B
....
- (void)methodCalledSomewhere:(RandomType1 *)type {
....
refA.mySwiftFile = [[MySwiftFile alloc] init];
[refA.mySwiftFile setupDummy: type]; <====THIS LINE PRODUCES THE ERROR
}
....
To sum it up, I want to init the property and call a function of a Swift object from ObjC code. Xcode seems to recognize MySwiftFile as a valid type, then how come it does not allow me to call the "setupDummy" method?
The errors are 2:
No visible #interface for 'MySwiftFile' declares the selector 'setupDummy:'
No visible #interface for 'MySwiftFile' declares the selector 'setupDummy'
First problem is that you forget to expose it to the Objective-C. Either add #objcMembers to expose everything ...
#objcMembers
open class MySwiftFile: NSObject {
...
}
... or just add #objc to your setupDummy function ...
#objc
open func setupDummy(param1: String) {
...
}
Second problem is about how the function name is translated to Objective-C ...
#objc func setupDummy(param1 : RandomType1) -> setupDummyWithParam1:
#objc func setupDummy(_ param1: RandomType1) -> setupDummy:
#objc(setupDummy:) func setupDummy(param1: String) -> setupDummy:
... which means that adding just #objc wont work. You have to either change the Swift function signature or use setupDummyWithParam1: in your Objective-C or keep the Swift function signature & use #objc(<name>) to change the Objective-C selector.

Swift CocoaPods Library in Objective-C Project

I have found several online resources on how to include an Objective-C library into a Swift project and a few limited resources on how to do the reverse (which is what I'm after).
I have managed to get my project to compile and run based on the work I did here in this question: Swift CocoaPod Library in Objective-C Project Migration from Swift 3 to 4/5
However whenever I try to access anything from the Swift library in my ObjC project my app crashes with the following...
2020-01-29 14:42:09.756352-0700 Hyperion[13547:2723315] -[HGCircularSlider.RangeCircularSlider setStartPointValue:]: unrecognized selector sent to instance 0x1074088c0
2020-01-29 14:42:09.763045-0700 Hyperion[13547:2723315] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[HGCircularSlider.RangeCircularSlider setStartPointValue:]: unrecognized selector sent to instance 0x1074088c0'
*** First throw call stack:
(0x18e32ea48 0x18e055fa4 0x18e2325a8 0x1923cf86c 0x18e332af4 0x18e334a7c 0x10208f554 0x10208d4d4 0x192d15dec 0x192be580c 0x10208d388 0x10208b570 0x191d8cab8 0x191d8d160 0x191d11b40 0x191d11c6c 0x191d192c0 0x191d23b84 0x191d23f70 0x191d1716c 0x191d119a0 0x191d87134 0x191d87838 0x1924f3d74 0x1924f7224 0x1924f70d0 0x1924f739c 0x191d87290 0x191d87838 0x1924f3d74 0x1924f7224 0x1924f70d0 0x1924f739c 0x191d87290 0x191d87838 0x191cceaec 0x191ccdf08 0x191cca9c8 0x191cca7e0 0x191ccde54 0x1923a2e50 0x191b3e148 0x1923a2e50 0x191dd9494 0x191dd97f8 0x191b40b58 0x1923a2e50 0x191dd9494 0x191dd97f8 0x191dd8814 0x1923dc3d4 0x1923dd714 0x1923b9e2c 0x192431fa4 0x192434500 0x19242d374 0x18e2aca00 0x18e2ac958 0x18e2ac0f0 0x18e2a723c 0x18e2a6adc 0x19822c328 0x1923a1ae0 0x1020de520 0x18e130360)
libc++abi.dylib: terminating with uncaught exception of type NSException
As I state in the answer of my question linked above I have written a Swift class that exposes the CocoaPod's library functions I need which allows my project to compile...
import Foundation
import HGCircularSlider
#objc public class CircularSliderObjc: RangeCircularSlider
{
#objc override open var startPointValue: CGFloat {
get {
return super.startPointValue;
}
set {
super.startPointValue = newValue;
}
}
#objc override open var endPointValue: CGFloat {
get {
return super.endPointValue;
}
set {
super.endPointValue = newValue;
}
}
#objc override open var endThumbImage: UIImage? {
get {
return super.endThumbImage;
}
set {
super.endThumbImage = newValue;
}
}
#objc override open var startThumbImage: UIImage? {
get {
return super.startThumbImage;
}
set {
super.startThumbImage = newValue;
}
}
}
As you can see in the project I have exposed startPointValue as both a set and a get. However invoking this function at runtime causes the crash.
Here is the calling class's header...
#import "BaseViewController.h"
#import "Hyperion-Swift.h"
#interface TemperatureDeviceViewController : BaseViewController
#property (weak, nonatomic) IBOutlet CircularSliderObjc *rangeSlider;
And the call in my .m file...
[self.rangeSlider setStartPointValue:[self getSliderValueForTemp:startValue]];
I'm assuming I'm missing one critical step here?
UPDATE #1
I've tried the answer suggested by Max which makes a lot of sense. However because this is an IBOutlet it in my ViewController his solution really doesn't work for my use case here.
I did some further debugging and put breakpoints all over my startPointValue function in order to see what the "super" was referencing. However none of the breakpoints are triggered before the crash happens. Therefore I'm not sure that the call to "super" is the actual cause? Verdict is still out on this one I think.
Try redesigning your wrapper class to encapsulate rather than inherit from the framework class. For example:
#objc public class CircularSliderObjc
{
let slider: RangeCircularSlider // NOT #objc!
#objc var startPointValue: CGFloat {
get {
return slider.startPointValue;
}
set {
slider.startPointValue = newValue;
}
}
That way Objective-C doesn't even need to know that the Swift class exists at all. My guess is that this is crashing on the super, where something Swift-specific is being accessed from Objective-C.

"This class is not key value coding-compliant for the key" error in Swift

I have been getting this error message in Swift:
Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<Faceit.ViewController 0x7f8f72501e40> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key faceview.'
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var faceView: FaceView! {
didSet{
updateUI()
}
}
var expression = FacialExpression(eyes: .closed, mouth: .frown) {
didSet {
updateUI()
}
}
private func updateUI() {
switch expression.eyes {
case .open:
faceView?.eyesOpen = true
case .closed:
faceView?.eyesOpen = false
case .squinting:
faceView?.eyesOpen = false
}
faceView?.mouthCurvature = mouthCurvatures[expression.mouth] ?? 0.0
}
private let mouthCurvatures = [FacialExpression.Mouth.grin:0.5,.frown: -1.0,.smile:1.0,.neutral:0.0,.smirk:-0.5]
}
See: Thread 1: signal SIGABRT Xcode 6.1
You have to go into Interface Builder and look for the one (or more) outlets that have a warning triangle (follow the link for a screenshot). Once you delete those bad connections, you're either (1) ready to go because you have already connected your new objects or (2) you need to make the new connections so that you have all the elements loaded properly and you have no warning triangles.
Open your storyboard > Select the ViewController which class is showing error> Just remove all of the outlet> And reassign outlet.
Hope your problem will be fixed. This is not a big issue , by mistake you have multiple key or different name key for one outlet and specially its faceview.
#vadian has told me how to fix the issue. It worked, changed to faceview, also reconnect with Interface Builder. (This is important)!

Crashing on presenting IDMPhotoBrowser in Swift

I am integrating IDMPhotoBrowser in my Swift Project.
I have created a bridging header and I have imported IDMPhotoBrowser.
#import <IDMPhotoBrowser.h>
In my view controller:
class ViewController: UIViewController, IDMPhotoBrowserDelegate {
override func viewDidLoad() {
super.viewDidLoad()
var photoBro = IDMPhotoBrowser(photos: imagesArray)
photoBro.delegate = self
presentViewController(photoBro, animated: false, completion: nil)
}
But when it is executed, I get the following error
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString unloadUnderlyingImage]: unrecognized selector sent to instance 0x165d6870'
In IDMPhotoBrowser Library, I found this function in IDMPhoto.m
// Release if we can get it again from path or url
- (void)unloadUnderlyingImage {
_loadingInProgress = NO;
if (self.underlyingImage && (_photoPath || _photoURL)) {
self.underlyingImage = nil;
}
}
From the error it looks like it is expecting to do something to an array of IDMPhotos but instead has an array of strings...are you passing the right kind of array to the constructor?
As #GoatInTHeMachine pointed, I was not passing the right kind of array.
But as I wanted to pass the imageURLs, I had to change the constructor.
The following worked for me:
var photoBro = IDMPhotoBrowser(photoURLs: imagesArray)

Swift Plist Reading and Initializing Arrays as Objects for Key

I'm developing a small UITableView-based app in Swift. I started out hard-coding some basic arrays as such (included is the basic class declaration and the UITableView outlet declaration:
import UIKit
class ScenesViewController: UITableViewController {
#IBOutlet var myTableView: UITableView
var sceneName = ["Scene 1", "Scene 2", "Scene 3", "Scene 4", "Scene 5"]
var sceneDetail = ["Hi", "Hello", "Bye", "My Bad", "Happy"]
This code is inside a UITableViewController which has an outlet that is all hooked up to a UITableView. I have created a plist for this called "Scenes.plist" and have attempted to replace the code. In Objective-C, I would do this:
NSString *path = [[NSBundle mainBundle] pathForResource:#"Scenes" ofType:#"plist"];
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:path];
sceneName = [dict objectForKey:#"SceneName"];
sceneDetail = [dict objectForKey:#"SceneDetail"];
I started doing this in Swift like this:
let path = NSBundle.mainBundle().pathForResource("Scenes", ofType:"plist")
let dict = NSDictionary(contentsOfFile:path) // Error: 'ScenesViewController.Type' does not have a member named 'path'
I scoured the Internet for a solution but was unable to find one. So I took up the next course of action - an 'almost' one-liner:
let dict = NSDictionary(contentsOfFile:
NSBundle.mainBundle().pathForResource("Scenes", ofType:"plist"))
var sceneName = dict["SceneName"] // Error: 'ScenesViewController.Type' does not have a member named 'dict'
Now, the only solution I can almost resort to is having all of that on one line for each array:
var sceneName = NSDictionary(contentsOfFile:
NSBundle.mainBundle().pathForResource("Scenes", ofType:"plist").objectForKey("SceneName")
// Warning: Variable 'sceneName' inferred to have type 'AnyObject!', which may be unexpected
// Fix-It: Add an explicit type annotation to silence this warning (var sceneName: AnyObject! = ...)
So I added the explicit type annotation just to find out that there were more errors. Inside the cellForRowAtIndexPath: function:
override func tableView(tableView: UITableView?, cellForRowAtIndexPath indexPath: NSIndexPath?) -> UITableViewCell? {
let cell: UITableViewCell = tableView!.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath) as UITableViewCell
// Configure the cell...
cell.textLabel.text = sceneName[indexPath!.row] // Error: could not find member 'row'
return cell
}
There are actually two errors; I do not know whether this is accidentally duplicated or not. The next error(s) are in the the prepareForSegue:sender: method:
override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?) {
if segue?.identifier == "ShowDetails" {
var detailVC: ScenesDetailViewController = segue!.destinationViewController as ScenesDetailViewController
var myIndexPath: NSIndexPath = myTableView.indexPathForSelectedRow()
var row: Int = myIndexPath.row
detailVC.detailModal = [sceneDetail[row], sceneName[row]] // Error: Could not find an overload for 'subscript' that accepts the supplied arguments
}
}
Again, there are two errors; however, I believe this is because sceneDetail and sceneName are both used. There seem to be errors all over the place with reading and using plists in files that aren't there (or that I haven't come across) in Objective-C.
To resolve your initial problem, put the code inside a func, like:
var memoryName = []
var memoryDetail = []
override func awakeFromNib() {
super.awakeFromNib()
let path = NSBundle.mainBundle().pathForResource("Memories", ofType:"plist")
let dict = NSDictionary(contentsOfFile:path)
memoryName = dict["MemoryName"] as Array<String>
memoryDetail = dict["MemoryDetail"] as Array<String>
}
You can solve this by moving your code into a function that is called after your objects initialization.
Properties are initialized as part of the initialization of your object. You have created path and dict as properties and are trying to initialize them with code that does not meet the requirements for initialization.
An initializer cannot call any instance methods, read
the values of any instance properties, or refer to self as a value
until after the first phase of initialization is complete.
--The Swift Programming Language - Initialization - Safety check 4
Also, it seems you only want and need sceneName and sceneDetail to be properties, so you can move them completely within the scope of the method you use to populate sceneDetail and sceneName after initialization.
It's hard for me to say what the subscript error is exactly because I don't see what type of data detailVC.detailModal is supposed to contain; even so, it seems the wrong type of object is being passed into the detailModal array. A good little description of this issue is Swift and arrays

Resources