Small knowledge, big challenge! This paper is participating in theEssentials for programmers”Creative activities.
This paper also participates inProject DigginTo win the creative gift package and challenge the creative incentive money.
preface
This is probably the last article on extending generics in Objective-C.
You may already be aware of the ID type and have learned to use it without realizing it, but this may not be a very new discovery.
Let everyone laugh.
Pass the parameter with id
I don’t know if you’ve used OC’s reactive framework, but it’s ReactiveCocoa.
Although ReactiveCocoa has now been rewritten in Swift, prior to 3.0 it was written in OC.
Let’s look at a classic API comparison between the SUBSCRIBE method in ReactiveCocoa and the subscribe function in RxSwift:
The subscribe in ReactiveCocoa | Subscribe function in RxSwift |
---|---|
– (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock error:(void (^)(NSError *error))errorBlock; | public func subscribe(onNext: ((Element) -> Void)? = nil, onError: ((Swift.Error) -> Void)? = nil, onCompleted: (() -> Void)? = nil, onDisposed: (() -> Void)? = nil) -> Disposable |
Both methods illustrate the processing of a sequence subscription to next, error, and Completed.
In ReactiveCocoa, the id representation is used for the passed value in Next, while in RxSwift, the generic placeholder Element representation is used.
Id represents any dynamic NSObject object, and in the nearly everything object Cococa framework, passing values like this basically resolves the definition of parameter types in methods.
The API design principle of the framework is to be as abstract and unified as possible.
When we actually use the SUBSCRIBE function in ReactiveCocoa, we usually convert the ID type to a specific object type, like the following pseudocode:
[[Http Request] subscribeNext:^(NSString *personId) {
} error:^(NSError *error) {
}];
Copy the code
The [Http Request] method above is a network Request that returns a sequence, which is then subscribed to, Then subscribeNext:(void (^)(id x))nextBlock is converted to subscribeNext:(void (^)(NSString * x))nextBlock.
The code here is specifically similar to Swift converting Any to a concrete type via the AS keyword:
HttpRequest().subscribe(onNext: { id in
guard let some = id as? String else {
return
}
}, onError: { error in
}).disposed(by: rx.disposeBag)
Copy the code
Of course, in Swift we have generic constraints, and the data types passed are already agreed upon.
In OC, however, the conversion of an ID to a specific type is dangerous. If the type is wrong, the program will crash when it reads the value.
This is why I hate taking on projects in OC that use the ReactiveCocoa framework: because you don’t know the business, you might just see a bunch of ID types passing around, but you don’t know what they’re passing around.
In fact, at the end of the last section, I gave an example of a self-extending map function in NSArray. The closure that is passed is also of type ID (^)(ID). Because NSArray holds objects, the map should also be an ID.
Reference documentation
ReactiveCocoa
conclusion
Objective-c is an ancient language after all, and I think Apple is responsible for its success.
Although it does not have generics, the flexibility to use the dynamics of OC to unify object types by ID types is one way to do it in many weak languages.
If we do iOS development, at present, as long as we still use Cocoa framework, OC cannot be separated from OC, but it is still suggested to transfer to Swift for development.