0
votes

Throwing my hands up in the air with this one. I've tried protocols, forward declared classes, forward declared protocols, and I can't figure out the configuration that works. I'm going to list the header files in question so you can see what is being imported, but I am positive the problem is circularly loading imports.

The error is:

Ld /Users/eamonwhite/Library/Developer/Xcode/DerivedData/maggie-govvbppylostlwaashtkbcuawqzc/Build/Products/Debug-iphoneos/maggie.app/maggie normal arm64 (in target 'maggie' from project 'maggie') cd /Users/eamonwhite/maggie/maggie /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -target arm64-apple-ios13.4 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.4.sdk -L/Users/eamonwhite/Library/Developer/Xcode/DerivedData/maggie-govvbppylostlwaashtkbcuawqzc/Build/Products/Debug-iphoneos -F/Users/eamonwhite/Library/Developer/Xcode/DerivedData/maggie-govvbppylostlwaashtkbcuawqzc/Build/Products/Debug-iphoneos -filelist /Users/eamonwhite/Library/Developer/Xcode/DerivedData/maggie-govvbppylostlwaashtkbcuawqzc/Build/Intermediates.noindex/maggie.build/Debug-iphoneos/maggie.build/Objects-normal/arm64/maggie.LinkFileList -Xlinker -rpath -Xlinker @executable_path/Frameworks -dead_strip -Xlinker -object_path_lto -Xlinker /Users/eamonwhite/Library/Developer/Xcode/DerivedData/maggie-govvbppylostlwaashtkbcuawqzc/Build/Intermediates.noindex/maggie.build/Debug-iphoneos/maggie.build/Objects-normal/arm64/maggie_lto.o -Xlinker -export_dynamic -Xlinker -no_deduplicate -fembed-bitcode-marker -fobjc-arc -fobjc-link-runtime -Xlinker -dependency_info -Xlinker /Users/eamonwhite/Library/Developer/Xcode/DerivedData/maggie-govvbppylostlwaashtkbcuawqzc/Build/Intermediates.noindex/maggie.build/Debug-iphoneos/maggie.build/Objects-normal/arm64/maggie_dependency_info.dat -o /Users/eamonwhite/Library/Developer/Xcode/DerivedData/maggie-govvbppylostlwaashtkbcuawqzc/Build/Products/Debug-iphoneos/maggie.app/maggie

duplicate symbol '_OBJC_CLASS_$_PersistentContainer' in: /Users/eamonwhite/Library/Developer/Xcode/DerivedData/maggie-govvbppylostlwaashtkbcuawqzc/Build/Intermediates.noindex/maggie.build/Debug-iphoneos/maggie.build/Objects-normal/arm64/AppDelegate.o /Users/eamonwhite/Library/Developer/Xcode/DerivedData/maggie-govvbppylostlwaashtkbcuawqzc/Build/Intermediates.noindex/maggie.build/Debug-iphoneos/maggie.build/Objects-normal/arm64/ViewController.o duplicate symbol '_OBJC_METACLASS_$_PersistentContainer' in: /Users/eamonwhite/Library/Developer/Xcode/DerivedData/maggie-govvbppylostlwaashtkbcuawqzc/Build/Intermediates.noindex/maggie.build/Debug-iphoneos/maggie.build/Objects-normal/arm64/AppDelegate.o /Users/eamonwhite/Library/Developer/Xcode/DerivedData/maggie-govvbppylostlwaashtkbcuawqzc/Build/Intermediates.noindex/maggie.build/Debug-iphoneos/maggie.build/Objects-normal/arm64/ViewController.o ld: 2 duplicate symbols for architecture arm64 clang: error: linker command failed with exit code 1 (use -v to see invocation)

At the bottom of the error it says which files are duplicated:

_OBJC_CLASS_$_PersistentContainer (a.k.a PersistentContainer.h, or a forward declaration of it, I'm not sure) _OBJC_METACLASS_$_PersistentContainer (again, I don't know what the difference between METACLASS and CLASS, I am assuming that the METACLASS is a forward declaration, like @class).

It appears, from the error, that this file is duplicated in both AppDelegate.o (a.k.a AppDelegate.h), and ViewController.o (compiled version of ViewController.h) - here are the relevant parts of those files:

AppDelegate.h:

#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@end

AppDelegate.m:

#import "AppDelegate.h"
#import "PersistentContainer.h"

@interface AppDelegate () 

@property (strong, nonatomic) NSManagedObjectContext* managedObjectContext;
@property (strong, nonatomic) NSPersistentStoreCoordinator* persistentStoreCoordinator;
@property (strong, nonatomic) NSPersistentStoreAsynchronousFetchResultCompletionBlock callback;
@property (nonatomic, strong) PersistentContainer *persistentContainer;

- (PersistentContainer*)persistentContainer;

@end

@implementation AppDelegate

...

ViewController.h:

#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>

@class PersistentContainer;

@protocol ViewControllerDelegate <NSObject>

- (PersistentContainer*)getPersistentContainer;

@end

@interface ViewController : UIViewController <CLLocationManagerDelegate, ViewControllerDelegate>

@property (weak, nonatomic) id<ViewControllerDelegate> delegate;

@end

ViewController.m:

#import "ViewController.h"
#import "HeaderCollection.h"
#import "PersistentContainer.h"

@interface ViewController ()

@property (nonatomic, strong) CLLocationManager* locationManager;
@property (nonatomic) UILabel* heading_label;
@property (nonatomic) UILabel* location_label;
@property (nonatomic) UILabel* loc_timestamp_label;
@property (nonatomic) UILabel* heading_accuracy_label;
@property (nonatomic) UILabel* mag_heading_label;
@property (nonatomic) UILabel* true_heading_label;
@property (nonatomic) UILabel* heading_timestamp_label;
@property (nonatomic) PersistentContainer* persistentContainer;

- (PersistentContainer*)getPersistentContainer;

@end

@implementation ViewController

...

HeaderCollection.h is not relevant, they are just the headers for a CoreData model.

Here is PersistentContainer.h:

#import <CoreData/CoreData.h>

@interface PersistentContainerProtocol : NSPersistentContainer

- (void)saveContext;

@end

@interface PersistentContainer : NSPersistentContainer

- (void)saveContext;

@end

@implementation PersistentContainer

- (void)saveContext {
    NSManagedObjectContext *context = [self viewContext];
    NSError *error = nil;
    if ([context hasChanges] && ![context save:&error]) {
        // Replace this implementation with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        NSLog(@"Unresolved error %@, %@", error, error.userInfo);
        abort();
    }
}

@end

There is no .m file for PersistentContainer - everything is in the header file.

I usually can get this kind of thing myself but this one has been irking me all day, time to ask for a fresh set of eyes, or a new strategy...thanks. Let me know if you need to see other files, I realize since this is a circular import problem, the problem might be in another file. Thanks.

1

1 Answers

1
votes

You actually spotted the cause of your problem:

There is no .m file for PersistentContainer - everything is in the header file.

You need to put the @implementation part in an .m file, otherwise all other source files that import PersistentContainer.h will re-implement the class, leading to the duplicate symbol definition. This because each import is equivalent to writing the same contents in the files that do the imports.

Unlike C++, where you are allowed to define parts of the class implementation in the header files, in Objective-C you must write all the implementation in implementation files.