I have framework which I developed in swift and I am using that framework in my objective C code base.
In Framework I have below class and method
public class MyClass: NSObject {
public func testMethod(typeId : Int?){
}
}
When I change typeId Int? optional to Int then I am able to access that testMethod in Objective C but with Int? optional paramter I am not able to access that testMethod in my Objective C code. Any idea how can I access optional swift parameterised method in Objective C?
try override your method like this:
public class MyClass: NSObject {
//this method can be called only from swift and can recieve nil
public func testMethod(typeId : Int?){
}
//this method can be called from swift and objective c but both can´t recieve nil instead you can send 0 or another value and check it
public func testMethod(typeId : Int){ // override method
testMethod(typeId:typeId == 0 ? nil : ticketId) //original method
}
}
Related
#objc public class A: NSObject
{
public func getSomething() -> Something
{
return Something()
}
}
#objc public class B: A{
override public func getSomething() -> SomethingGood
{
return SomethingGood()
}
}
#objc public class C: A{
...
}
#objc public class Something: NSObject{
var name: String=“”
}
#objc public class SomethingGood: Something{
var type_id: Int = 0
}
Swift compiler shows incompatible types for class B's override function. How do I implement the above? I have tried to use Generics but they are not available for Objective-C developer once the library is built.
I want to be able to use:
A.getSomething() and C.getSomething() to return an object of Something
And B.getSomething() to return an object of SomethingGood.
And I don't want to get two same named function which is func getSomething() for B with two different return types.
Any idea?
The code is used in a static library written in Swift. Once the library is compiled, it should be available to both swift and objective-c.
You can't change the return type, or it wouldn't be an override. You can still return SomethingGood in this case, just your function declaration can't show the return type as that.
#objc public class B: A{
override public func getSomething() -> Something
{
return SomethingGood()
}
// now whereever you're calling this, if you know it's SomethingGood, you can cast it
if let somethingGood = b.getSomething() as? SomethingGood {
// do something good
}
While updating to Xcode 8 Beta 6, from what I saw a new type got introduced: UIActivityType
So I tried to do somewhere like this in my UIActivity custom class:
class FooActivity: UIActivity {
func retrieveActivityType() -> String {
return "someStringDescribingActivityType"
}
override open var activityType: UIActivityType? {
#objc(retrieveActivityType)
get {
return UIActivityType(rawValue: "someStringDescribingActivityType")
}
}
}
where retrieveActivityType() is the Objective-C equivalent since UIActivityType is only defined in Swift. But no luck so far, still having two errors:
Property cannot be an #objc override because its type cannot be represented in Objective-C
'#objc' getter for non-'#objc' property
Is there something obvious that I'm missing?
Found a quick fix by just making the return type as non-optional.
I guess there is no real workaround until beta 7 gets released.
class FooActivity: UIActivity {
override open var activityType: UIActivityType {
get {
return UIActivityType(rawValue: "someStringDescribingActivityType")
}
}
Sources:
https://bugs.swift.org/browse/SR-2344
https://github.com/apple/swift/pull/4360
I have a simple Swift extension on NSManagedObject, in which I have a parametrized method for finding a single object - the signature looks like:
public class func findFirst<T:NSManagedObject>(inContext context : NSManagedObjectContext? = .None) -> T?
I'm trying to call this from Objective-C, but it seems like it cannot be seen. If I create a non-parameterized version I can see and call it just fine from Objective-C:
public class func findFirstUntypedWithPredicate(predicate:NSPredicate?, inContext context : NSManagedObjectContext? = .None) -> NSManagedObject?
Is there any way for ObjectiveC to be able to reach the parameterized version of the call?
I would use Self like so:
public class func findFirst(inContext context : NSManagedObjectContext? = .None) -> Self?
using the technique found here:
How can I create instances of managed object subclasses in a NSManagedObject Swift extension?
However, that causes the Swift compiler to segfault when compiling the code (Xcode 6.3.1, or Xcode 6.4 beta 2).
Edit: Here's a link with the full source of the framework I'm trying to build, including bonus Swift compiler crashes caused by templated methods:
https://www.dropbox.com/s/fixaj9ygdoi4arp/KiGiCoreData.zip?dl=0
Generic methods are not visible from Objective-C. However you can use
the ideas from How to use generic types to get object with same type to define a findFirst() class method
which returns Self? (the Swift equivalent of instancetype) without
being generic:
// Used to cast `AnyObject?` to `Self?`, `T` is inferred from the context.
func objcast<T>(obj: AnyObject?) -> T? {
return obj as! T?
}
extension NSManagedObject
{
class func entityName() -> String {
let classString = NSStringFromClass(self)
// The entity is the last component of dot-separated class name:
let components = split(classString) { $0 == "." }
return components.last ?? classString
}
// Return any matching object, or `nil` if none exists or an error occurred
class func findFirst(context : NSManagedObjectContext, withPredicate pred : NSPredicate?) -> Self? {
let name = entityName()
let request = NSFetchRequest(entityName: name)
request.predicate = pred
var error : NSError?
let result = context.executeFetchRequest(request, error: &error)
if let objects = result {
return objcast(objects.first)
} else {
println("Fetch failed: \(error?.localizedDescription)")
return nil
}
}
}
This can be used from Swift
if let obj = YourEntity.findFirst(context, withPredicate: nil) {
// found
} else {
// not found
}
and from Objective-C:
YourEntity *obj = [YourEntity findFirst:context withPredicate:nil];
I'm trying to extend an Objective-C class in Swift and make it conform to the Equatable protocol. This requires to access some private members of the extended class, which the compiler doesn't let me do. What is the correct way to do it without making the private members public?
My Swift code:
import Foundation
extension ShortDate : Equatable { }
public func == (lhs: ShortDate, rhs: ShortDate) -> Bool {
if (lhs.components.year == rhs.components.year)
&& (lhs.components.month == rhs.components.month)
&& (lhs.components.day == rhs.components.day) {
return true;
}
return false;
}
Objective-C:
#interface ShortDate : NSObject<NSCopying, NSCoding> {
NSDate *inner;
NSDateComponents *components; // The date split into components.
}
...
#end
The error I'm getting:
ShortDate.swift:26:9: 'ShortDate' does not have a member named 'components'
I came across this question while trying to find a way to access a private variable of a class from one of the SDKs we use. Since we don't have or control the source code we can't change the variables to properties. I did find that the following solution works for this case:
extension ObjcClass {
func getPrivateVariable() -> String? {
return value(forKey: "privateVariable") as? String
}
open override func value(forUndefinedKey key: String) -> Any? {
if key == "privateVariable" {
return nil
}
return super.value(forUndefinedKey: key)
}
}
Overriding value(forUndefinedKey:) is optional. value(forKey:) will crash if the private variable doesn't exist on the class unless you override value(forUndefinedKey:) and provide a default value.
I believe that there is no way to access Objective-C instance variables from Swift. Only Objective-C properties get mapped to Swift properties.
I wrote a class in a swift-file:
class UtilityMethods {
class func userId() -> Integer {
...
}
class func setUserId(userId : Int) {
...
}
}
I'm importing the -swift.h-header which compiles fine, but I can't use
[UtilityMethods userId];
in my Objective-C code:
Unknown receiver 'UtilityMethods'; did you mean 'UtilMethods'?
UtilMethodsis an Objective-C class I'd like to replace. Am I missing something?
EDIT
With the help of Lance, the class is now recognized, but the getter method isn't, unfortunately, the header files looks like the following:
SWIFT_CLASS("_TtC15...14UtilityMethods")
#interface UtilityMethods : NSObject
+ (void)setUserId:(NSInteger)userId;
- (instancetype)init OBJC_DESIGNATED_INITIALIZER;
#end
Why is the getter missing?
In order to have a Swift class available to Objective C you have two options:
Option 1: Subclass NSObject (or some other Objective C class)
class UtilityMethods : NSObject {
class func userId() -> Int {
...
}
class func setUserId(userId: Int) {
...
}
}
Option 2: Add the #objc attribute to your class telling the Swift compiler to make an Objective C object that uses dynamic dispatch rather than static dispatch for method calls
#objc class UtilityMethods {
class func userId() -> Int {
...
}
class func setUserId(userId: Int) {
...
}
}
In my case, I was doing #objc correctly, but in changing from my old Objective-C .h file to my new swift file, I had accidentally lost the Target Membership of the new file, so it wasn't being included in the build.