I have a class Comment declared as such:
public class Comment: NSManagedObject {
vars and methods...
}
When I try to compile my project, I get an error that reads:
Redefinition of 'Comment' as different kind of symbol
It highlights this line in the generated .h file: #interface Comment : NSManagedObject, and it tells me that the original declaration of Comment is in AIFF.h (something part of Foundation) and the line of the declaration is: typedef struct Comment Comment;.
I've only recently gotten this problem, and I've built the project with a Comment object successfully before. Why would an error like this happen in Swift?
Edit
If I remove the NSManagedObject superclass it compiles...
It may be a case that your class Comment is defined somewhere else in Foundation framework. What you need to do is importing only specific classes that you need inside your file. First remove all import statements in the source file and then import NSManagedObject like this:
import class CoreData.NSManagedObject
Then you will gain access to the NSManagedObject class you need for your Comment subclass. If you need any classes or structs from Foundation framework (for example NSError) you should import them like this:
import class Foundation.NSError
This will eliminate compiler errors about redefinition of class Comment.
Also make sure to clean the project and clean build folder by using Command + Shift + K and Command + Shift + alt + K
Related
I created a Swift enum as an Int (so it will work with Objective-c).
When I build the project, everything is fine. However, as soon as I try to import the class in a .h file (using a forward declaration #ClassName), the generated header file errors out with Redefinition of 'ClassName' as a different kind of symbol
Looking in the generated .h file I can see it generated the new type like so:
typedef SWIFT_ENUM(NSInteger, ClassName, closed) {
type1 = 1,
type2 = 2,
};
It underlines the ClassName saying it's been re-declared. However, it exists nowhere else in the header file (doing a search and it comes up only once) and it's only declared once in a swift file.
Any suggestions on what is going on?
Enums are not classes in Objective-C, so you need to use typedef instead of forward declaration in your .h file:
typedef NS_ENUM(NSInteger, ClassName);
and then in .m file, you need to import Module-Swift.h file.
Short version:
Assuming I have an app called MyApp. In some situation I have a duplicate class name so that one is MyClass where the other is MyApp.MyClass. How can I call MyApp.MyClass having MyApp constant (do not need to change the code if I change the app name).
Why and what happened (long version):
So assume we are in this MyApp application having following code (the real one is way way longer and used allover the app):
class MyClass {
}
class SomeOtherClass {
class MyClass {
}
func findMyClass(fromMyClass: MyApp.MyClass) -> MyClass {
...
}
}
Because there are two classes called MyClass in inner scope we need to call MyApp.MyClass to get the outer one which is all good.
But it seems a bit silly when MyApp changes which is my case.
Why did it change? I actually added a new target by duplicating the original one because I wanted to have some extra and some different settings (pretty standard procedure). So I renamed the new one to have MyApp-dev where I then got an error Use of undeclared type 'MyApp'.
So is there a keyword that can replace MyApp?
My current solution is to define a typealias on file scope that is then used inside the class to replace MyApp. The problem is that the method is not private so the typealias may not be private either which means I just have an extra name defined globally in the project.
EDIT:
Also there is a setting in Xcode build settings called Product Module Name which may be overridden to explicit naming which fixes the issue. Still this not really a good general solution; I can see cases where you might reuse the same code in multiple modules (creating libraries) which has the same issue. This would still meant that code would need to be fixed for each of these modules.
In c# when pulling in a library that has a lot of name collisions with existing code, there's a way to alias the import so you don't need to fully clarify the namespace for each use. eg:
using MyCompany.MyLibrary.Model as MMM
then you could do
MMM.MyObject
instead of
MyCompany.MyLibrary.Model.MyObject
With the recent update to swift 3.0, I've found some of my model objects are now colliding with the Foundation types, and I've been forced to prefix things that used to have an NS prefix in the class name with Foundation.classname. It would be great if I could type alias the import of my model library much like the c# example given above. Is this possible in swift 3.0? If not is there another strategy to avoid name collisions that would result in having to write the framework name in front of each type? I'm considering going back to prefixing my class names like we did in obj-c, but I'm trying to explore my options before I do that.
Update 2021 for Swift 5;
No, but you can import all and alias (in separate file), read below for more details.
Generally
You can import a particular entity as well as the entire module:
import struct SomeModule.SomeStruct
import class SomeModule.SomeClass
import func SomeModule.someFunc
See the full list of "importable" entity types in the import-kind rule of Swift grammar.
Then you can create a typealias:
typealias SMSomeStruct = SomeModule.SomeStruct
And, as of Swift 3, there is no import declaration combined with aliasing.
Considering the Collisions with Foundation Entities
Say, you have a class SomeModule.NumberFormatter.
It is enough to create two typealiases in a separate Swift file (in an importing project) to prevent collisions:
import Foundation
import SomeModule
typealias NumberFormatter = Foundation.NumberFormatter
typealias SMNumberFormatter = SomeModule.NumberFormatter
It's not even with Swift 5 possible to directly alias an import-statement!?
But fortunately, I could workaround it with something like:
import typealias MyModule.MyInnerClass
I mean, if we are the module's developer, simply move the alias into the module, like:
public typealias MyInnerClass = MyClass.MyInnerClass
public class MyClass {
public class MyInnerClass {
// Some cool logic here...
}
}
Like:
#interface ClassXXName(private)
- (void) xxxfunctions
#end
or user category methods?
#interface Foo() creates a class extension (I stand corrected, props to bbum) on interface Foo which is like additional methods added to the interface. Some people also use #interafce Foo(Private) (category) instead of a class extension with (). It's more like "injecting" new methods into a class from outside the class.
Placing this in the .m file just keeps other things from "seeing it" in the .h file, but that's it. Basically people normally use categories or class extensions in .m files to specify private interfaces, but they are also used for things like UIKit uses categories to add row and section public methods to NSIndexPath. (This can be confusing.)
You don't really need to define private methods this way, but if you have a method called bar that calls method foo before foo is defined in the source file you'll get a compiler warning something like "object self may not respond to foo". You can get rid of that by defining foo before you define bar or any other foo-calling code. It's the same with plain C and functions.
Like Ole says this doesn't stop anyone from calling the private methods, it just declares your intention that they be private and causes the compiler to generate the "may not respond to" warnings even if they import the .h file.
I was facing the same error as asked in this question
I overcome with this error by solution of declaring class ahead of time in my .h file with the class parameter
I am having FFTBufferManager.h and FFTBufferManager.cpp file and using it in HomeView.h and HomeView.mm file
class FFTBufferManager,CAStreamBasicDescription,DCRejectionFilter;
But now I am having error as
#include "FFTBufferManager.h"
#include "aurio_helper.h"
#include "CAStreamBasicDescription.h"
class CAStreamBasicDescription,FFTBufferManager; //here it shows this error
EXpected Unqualified-id befor ',' token
#interface HomeView
{
FFTBufferManager* fftBufferManager;
//it shows erros
EXpected Unqualified-id befor ',' token
ISO c++ forbids declaration of FFTBufferManager with no type
}
#property FFTBufferManager* fftBufferManager;
//shows error
'FFTBufferManager' is not a type
I'm gathering you're using both C++ and Objective-C.
I'd suggest renaming all your .cpp and .m files in which Objective-C and C++ code are meeting to use the extension .mm - this tells the compiler to use "Objective-C++" rules, and will stop a lot of compiler troubles.
Also, it seems CAStreamBasicDescritpion is a C++ class - you'll have to forward-declare it with class CAStreamBasicDescritpion;, not #class CAStreamBasicDescritpion; (note, no "at" sign) - the second form is only for forward-declaring Objective-C classes. This I suspect is the root cause of the particular error you have observed.
EDIT in response to comment: I'm not sure about your first new issue - that should work fine so long as both FFTBufferManager and CAStreamBasicDescription are C++ classes. As to your second one, depending on where exactly that line of code is (CAStreamBasicDescription thruFormat;) you may need to include the header rather than just the forward-declare: you're declaring an instance of CAStreamBasicDescription here, and the compiler needs to know its structure to do so.
You can't declare more than one class at a time.
Change your declarations to
class CAStreamBasicDescription;
class FFTBufferManager;
The compiler is looking for an unqualified-id because it believes that you're declaring a variable of type CAStreamBasicDescription, so it expects a variable name where you gave it a comma.
Looks like you are trying to create a class that already exists in one of the Cocoa frameworks.