0

I am having a bit of a problem with importing custom objects into my viewController.

I have created a Message Object that holds the json response from the server. I then created a MessageManager class, that does all of the network calls to the API.

MessageManager imports Message, to create the message object and pass it off to whatever class is using it.

I now have my viewController class, which #import both MessageManager and Message. so I can create an instance variable of Message. However I run into duplicate symbol errors with the compiler.

How do I get around this issue, and have the correct sequence of imports.

If i remove the Message.h from the viewcontroller, and remove any code referencing Message, it compiles normally.

Messages.h Which is returned by JSONModel and parses json object

#import <JSONModel/JSONModel.h>

@protocol Messages;
@interface Messages : JSONModel
@property (nonatomic) NSString<Optional>* id;
@property (nonatomic) NSString<Optional>* sender_id;
@property (nonatomic) NSString<Optional>* receiver_id;
@property (nonatomic) NSString<Optional>* user_user_id;
@property (nonatomic) NSString<Optional>* job_id;
@property (nonatomic) NSString<Optional>* file_id;
@property (nonatomic) NSString<Optional>* title;
@property (nonatomic) NSString<Optional>* replied;
@end






@protocol MessagesModel;
@interface MessagesModel : JSONModel
@property (nonatomic) NSString<Optional>* action;
@property (nonatomic) NSDate<Optional>* dateTime;
@property (nonatomic) NSString<Optional>* result;
@property (nonatomic) NSString<Optional>* numItems;
@property (nonatomic) NSArray <Messages>  *items;
@end

@implementation MessagesModel
+ (JSONKeyMapper *)keyMapper
{
    return [JSONKeyMapper mapperForSnakeCase];
}
@end

MessageViewController.h

#import <UIKit/UIKit.h>

@interface MessagesViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>

@property (strong, nonatomic) UISearchController *searchController;


@end

MessageViewController.m

#import "MessagesViewController.h"
#import "MessageTableViewCell.h"
#import "MessageThreadViewController.h"
#import "Messages.h" <--Need Messages Object to use Object and pass object around
#import "MessageManager.h"

@interface MessagesViewController () <UISearchBarDelegate, UISearchResultsUpdating, UIActionSheetDelegate, UISearchControllerDelegate>

@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (strong, nonatomic) NSArray *inbox;
@property (strong, nonatomic) NSArray *sent;
@property (strong, nonatomic) NSArray *deleted;
@property (strong, nonatomic) NSArray *temp;
@property (assign, nonatomic) NSInteger selectedBox;
@property (assign, nonatomic) NSInteger selectedMessage;
@property (strong, nonatomic) MessageManager *messageManager;
@property (weak, nonatomic) IBOutlet UISearchBar *searchbar;
@property (strong, nonatomic) Messages *messages;

@end

MessageManager.h

#import <Foundation/Foundation.h>
@interface MessageManager : NSObject


- (void)getReceivedMessagesListForReceiverID:(NSString*)receiverID success:(void (^)(NSArray *success))success failure:(void (^)(NSError *error))failure;
- (void)getSentMessagesListForSenderID:(NSString*)senderID success:(void (^)(NSArray *success))success failure:(void (^)(NSError *error))failure;
- (void)getDeletedMessagesListForMemberID:(NSString*)memberID success:(void (^)(NSArray *success))success failure:(void (^)(NSError *error))failure;
- (void)searchReceivedMessagesListForReceiverID:(NSString*)receuverID andKeyword:(NSString*)keyword success:(void (^)(NSArray *success))success failure:(void (^)(NSError *error))failure;
- (void)searchDeletedMessagesListForMemberID:(NSString*)memberID andKeyword:(NSString*)keyword success:(void (^)(NSArray *success))success failure:(void (^)(NSError *error))failure;
- (void)unreadMessagesCountForReceiverID:(NSString*)receiverID success:(void (^)(NSArray *success))success failure:(void (^)(NSError *error))failure;
- (void)sendMessageToReceiverID:(NSString*)receieverID ToSenderID:(NSString*)senderID withTitle:(NSString*)title andMessage:(NSString*)message success:(void (^)(NSArray *success))success failure:(void (^)(NSError *error))failure;
- (void)markMessageRead:(NSString*)messageID success:(void (^)(NSArray *success))success failure:(void (^)(NSError *error))failure;
- (void)markMessageUnRead:(NSString*)messageID success:(void (^)(NSArray *success))success failure:(void (^)(NSError *error))failure;
- (void)receivedListCountForReceivedID:(NSString*)receivedID success:(void (^)(NSArray *success))success failure:(void (^)(NSError *error))failure;
- (void)deletedMessagesListCountForMemberID:(NSString*)memberID success:(void (^)(NSArray *success))success failure:(void (^)(NSError *error))failure;
- (void)searchReceivedListCountForReceiverID:(NSString*)receiverID andKeyword:(NSString*)keyword success:(void (^)(NSArray *success))success failure:(void (^)(NSError *error))failure;
- (void)searchSentListCountForSender:(NSString*)senderID andKeyword:(NSString*)keyword success:(void (^)(NSArray *success))success failure:(void (^)(NSError *error))failure;
- (void)searchDeletedListCountForMemberID:(NSString*)memberID andKeyword:(NSString*)keyword success:(void (^)(NSArray *success))success failure:(void (^)(NSError *error))failure;
@end

