SpokaneDude SpokaneDude - 22 days ago 5
iOS Question

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?

Answer

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.

Comments