Interface and setter, getter

Time:2020-3-26

The previous article said that we can add convenient implementation to our daily work through the category feature of objc. In this article, I want to share some thoughts with you from the perspective of language design.

Don’t ignore interface

Objc’s @ interface design is really similar to Java and C ා, but slightly different. Java and C ා, by contrast, are like a mold. The characteristics of objc are very obvious. First of all, it is generally unnecessary to write@privateand@publicTo distinguish private variables, most objc developers do not even know that there are two keywords. In fact, this design has not been used in cocoa source code, even if objc supports it.

<!–more–>

Use @ private and @ public in @ interface

@interface Student : NSObject
{
    @private
    NSString* _name;
    @public
    NSNumber* _age;
    int _height;
}
@end

In the above code,StudentThere is a private variable_name, and two common variables_age_heightBut in@interfaceIt must not be the original intention of cocoa designers to declare variables in. Here are two considerations.

First, exposing the internal variables directly will reduce the stability of the whole framework, because increasing the coupling between different modules will reduce the cohesion of each class.
Second, the variable name of internal variable is easy to conflict with the variable name of local variable. In the above example, I underlined each variable name to prevent this problem.

So looking at the header file design of cocoa framework, there is basically no such code, because the designer provides a better way to implement, that is, we use more@propertyKeyword.

If you use @ property to declare the above classes, you are familiar with it

@interface Student : NSObject

@property (nonatomic, strong) NSString* name;
@property (nonatomic, strong) NSNumber* age;
@property (nonatomic, assign) NSInteger height;

@end

@The design of property is really interesting. First of all, we don’t distinguish between private and public properties, because as long as we write.hThe @ property in it is shared by us by default. The private @ property can be written in the.mIn the document.

Secondly, with the @ synthesize keyword written in @ implementation, setter and getter methods can be generated automatically. Now @ synthesize keyword can be omitted, except for the need to modify the internal variable name in some cases.

@implementation Student
@synthesize name = _name;
@synthesize age = __age;
@end

The first one of the above @ synthesize can be omitted. Without writing, the compile preprocessing will automatically add @ synthesize code. So even if there is no synthesize height property, we still implement its setter and getter methods

//These two methods can be overridden

- (void)setHeight:(NSInteger)height
{
    _height = height;
}

- (NSInteger)height
{
    return _height;
}

When both setter and getter methods are overridden, @ synthesize needs to be added manually.

@synthesize height = _height;

Why use setter and getter

setterandgetterThe design of is really worth pondering. We mainly analyze from the following points:

Setter and getter wrap the internal variables. The whole class can only expose the interface externally to enhance the cohesion of the class.

For example, the internal variable in the above example_name, external classes cannot operate. Messages can only be sent through the set and get interfaces:

Student* s = [[Student alloc] init];

[s setName:@"Tom"];
[s name];

By implementing the getter method, we can avoid the timing problem of initializing variables

This is also a very practical point, because the message design mechanism of objc makes it difficult for objc to pass in too many parameters in the init method (in addition, I extended dependency injection for objc, see IOS implementation dependency injection for details). Therefore, the default attribute of the new instance, where to implement it, is a problem that we must have encountered.

For example, the most commonUIViewController, code initializationinitMethod, and go through storyboard strengthinitWithCoderMethod, some container properties, can be initialized by getter method to avoid the problem caused by the first call that has not been initialized.

The early cocoanilSending a message will cause an exception. The current version does not throw an exception to an object without an alloc, so that sometimes the problem caused by the property not being initialized becomes more hidden. However, overriding the getter method can effectively avoid this problem, for example:

// class class
@interface XXClass : NSObject
@Property (nonatomic, strong) nsmutablearray * students; // students
@end

@implementation

//Implement the getter method to initialize the internal variable "students" if it is not initialized
- (NSMutableArray *)students
{
    if (!_students) {
        _students = [NSMutableArray array];
    }
    return _students;
}

@end

In this way, the first time at any time[self students]Internal variable when message_studentsWill be initialized.

Note another point here. In the class, do not use internal variables directly outside the setter and getter methods. It will benefit a lot to abide by this rule.

Setter and getter can be used separately or separated from internal variables

What we want to say here is the flexibility of @ property. As you know, @ property has a series of modifiers, except for the commonly used onesNonatomic (non atomic, thread safe)Strong (strong reference type)Weak (weak reference type)Assign (assignment, for non object properties)Besides, there areReadonlyandReadwrite (read write)Two properties that affect setter and getter methods,readonlyDecorated property, only getter method and no setter method.

readwriteIt is a modifier that looks dispensable, because it is read and write by default. However, it has a specially designed usage, that is, in the interface of. HreadonlyWhen redeclared in another category or anonymous category of this class, modify its read-write restrictions, such as

// class class
@interface XXClass : NSObject
@Property (nonatomic, strong, readonly) nsmutablearray * students; // students
@end
//Anonymous category
@interface XXClass()
@property (nonatomic, strong, readwrite) NSMutableArray* students;
@end

In this way, because anonymous classes are usually written in. M files (I haven’t seen them written in. H files), external users can’t call themstudentsProperty, andXXClassClass can be used internally.

Another common situation is to use setter and getter to simulate property (@ property), for example:

// class class
@interface XXClass : NSObject
@Property (nonatomic, strong, readonly) nsmutablearray * students; // students
@Property (nonatomic, assign, readonly) nsuinteger studentscount; // number of students
@end
- (NSUInteger)studentsCount
{
    return self.students.count;
}

TherestudentsCountThere is no internal variable. The property interface is created by getter method.

Summary

This article is a part of objc’s interface design pattern. It is written in detail to help novices get started, bring some thoughts to experienced friends, and lead to the following content.

Recommended Today

Talk about Flink’s tablefunction

order This paper mainly studies the table function of Flink example // The generic type “Tuple2<String, Integer>” determines the schema of the returned table as (String, Integer). public class Split extends TableFunction<Tuple2<String, Integer>> { private String separator = ” “; public Split(String separator) { this.separator = separator; } public void eval(String str) { for (String […]