Prevent Subclassing Objective-C Classes in Swift - objective-c

I'm adding Swift interior annotations to my Objective-C classes. I'm trying to prevent my class from being subclassed:
__attribute__((objc_subclassing_restricted))
#interface CWTestFinalClass : NSObject
#end
This works as expected in Objective-C:
// Generates Error, as expected
#interface CWTestSubclass : CWTestFinalClass
#end
However, I'm still able to subclass in Swift
// Should fail, but works without error
class TestSubclass: CWTestFinalClass {
}
Question: How do I prevent Objective-C classes from being subclassed in Swift?

Objective C does not have a final keyword, or anything like it. Even if a compile-time attribute or modifier did exist, it could trivially be sidelined by the use of the runtime APIs to dynamically create a subclass of any psuedofinal class.
The Swift compiler enforced that Swift could block attempts to subclass a final class, but that wouldn't stop Objective C from being able to do so (which isn't compiled through the Swift compiler). Thus, the objc_subclassing_restricted attribute was added, specifically to make clang enforce the illegality of subclassing final Swift classes.
There really isn't much of a benefit to making Objective C classes final, even if it were possible. Objective C is a much more dynamic language, that seems to follow Python's "we're all adults here" mantra.
The biggest reason to support final classes is inform the compiler which classes are candidates for de-virtualization. But Objective C always uses dynamic dispatch, and never does de-virtualization, anyway.

Related

What type of class definition is this: ClassName<Variable> : parent

What dose ViewControllerClass means here?
As far as I know this is not protocol, delegate or extension. Any one can explain how dose this work?
.h file:
#interface BaseViewControllerTest <ViewControllerClass> : XCTestCase
#property ViewControllerClass viewController;
- (void)setUpTestWithStroyboardName:(NSString *)viewControllerName;
.m file:
#implementation BaseViewControllerTest
- (void)setUpTestWithStroyboardName:(NSString *)viewControllerName {}
Used like this:
#import "BaseViewControllerTest.h"
#interface CTSelectChildAccountViewControllerTests : BaseViewControllerTest <CTSelectChildAccountViewController *>
#end
Starting with Xcode 7 Objective-C supports generics:
Objective-C has been updated to enable it and Swift to work together more easily and efficiently. The new Objective-C language features include:
Generics. Allow you to specify type information for collection classes such as NSArray, NSSet, and NSDictionary. The type information improves Swift access when you bridge from Objective-C and simplifies the code you have to write.
CTSelectChildAccountViewController is a ViewController. Dose that mean ViewControllerClass is defined as UIViewController?
The asterisk from the instantiation is relevant too, so ViewControllerClass viewController is interpreted as CTSelectChildAccountViewController* viewController.
What is the benefit except Swift?
Objective C compiler has more type information now, so it can perform better checks on the methods that you call. For instance, you can annotate Cocoa collections with the type that goes into them, e.g. NSArray<NSString*> *array, and have the compiler spot places where you insert a wrong type by accident.
And how is it useful with Swift?
Swift has built-in support for generics. Adding lightweight generics to your Objective-C API makes it easier to interface with Swift, because your API gets translated more precisely. For instance, translating your example from Swift would keep its generic nature, instead of replacing generic type parameter ViewControllerClass with its base type.

How to reference Swift enum in Objective-C Header

