kaylanx
kaylanx

Reputation: 908

How to conform to Objective-C protocol with readonly properties in Swift

We're currently using this library in our project... https://github.com/OliverLetterer/SLExpandableTableView

How would one go about conforming to the UIExpandingTableViewCell protocol in Swift?

Here is a copy...

typedef enum {
    UIExpansionStyleCollapsed = 0,
    UIExpansionStyleExpanded
} UIExpansionStyle;

@protocol UIExpandingTableViewCell <NSObject>

@property (nonatomic, assign, getter = isLoading) BOOL loading;

@property (nonatomic, readonly) UIExpansionStyle expansionStyle;
- (void)setExpansionStyle:(UIExpansionStyle)style animated:(BOOL)animated;

@end

I've tried the following but still says it doesn't conform to it...

class SectionHeaderCell: UITableViewCell, UIExpandingTableViewCell {

    @objc var loading: Bool
    @objc private(set) var expansionStyle: UIExpansionStyle

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
    }

    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func setExpansionStyle(style: UIExpansionStyle, animated: Bool) {


    }
}

Is it because of the way UIExpansionStyle is defined without using NS_ENUM?

confused

Upvotes: 4

Views: 1175

Answers (1)

SwiftArchitect
SwiftArchitect

Reputation: 48542

Short Answer

Use something in the spirit of:

var loading:Bool {
    @objc(isLoading) get {
        return self._isLoading
    }
    set(newValue){
        _isLoading = newValue
    }
}

Long Answer

Create a new, fresh project, do a pod init, add a Podfile similar to the one below, and run pod install.

platform :ios, '8.0'
target 'SO-32254051' do
pod 'SLExpandableTableView'
end

Using Objective-C Named Properties Attribute in Swift

As read in the developer.apple.com documentation:

Use the @objc(<#name#>) attribute to provide Objective-C names for properties and methods when necessary.

The conforming issue is about just that: custom getter name.

Complete Solution

Adopt protocol

class TableViewCell: UITableViewCell, UIExpandingTableViewCell { ... }

Define local storage

var _isLoading:Bool = false
var _expansionStyle:UIExpansionStyle = UIExpansionStyle(0)

Implement named getter and setters

var loading:Bool {
    @objc(isLoading) get {
        return self._isLoading
    }
    set(newValue){
        _isLoading = newValue
    }
}

private(set) var expansionStyle:UIExpansionStyle {
    get{
        return _expansionStyle
    }
    set(newValue){
        _expansionStyle = newValue
    }
}

func setExpansionStyle(style: UIExpansionStyle, animated: Bool) {
    self.expansionStyle = style
    // ...
}

Using Enum shorthand

You also mention Is it because of the way UIExpansionStyle is defined without using NS_ENUM? in your question. That is actually a different problem entirely, one you could easily fix in the library and do a git push and pull request for.

Since the enum is not defined as bellow, you cannot use the .Collapsed shorthand.

typedef NS_ENUM(NSUInteger, UIExpansionStyle) {
    UIExpansionStyleCollapsed = 0,
    UIExpansionStyleExpanded
};

and subsequently do this in Swift:

var _expansionStyle:UIExpansionStyle = UIExpansionStyle.Collapsed

Compiled, linked, built & ran.

Upvotes: 1

Related Questions