-6

I have a value that is coming from the server, it's saving to NSString variable (sometimes server return it as a string, sometimes as a boolean value).

Please assume that this part of the code could not be changed.

The problem came when I rewrote the Objc part to the swift 4

The code that I have in Objc:

[data.isActive boolValue]

In swift 4 it fails since there are no .boolValue notation in String, you only could convert String to bool using Bool() syntax. And since the value is not a real string, calling Bool() would resolve in crashes because of CFBoolean unrecognized selector since it was force wrapped from String.

Is there any way to overcome that without falling back for Objc code that would wrap those transformations?

Please check this test project on GitHub

It even fails on assigning those type of value to any swift object.

Taier
  • 2,109
  • 12
  • 22
  • 1
    "(sometimes server return it as a string, sometimes as a boolean value)" wat – Alexander Nov 05 '18 at 21:29
  • @Alexander sometimes value come as a string like "0", sometimes as false – Taier Nov 05 '18 at 21:32
  • 1
    `"false"` or `false`? – Alexander Nov 05 '18 at 21:35
  • 1
    How do you get and declare your `data` from the server? Please show your current Swift code accessing `data.isActive` with all relevant declarations and definitions. – OOPer Nov 05 '18 at 21:42
  • @Alexander JSON example { "isActive": false} or {"isActive":"0"}. Since the assigning happened from NSDictionary, it may stay wrapped inside any class. My question is not about input data, it's about how to resolve this particular case that worked in objc but now not working with swift. – Taier Nov 05 '18 at 21:42
  • @OOPer there is no need for that, please read my comment above – Taier Nov 05 '18 at 21:43
  • 4
    YOU think no need, readers do. – OOPer Nov 05 '18 at 21:43
  • @OOPer I'm telling you all variables classes and values, there is no need to wrote how they are assigned since it's not relevant if you already know the output. – Taier Nov 05 '18 at 21:49
  • 3
    YOU think so, think in a way readers do. – OOPer Nov 05 '18 at 21:50
  • @OOPer readers are given enough information, you could reverse engineer it back to assigning. The question is not about that at all. – Taier Nov 05 '18 at 21:54
  • OK, you think it's enough. Then the vadian's answer is enough or the linked answer is enough. If you really had shown enough info for readers, you would not get such an answer or marked as duplicate or downvoted. – OOPer Nov 05 '18 at 21:57
  • @Sh_Khan please create a variable in Objc of class NSString, assign to it bool via cast and then pass this to swift and try to check for class. You would have a crash. My question is not about swift-swift class compare, it's about objc-swift compare. The questions that you link does not work in my case. – Taier Nov 05 '18 at 21:59
  • @OOPer I agree with enough, I showed enough info for a problem description, You don't need to know how Universe was created in order to make a pie. Both of linked question and vadian answer would not work, you could check that by example I described above. – Taier Nov 05 '18 at 22:04
  • I'm not telling you to show Universe, but just saying all the gradients and equipments to make the pie. You're just complaining some recipe based on other equipment would not work. When you have enough info shown, you will get a right answer. – OOPer Nov 05 '18 at 22:21
  • @OOPer thank you for your time and effort, please see the attached project on GitHub, It illustrates the problem :) – Taier Nov 05 '18 at 22:50

1 Answers1

0

Objective-C is very typeinsensitive, from the BOOL perspective 0, "0", "NO", ``false, "false" and even nil is false, everything else is treated as true. That's why NSString has a boolValue property. It just returns value != 0.

Swift is a strong typed language. You have to check the type:

let value : StringOrBool

let result : Bool
switch value {
  case let boolValue as Bool: result = boolValue
  case let stringValue as String: result = stringValue == "1" || stringValue == "true"
  default: result = false
}      
vadian
  • 274,689
  • 30
  • 353
  • 361
  • thanks, but it still fails with [__NSCFBoolean _fastCStringContents:] since in class comparing swift assume that NSString would be NSString :) – Taier Nov 05 '18 at 21:55
  • Avoid `NS` classes for example don't use `NSDictionary` and `NSArray`. Use native Swift types. And don't try to translate ObjC literally to Swift. – vadian Nov 05 '18 at 21:57
  • @vadin thanks, but the question is exactly about objc-swift. Please create a variable in Objc of class NSString, assign to it bool via cast and then pass this to swift and try to check for class. You would have a crash. I just dont want to fall back to objc wrapped in order to fix that, but looks like that the only way – Taier Nov 05 '18 at 22:02
  • "assign to it bool via cast" ...don't do this. – Alexander Nov 05 '18 at 22:03
  • You wrote *...I rewrote the Objc part*. Once again, don't *translate Objc code literally* and don't use `NSString, NSDictionary` etc in Swift. – vadian Nov 05 '18 at 22:03
  • @Alexander imagine you have an SDK that does that and you can't change it or live without it. That why I wrote, "Please assume that this part of the code could not be changed." :) – Taier Nov 05 '18 at 22:06
  • @Taier The author of that library knew they couldn't assign `NSString` to where `bool` is expected. They did anyway. Unfortunately, you have to deal with the consequences. Either clean up their mess, or write up some nasty hack in Swift to handle the weird type. – Alexander Nov 05 '18 at 22:10
  • @vaian thanks, I understand that, the thing is its not possible to rewrite it in any way in swift since any call to such wrapped variable resolves in crash. And since NSString come from class that is bridge-headered.. there are not much that I could do from swift :) – Taier Nov 05 '18 at 22:10
  • @Alexander the second part is exatcly my questions. Its not possible since any call to such wrapped variable resolvs in crash. The only way that I see is to fall back for a objc wrapper that would incapsulate boolValue comparison and return true/false back.. – Taier Nov 05 '18 at 22:13
  • @Taier What exactly is the type of the `isActive` property on class of `data`? Is it `bool`? – Alexander Nov 05 '18 at 22:17
  • @Alexander NSString as its written in the first sentence of the question :) – Taier Nov 05 '18 at 22:18
  • I tested to return `@"false".boolValue;` from an ObjC class via bridging header. I get a Swift `Bool` `false` and even with `@"hello".boolValue;` I get Swift `Bool` `true`. I suspect the error is somewhere else. – vadian Nov 05 '18 at 22:19
  • @Taier That doesn't match what you said in an earlier comment: "NSString, assign to it bool via cast and then pass this to swift and try to check for class." That implies that it was an `NSString` being assigned to a variable of type `bool`. So which is it? – Alexander Nov 05 '18 at 22:24
  • @vadian thanks for your time, I created a test project on GitHub in order to illustrate the problem. Although I used NSNumber, it would work the same for CFBoolean. – Taier Nov 05 '18 at 22:46
  • @Alexander thanks for your time, I created a test project on GitHub in order to illustrate the problem. Although I used NSNumber, it would work the same for CFBoolean. – Taier Nov 05 '18 at 22:46
  • Your code contains a fatal mistake. The value of the ObjC dictionary is `NSNumber` but the return type is `NSString`. This cannot work. Change the ObjC return type to `id` which is `Any` in Swift. – vadian Nov 05 '18 at 23:00
  • @vadian thank you for looking, yes, that the thing) in Objc it was possible to overcome because of a messaging structure. I was looking for a way to overcome that in swift without touching objc implementation. – Taier Nov 05 '18 at 23:11