Is there a way to reference a Swift enum from an Objective-C header? If you want to see Swift classes in the Objective-C header you can use
#objc class Foo
I don't see anything similar for enums.
What you want to do is called forward declaration. To forward declare an enum you can do:
enum name;
But since the compiler won't know the size of the enum, you will only be able to use it as a pointer in your header file.
Even doing this might prove problematic if you use compiler flags like -pedantic.
So in short, there is no good way to do this. Your best bet is not to, and access the enum from your implementation (.m) file instead.
In your implementation file, #import your swift bridging header file, and, without knowing more details about your problem, you could add private properties that use your enum like this:
#interface MyObjCClassDefinedInTheHFile()
#property (nonatomic, assign) SomeSwiftEnum type;
#end
Hope this helps.
typedef SWIFT_ENUM(NSInteger, MyEnum);
In Mixed OBJC - Swift projects the best way to have enums work in both types of classes will be to define the enum in an OBJC header and not in a swift class. swift enums can't be used in OBJC header files
taken from the answer here
enums are one part of the swift Objective-C communication that does not always work. The thing is that in Objective-C, the enums can just be primitive types(NSInteger for example).
In swift you can have enums on more types, for example like String. Which is one of the awesome things about swift.
However, these enums wont be compiled to Objective-C because there is no equivalent for them. So they will simply be ignore and not generated in this header file that xcode creates for all your swift files.
This is called Objective-C generated interface header:
This generated file contains all the classes and enums available in objective-c . You have to mark everything you want to expose in Objective-c with #objc or make them public. You dont need any forward declaration for them to work, if you have this.
Hope this helps you figure out why your enum is not visible in Objc. Let me know if it worked out.
As far as I can tell, raf's answer is still correct. The cleanest solution is to simply leave your enum in an Objective-C file until you no longer need to access it from an Objective-C header. I wanted to offer another possible workaround, though.
In my case I am gradually rewriting a large Objective-C project in Swift, and I don't mind an imperfect workaround if it allows me to rewrite more of my code in Swift. So I've settled on simply passing the enum to Objective-C as it's raw type, Int, or NSInteger to Objective-C. For example:
- (void)doSomethingWithType:(NSInteger)rawType {
if (rawType == ExampleTypeWhatever) {
// Do something
} // etc...
}
When I call this method from Swift, all I have to do is pass the .rawType, instead of the actual enum value:
objcObject.doSomething(withType: ExampleType.whatever.rawValue)
This keeps things fairly simple on both sides, and it'll be easy to update once doSomethingWithType: is eventually rewritten in Swift.
I just use NSInteger as return type for both header and implementation files. And when you need to use the enum, get the enum by let yourEnum = YourEnum(rawValue: Int(enumNSInteger)). This works for me.
You can access Swift enums in Objective-C, but only if the enum is declared with an #objc qualifier, which means that it has to be of type Int.

Can Swift do everything that Objective-C can do?

I am new to IOS developing, and want to use the Swift language instead of Objective-C.
I know few concepts about Cocoa touch, and I want to know : Can Swift do everything that Objective-C can do ?
There are a lot of things that can be done in Objective-C but cannot be done in Swift, without implementing it in Objective-C and then using it from Swift. Some of them include:
Catching Objective-C exceptions
Using C++ APIs (through Objective-C++)
Using NSInvocation, performSelector: and other ways of making calls dynamically where the method to call is chosen at runtime
Handling unimplemented method calls using forwardInvocation:
Provide a function for use in C APIs that take a function pointer
The only concept I know that is in Objective-C but not in Swift, is Key-Value Observing (KVO). You can use KVO for a Swift class to observe the property of an Objective-C class, but you cannot observe any arbitrary property of a Swift class. See this answer for more details.
This is an interesting question but essentially the answer must be NO because you can use Objective-C resources in swift using bridging-headers. Xcode automatically translates Swift to Objective-C and vice versa. However, if you cannot write Objective-C code then you cannot include your own custom objective-c classes in your swift projects!
It all depends on how you like to code. Apple have said that Objective-C is still a 'first class' language meaning that they are going to run Swift and Objective-C side by side for the foreseeable future. Personally I prefer Objective-C because you can use C very easily (as anything that is legal in C is also legal in Objective-C) added to which Swift is a more procedural in style where Objective-C is quite clearly object orientated.
It is worth noting that the Cocoa and Cocoa Touch classes are all objective-c classes and so it may be useful to have a working knowledge of Objective-C. I think the best advice I've heard so far is, if you have the time, learn both!

Objective-C method implementation nuances

