Search code examples
iosobjective-cencapsulation

Encapsulation causing crash


I am trying to incorporate encapsulation into my app (for an explanation of what this code is supposed to do, see here)... this is the code in Class 'A':

.h file

@interface ExportBookData : NSObject {

@public NSArray *booksArray;
@public NSMutableDictionary *builtFileList;
@public NSMutableArray *exportData;
}

- (id)initWithCategory: (NSString*) booksellerID;

@end

This is the code for the .m file:

.m file

@implementation ExportBookData

-(id)initWithCategory: (NSString*) booksellerID  {

return (id)booksellerID;
}

@end

This is the beginning of the method in class 'B' (.m file) that uses the encapsulated data:

ExportBookData *abe = [[ExportBookData alloc] initWithCategory:@"ABE"];
abe->builtFileList = [NSMutableDictionary dictionary]; <- crash on this line
abe->exportData = [NSMutableArray arrayWithCapacity:abe->booksArray.count];

if(cbvABE.checked)  {

I'm getting the following error on the 2nd line of code as indicated:

enter image description here

Since I'm a noob using encapsulation, I don't see what I've done wrong. I have followed several examples which are similar to my code; what am I doing wrong to cause this crash?


Solution

  • So many issues here.

    First off, do not declare public instance variables. Use properties and only for values that you want other classes to have access to.

    @interface ExportBookData : NSObject
    
    @property(nonatomic, strong) NSArray *booksArray;
    @property(nonatomic, strong) NSMutableDictionary *builtFileList;
    @property(nonatomic, strong) NSMutableArray *exportData;
    
    - (id)initWithCategory: (NSString*) booksellerID;
    
    @end
    

    Now your ExportBooksData init method.

    It needs to be:

    -(id)initWithCategory: (NSString*) booksellerID  {
        self = [super init];
        if (self) {
            // do something with booksellerID
        }
    
        return self;
    }
    

    Every init method of a base class should following this general pattern.

    And now your other code is needlessly using -> operator. Use the actual properties provided by the interface instead:

    ExportBookData *abe = [[ExportBookData alloc] initWithCategory:@"ABE"];
    abe.builtFileList = [NSMutableDictionary dictionary];
    abe.exportData = [NSMutableArray arrayWithCapacity:booksArray.count];
    

    But it makes no sense that external code is doing all of this. Let your class set itself up as needed. So now your init method should be:

    -(id)initWithCategory: (NSString*) booksellerID  {
        self = [super init];
        if (self) {
            self.builtFileList = [NSMutableDictionary dictionary];
            self.exportData = [NSMutableArray arrayWithCapacity:booksArray.count];
    
            // do something with booksellerID
        }
    
        return self;
    }
    

    Now your other code simply becomes:

    ExportBookData *abe = [[ExportBookData alloc] initWithCategory:@"ABE"];
    

    without the need to set the other properties.

    There's a lot more you should be doing here (like making use of the booksellerID and booksArray) but this will get you started.