MessageManager.m

#import "MessageManager.h"
#import "Constants.h"
#import <AFNetworking/AFNetworking.h>
#import "Messages.h" <--Need Messages Object to create Messages from response

@implementation MessageManager
...

Error

duplicate symbol _OBJC_IVAR_$_MessagesModel._result in:
    /Users/anthonytaylor/Library/Developer/Xcode/DerivedData/Build/Intermediates/Voices.com.build/Debug-iphonesimulator/Voices.com.build/Objects-normal/x86_64/MessagesViewController.o
    /Users/anthonytaylor/Library/Developer/Xcode/DerivedData/Build/Intermediates/Voices.com.build/Debug-iphonesimulator/Voices.com.build/Objects-normal/x86_64/MessageManager.o
duplicate symbol _OBJC_IVAR_$_MessagesModel._items in:
    /Users/anthonytaylor/Library/Developer/Xcode/DerivedData/Build/Intermediates/Voices.com.build/Debug-iphonesimulator/Voices.com.build/Objects-normal/x86_64/MessagesViewController.o
    /Users/anthonytaylor/Library/Developer/Xcode/DerivedData/Build/Intermediates/Voices.com.build/Debug-iphonesimulator/Voices.com.build/Objects-normal/x86_64/MessageManager.o
duplicate symbol _OBJC_IVAR_$_MessagesModel._numItems in:
    /Users/anthonytaylor/Library/Developer/Xcode/DerivedData/Build/Intermediates/Voices.com.build/Debug-iphonesimulator/Voices.com.build/Objects-normal/x86_64/MessagesViewController.o
    /Users/anthonytaylor/Library/Developer/Xcode/DerivedData/Build/Intermediates/Voices.com.build/Debug-iphonesimulator/Voices.com.build/Objects-normal/x86_64/MessageManager.o
duplicate symbol _OBJC_CLASS_$_Messages in:
    /Users/anthonytaylor/Library/Developer/Xcode/DerivedData/Build/Intermediates/Voices.com.build/Debug-iphonesimulator/Voices.com.build/Objects-normal/x86_64/MessagesViewController.o
    /Users/anthonytaylor/Library/Developer/Xcode/DerivedData/Build/Intermediates/Voices.com.build/Debug-iphonesimulator/Voices.com.build/Objects-normal/x86_64/MessageManager.o
duplicate symbol _OBJC_METACLASS_$_Messages in:
    /Users/anthonytaylor/Library/Developer/Xcode/DerivedData/Build/Intermediates/Voices.com.build/Debug-iphonesimulator/Voices.com.build/Objects-normal/x86_64/MessagesViewController.o
    /Users/anthonytaylor/Library/Developer/Xcode/DerivedData/Build/Intermediates/Voices.com.build/Debug-iphonesimulator/Voices.com.build/Objects-normal/x86_64/MessageManager.o