I have just started to develop for the iPhone and am in the process of learning Objective-C. I have seen some code that implements a method in the #implementation side of a class like this:
-(void)myMethod; {
// method body
}
What makes this interesting is that there is no mention of myMethod in the #interface for the class. I tried a sample project with this and when I compile I get a warning from XCode that myMethod may not be seen by the calling code.
Can anyone tell me what is going on?
Thanks!
It's just like functions in C. You don't need a declaration (i.e. it doesn't have to be in the #interface) but if there's no declaration, any code before the method definition will generate that warning. Code after the method definition will not generate a warning.
In ObjC, method calls are resolved dynamically (dynamic binding), meaning that when you do [obj myMethod];, internally the ObjC runtime software will go through the class methods at that point in time and if it finds one called "myMethod" it will then call it.
Also it is possible to add methods to an object at runtime.
The method declarations in an #interface section is only there to help the compiler determine what methods are publicly available for a given class. If you do add a method in your #implementation only, the compiler may warn you about that, but the code will still compile and work.
I sometimes use this to add internal methods to my objects, which are only called from other methods after it, and never from outside. Though I don't remember seeing warnings about it... Make sure that the calling code is placed after the method implementation in the same file.

Why subclass NSObject?

What is the purpose/use of NSObject in Objective-C? I see classes that extend NSObject like this:
#interface Fraction : NSObject
In C++ or Java, we don't use any variables like NSObject even though we have preprocessor directives and import statements in both Objective-C and Java.
Why do classes explicitly inherit from NSObject in Objective-C? What are the consequences of not declaring inheritance from NSObject?
We use NSObject to explicitly state what a given class inherits from. I'm not sure about C++, but in Java there's something similar - the Object class. The only difference is that Java doesn't require that classes explicitly descend from Object - the language assumes anything that doesn't have a specified parent class descends from Object. Objective-C is different because it allows you to define different root classes - you are allowed to make a class that doesn't inherit from NSObject.
An example of such a different root class is NSProxy.
Have a look at the GNUstep NSObject source, it shows how the methods interact with the objective-c runtime through C functions.
+ (id) allocWithZone:(NSZone*)z
{
return NSAllocateObject(self, 0, z);
}
- (void) dealloc
{
NSDeallocateObject (self);
}
+ (BOOL) isSubclassOfClass: (Class)aClass
{
return GSObjCIsKindOf(self, aClass);
}
Since object-oriented languages have the concept of an inheritance, in any inheritance hierarchy there is a root class. In Java, the default parent class (if none is provided) is java.lang.Object, whereas in Objective-C, if you don't explicitly declare a parent class, you don't get one. Essentially, your class becomes a root class itself. This is a common mistake among Objective-C newcomers, since you normally want to inherit from NSObject in such cases.
While often problematic and puzzling, this actually allows quite a bit of flexibility, since you can define your own class hierarchies that act completely differently from NSObject. (Java doesn't allow you to do this at all.) On the other hand, unless you know what you're doing, it's easy to get yourself into trouble this way. Fortunately, the compiler will provide warnings if you call a method not defined by a class with no declared parent class, such as those you would normally expect to inherit from NSObject.
As for the "use" of NSObject, check out the documentation of the NSObject class and NSObject protocol. They define common methods used for object allocation, memory management, comparison, hashing, printing descriptions, checking class membership, querying whether objects respond to a selector, etc. Basically, NSObject is "good for" providing the core functionality of Objective-C objects free of charge.
All classes don't necessarily inherit from NSObject but it is the core for many of the classes because it provides things like alloc, retain, and release.
NSObject is the root class of all classes. In my estimation, it's 3 most basic functions are to allocate and initialize memory for you (alloc & init), as well as provide a description function.
Objective-C is all about objects sending messages to other objects -- so NSObject exists to provide that basic functionality.
If this sounds strange to you, you may wish to read more about programming paradigms, particularly object-oriented programming....In a nutshell, however, Objective C is a simple extension to the C language. C gets you the ability to program computer memory, numbers, and characters, but do anything else (like use strings, or show views, for example) you need the extension part, and NSObject is the beginning of that extension.
It may be a useful exercise to pick a class (like NSString, or any for that matter), and follow it's superclasses back to NSObject, to see what functionality each class added.
Hope that helps...
NSObject
The root class of most Objective-C class hierarchies, from which
subclasses inherit a basic interface to the runtime system and the
ability to behave as Objective-C objects.
From Apple documentation - https://developer.apple.com/documentation/objectivec/nsobject.
Basically, most of OOP programming languages explicitly or implicitly specify base class or base functionality. Otherwise you cannot build system where objects communicate with each other. Properties, memory management, message sending mechanism are partly or completely provided or supported by NSObject. Apple provide parts of the Objective-C implementation - https://opensource.apple.com/source/objc4/objc4-723/runtime/NSObject.mm.auto.html, where it's possible to see what is actually inside NSObject.
Also because Objective-C is a language from C-family, so compiler and linker needs to calculate how to layout object in memory and where put and find methods, that's only possible if you know how each of the classes/instances lays in memory and where. In case of Objective-C all base classes (NSObject, NSProxy, etc) have specification of that, so it's possible to calculate their size and add on top all inherited stuff - https://clang.llvm.org/compatibility.html#objective-c.
Consequently compiler don't let to leave a class without base class. So in the end class inheritance should lead to one of the root classes. Here is the error that appears if you don't specify it (from Xcode):
Class 'ClassWithoutBaseClass' defined without specifying a base class