Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can we put IBOutlets in a category?

Since the ViewController's code is getting too large, I was wondering how to split the code into multiple files. Here's the problem I ran into:

// In the original .m file, there are bunch of outlets in the interface extension.
@interface aViewController()
@property (weak, nonatomic) IBOutlet UIView *contentView1;
@property (weak, nonatomic) IBOutlet UIView *contentView2;
@property (weak, nonatomic) IBOutlet UIView *contentView3;
@end

I want to split the file into 3 categories, according to three different views.

// In category aViewController+contentView1.m file
@interface aViewController()
@property (weak, nonatomic) IBOutlet UIView *contentView1;
@end

If I delete the original contentView1 outlet, however, it doesn't work.

Question
Why do I have to keep the contentView1 outlet in the original .m file?

like image 655
Kyle Fang Avatar asked Dec 28 '25 07:12

Kyle Fang


1 Answers

An Objective-C category doesn't allow you to add additional properties to a class, only methods. Thereby, you aren't allowed to add additional IBOutlets within a category. A category is denoted similar to @interface aViewController (MyCategoryName) (note the name given inside the parentheses).

You can, however, add additional properties within a class extension. A class extension is denoted with the same name as the original class followed by (). In your code example, both lines referring to @interface aViewController() actually declare a class extension (not a category), regardless of which header file they're actually in.

Furthermore, you are allowed to create multiple class extensions across several different headers. The trick is that you need to import these correctly.

In example, let's consider a class called ViewController. We want to create ViewController+Private.h and ViewController+Private2.h that have additional privateView outlets, which will still be accessible within ViewController.m.

Here's how we can do it:

ViewController.h

// Nothing special here

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
// some public properties go here
@end

ViewController+Private.h

// Note that we import the public header file
#import "ViewController.h"

@interface ViewController()
@property (nonatomic, weak) IBOutlet UIView *privateView;
@end

ViewController+Private2.h

// Note again we import the public header file
#import "ViewController.h"

@interface ViewController()
@property (nonatomic, weak) IBOutlet UIView *privateView2;
@end

ViewController.m

// Here's where the magic is
// We import each of the class extensions in the implementation file
#import "ViewController.h"
#import "ViewController+Private.h"
#import "ViewController+Private2.h"

@implementation ViewController

// We can also setup a basic test to make sure it's working.
// Just also make sure your IBOutlets are actually hooked up in Interface Builder

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.privateView.backgroundColor = [UIColor redColor];
    self.privateView2.backgroundColor = [UIColor greenColor];
}

@end

And that's how we can do it.

Why Your Code Wasn't Working

Most likely, you've probably mixed up the #import statements. To fix this,

1) Make sure that each class extension file imports the original class header (i.e. ViewController.h)

2) Make sure that the class implementation (i.e. ViewController.m) file imports each of the class extension headers.

3) Make sure the class header (i.e. ViewController.h) file doesn't import any of the class extension headers.

For reference, you can also checkout the Apple docs on Customizing Existing Classes.

like image 179
JRG-Developer Avatar answered Dec 30 '25 21:12

JRG-Developer



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!