duplicate symbol _OBJC_IVAR_$_Messages._deleted_by_sender in:
    /Users/anthonytaylor/Library/Developer/Xcode/DerivedData/Build/Intermediates/Voices.com.build/Debug-iphonesimulator/Voices.com.build/Objects-normal/x86_64/MessagesViewController.o
    /Users/anthonytaylor/Library/Developer/Xcode/DerivedData/Build/Intermediates/Voices.com.build/Debug-iphonesimulator/Voices.com.build/Objects-normal/x86_64/MessageManager.o
duplicate symbol _OBJC_IVAR_$_MessagesModel._action in:
    /Users/anthonytaylor/Library/Developer/Xcode/DerivedData/Build/Intermediates/Voices.com.build/Debug-iphonesimulator/Voices.com.build/Objects-normal/x86_64/MessagesViewController.o
    /Users/anthonytaylor/Library/Developer/Xcode/DerivedData/Build/Intermediates/Voices.com.build/Debug-iphonesimulator/Voices.com.build/Objects-normal/x86_64/MessageManager.o
duplicate symbol _OBJC_IVAR_$_Messages._receiver_login in:
    /Users/anthonytaylor/Library/Developer/Xcode/DerivedData/Build/Intermediates/Voices.com.build/Debug-iphonesimulator/Voices.com.build/Objects-normal/x86_64/MessagesViewController.o
    /Users/anthonytaylor/Library/Developer/Xcode/DerivedData/Build/Intermediates/Voices.com.build/Debug-iphonesimulator/Voices.com.build/Objects-normal/x86_64/MessageManager.o
duplicate symbol _OBJC_IVAR_$_Messages._sender_login in:
    /Users/anthonytaylor/Library/Developer/Xcode/DerivedData/Build/Intermediates/Voices.com.build/Debug-iphonesimulator/Voices.com.build/Objects-normal/x86_64/MessagesViewController.o
    /Users/anthonytaylor/Library/Developer/Xcode/DerivedData/Build/Intermediates/Voices.com.build/Debug-iphonesimulator/Voices.com.build/Objects-normal/x86_64/MessageManager.o
...
Anthony Taylor
  • 3,073
  • 3
  • 21
  • 30
  • It sounds like you may have more inside Message.h than just declarations. Can you copy and paste the exact message that says which symbols are being duplicated into your question? – Phillip Mills Feb 07 '18 at 20:22
  • @PhillipMills added Message.h that is written with jsonModel – Anthony Taylor Feb 07 '18 at 20:27
  • 6
    Don't put `@implementation` stuff in .h files. Ever! :) Implementations go in the .m. – Phillip Mills Feb 07 '18 at 20:28
  • The JSONModel tutorials all show doing the @implementation in the header, and not needing the .m files at all. – Anthony Taylor Feb 07 '18 at 20:32
  • 1
    Well, you can do as you like but I suggest moving those few lines into a .m file and seeing whether your duplicate symbol error goes away. – Phillip Mills Feb 07 '18 at 20:36
  • It just seems to complain that MessageViewController and MessageManager both import Message.h Then MessageViewController imports MessageManager How do I use Message.h in the VC – Anthony Taylor Feb 07 '18 at 20:47
  • Look at https://code.tutsplus.com/tutorials/beyond-the-basics-of-jsonmodel--cms-20731 and search for the phrase "Open PhotoModel.m". It shows something that seems reasonable to me. – Phillip Mills Feb 07 '18 at 20:49
  • You can import a header as many times as you want as long as the header only declares symbols and doesn't actually define them. – Phillip Mills Feb 07 '18 at 20:51
  • check that you dont have any files duplicates in your build phases > compile sources list. I had this issue a few times now and that has solved it for me – Scriptable Feb 12 '18 at 14:22
  • Compiler is usually good at telling you what is duplicate and in what place. Would you mind to share this info as well? Generally, you have something defined (not declared) in .h file that you are importing to other places. Error message from compiler tells you exactly what and where. – Juraj Antas Feb 14 '18 at 10:31
  • @JurajAntas added more info – Anthony Taylor Feb 14 '18 at 17:00
  • So I think it is clear, right? You are using Messages.h in two places, and it does have implementation section. So you get duplicities. Solution could be: import it just once (I wonder if importing it to precompiled header (.pch) would help) You should test it. Might be easy way out. Or move implementation to .m file and you can import as many times you wish. – Juraj Antas Feb 15 '18 at 13:57

