In objective C, a Category will only "be used" in a class if I import it. So if I have a Category NSString+category, I have to #import NSString+category.h in each class I want to use it.
I have such a Category, and some of the classes I want to use it in are written in Swift. If I expose this category to Swift by putting it in the Bridging header, ALL swift classes will use it. How can this be avoided?
Note: My Category is actually on UIViewController and the code I have put there must only be used by SOME ViewControllers. It feels wrong and unneccessary to use this Category on the "other" ViewControllers.
Your base assumption is incorrect:
In objective C, a Category will only "be used" in a class if I import it
The methods in a category are present on the class if the category is compiled. Importing the header makes the method names visible; without that the compiler will give you a warning if you try to send a message using one of those names. (You can call the methods using performSelector: or the runtime library if you're determined.)
The same is true of your Swift class, and because of the way Objective-C headers are brought in to Swift, I don't believe there's a way to limit the methods' visibility in your Swift code.
Related
I'm working on a framework.
The library is written in Swift and I notice that when a class inherits from NSObject or conforms to NSObjectProtocol, its declaration can be found in *.framework/Headers/*-Swift.h.
This class is available outside of the module in Objective-C code, so it became public.
Why does it happen if the access level is internal?
Internal Swift classes need to be available to the Objective-C code of that framework, however the only way Objective-C code can access the Swift classes is by importing the -Swift.h header file.
Now, how can a Swift class be visible to Objective-C: it either needs to inherit NSObject, or conform to NSObjectProtocol. If any of these two conditions is fulfilled, and the class declaration is not decorated with #nonobjc/private/fileprivate, then it will be exported to Objective-C via the -Swift.h module header.
This is why any Swift classes that are exportable to Objective-C will automatically be present in the discussed header file. It's an (unfortunate) coincidence that for frameworks this results in the class being publicly available (due to the fact that any Objective-C declarations that appear in a header are public).
Now, if you want your class to not end up in the -Swift.h header file, but still want to keep the NSObject(Protocol) inheritance/conformance, a workaround would be to make your class generic, thus prohibiting its exposure to Objective-C. Note that this will also prevent the class from being available to Objective-C code in the same framework.
// the generic argument doesn't matter, it's only used to make the class
// Swift-only
class MyClass<T>: NSObject { }
The caveat would be that every time the class is used, you will need to specify a value for the generic argument. This can be avoided by adding an intermediary base class:
// just a class that inherits NSObject, but is not exported in the -Swift header
class Empty<T>: NSObject { }
class MyClass: Empty<String> { }
I am trying to convert my existing Objective C code to swift. I have a BaseClass 'A' which implements a protocol 'P' by using different Categories for proper code separation. It works fine when I use Objective Categories but when I implement a procotol method (method:) in a swift extension, I get the following error:
Method 'method:' with Objective-C selector 'method:' conflicts with previous declaration with the same Objective-C selector. Not sure how to resolve this issue? Is it not possible to do this Swift
I'm working on a library written in Objective-C. I want to have some methods available to callers written in Swift, and not available to callers written in Objective-C.
Going in the other direction, you can control Swift visibility in Objective-C with the #objc and #nonobjc attributes. Are there equivalents to make some Objective-C methods Swift-only or Objective-C-only?
Would I have to maintain a separate header? And if so, is there any way I could require Swift users to import Library-Swift.h in their bridging headers instead of Library.h?
You need separate headers,one for swift and one for objc(for the class).And for swift you could make a header for the whole framework(just for swift,and where you put the swift header for that class),and who wants to use your framework in swift include that header into their bridging header.
I have been reading through Apple documentation and as I read it is possible to use Swift classes in existing Objective-c project.
My question is, Can I use Swift code with objective-c code in the same class, in my existing Objective-c project?
Thanks
If you mean Objective C and Swift in the same file, no, you can't.
What you can do is create a class in Objective C, and add extensions in a Swift file, or the opposite
No, a class must be defined in Swift or in Objective-C not mixed language inside single class file, sorry .
As you may have already noticed a class in swift is generally made by a single file with .swift extension, while objective-C class is defined using two files .h and .m . So, a .h or .m can't contain swift code, the compiler will gives you some errors ...
The prequel for this question is here.
I have a class (A) and the class has category. In the category I've defined and implemented a method.
Now I am trying in (let's assume B) class to call [a someMethod]. My B class can't reach this method. Isn't possible to call the category meths from some other class?
You didn't show your code, but in the .m file that refers to the category method, you do need to import the header of the file that defines the category interface.
If you define a category in a .m file, you will not be able to call the category's methods from outside of that .m file.
Unfortunately, you did not provide enough information about your problem. Thus, all we can do is tell you how it should be done, and guess about why you are having trouble.
When you post a question, you should post all the relevant information. In this case, that would be the code that does not work.
Also, your statement
My B class can't reach this method.
means almost nothing. You get a compiler error, a runtime error, the syntax window does not show it, what exactly do you mean by that?
Now, when you implement a category on a class, you want to declare the category in a header (.h) file...
#interface Foo (BarExtensions)
- (NSString*)bar;
#end
and then, in the implementation (.m) file, provide the implementation for those methods.
#implementation Foo (BarExtensions)
- (NSString*)bar {
return #"FooBar";
}
#end
Of course, you should name things appropriately.
Also, make sure you include the .m file in the list of files that get built for your target.
If you do that, there's not much left to go wrong.