1 Answers1

2

Based on the files you've mentioned in the question, you only have the Messages.h file in your project and do not have the Messages.m file, instead have the implementation declared in the header file, am I right? I was able to replicate your duplicate symbols error on the example project I found here by copying the classes from your question. But when I created a Messages.m file with the implementation of both Messages and MessageManager classes, the duplicate symbols compiler error disappeared, and I was able to create an instance of the MessageManager class.

With that said, I'm not sure what you mean by

The JSONModel tutorials all show doing the @implementation in the header, and not needing the .m files at all.

comment, but according to JSONModel's Github readme page, they say:

There's no need to do anything in the implementation (.m) file.

This probably doesn't mean that you don't need to have the .m file. Its a good practice anyway to have both .h and .m files for a class since the Compile Sources option under the Build Phases tab of your Xcode project's target only has the .m files files. This is what tells the compiler which source files should be compiled while building a target. Since you declared the implementation inside the .h file, the compiler can't find it at build time.

Here's a screenshot of the example Xcode project I setup:

Screenshot of the Xcode project setup

MessageManager.h file

#import <Foundation/Foundation.h>
@class MessagesModel;

@interface MessageManager : NSObject

+ (MessagesModel *)getMessages;

@end

MessageManager.m file:

#import "MessageManager.h"
#import "Messages.h" //<-- Imported here

@implementation MessageManager

+ (MessagesModel *)getMessages {
    NSError *error = nil;
    NSDictionary *dictionary = @{@"action": @"replied",
                                 @"dateTime": @"",
                                 @"result": @"success",
                                 @"numItems": @"1",
                                 @"items": @[@{@"id": @"1",
                                               @"sender_id": @"2",
                                               @"receiver_id": @"3",
                                               @"user_user_id": @"4",
                                               @"job_id": @"5",
                                               @"file_id": @"6",
                                               @"title": @"Hello world",
                                               @"replied" : @"7"}]};
    MessagesModel *messages = [[MessagesModel alloc] initWithDictionary:dictionary error:&error];
    if (error)
        NSLog(@"Oops!");

    return messages;
}

@end

Messages.h file:

#import <JSONModel/JSONModel.h>

@protocol Messages;
@interface Messages : JSONModel
@property (nonatomic) NSString<Optional>* id;
@property (nonatomic) NSString<Optional>* sender_id;
@property (nonatomic) NSString<Optional>* receiver_id;
@property (nonatomic) NSString<Optional>* user_user_id;
@property (nonatomic) NSString<Optional>* job_id;
@property (nonatomic) NSString<Optional>* file_id;
@property (nonatomic) NSString<Optional>* title;
@property (nonatomic) NSString<Optional>* replied;
@end


@protocol MessagesModel;
@interface MessagesModel : JSONModel
@property (nonatomic) NSString<Optional>* action;
@property (nonatomic) NSDate<Optional>* dateTime;
@property (nonatomic) NSString<Optional>* result;
@property (nonatomic) NSString<Optional>* numItems;
@property (nonatomic, strong) NSArray <Messages>  *items;
@end

Messages.m file:

#import "Messages.h"

@implementation Messages

@end

@implementation MessagesModel

+ (JSONKeyMapper *)keyMapper {
    return [JSONKeyMapper mapperForSnakeCase];
}

@end

ViewController.m file:

#import "ViewController.h"
#import "MessageManager.h"
#import "Messages.h" //<-- Imported here

@interface ViewController ()

@property (strong, nonatomic) MessagesModel *messagesModel;
@property (weak, nonatomic) NSArray<Messages *> *messages;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.messagesModel = [MessageManager getMessages];
    self.messages = self.messagesModel.items;
    NSLog(@"%@", self.messages);
}

@end

And finally, the output: LLDB Output

Let me know if you want me to upload the Xcode project in case you want to examine the setup.

Hope this helps.

Pranay
  • 846
  • 6
  • 10