OBJC and Duck object (upper)

Source: Internet
Author: User

This is the upper part of "OBJC and Duck Object", "ObjC and Duck object (bottom)" introduced the duck type of advanced usage, Dependency injection and demo.

I'm the preface.


鸭子类型(Duck Type) that is:"When you see a bird walking like a duck, swimming like a duck, and barking like a duck, then this bird can be called a duck", the Program Ape language is:"When the caller knows what method this object can invoke, What kind of an instance of this object is it? " This paper makes a simple study of duck type object in OBJC, and uses the magic of this idea in a small demo of "using only one class to implement JSON Entity". Please look at the lower part of the advanced article.

OBJC and Duck type ID type is a big duck.

Duck type is the characteristic of dynamic language, and does not determine the function call relationship at compile time, so all type declarations are given to the compiler. OBJC has found a good balance between dynamic and static, preserving strict static checks and not destroying the dynamic characteristics of the runtime.
We know that sending a message to a OBJC object (or Class) is actually isa looking for a real function address along its pointer, so that if an object satisfies the structure below, it can send a message to it:

struct Objc_object {
Class Isa;
} *ID;

Known as the id type, OBJC supports this basic duck type at the language level, and we can convert any object to an ID type to send a message to it, even if it doesn't respond to the message, and the compiler doesn't know it.
As the short definition of the OBJC object in this article: The best definition for a Smalltalk or Objective-C "object" is "something that can respond to messages. object is not necessarily an instance of a particular type, as long as it responds to the required message.

From @interface to @protocol

As OBJC's innate support for dynamic id types, the @protocol duck type provides a compile-time strong typing check that implements the classic duck type usage scenario in cocoa:

@property (ID <uitableviewdatasource> dataSource;
@property (ID <uitableviewdelegate> delegate;

The use of duck type design interface will give users greater flexibility. And @protocol can be used to build 伪继承 relationships.

uiscrollviewdelegate<nsobject>
uitableviewdelegate<uiscrollviewdelegate>

<NSObject>The existence of the Protocol is on the one hand given to NSProxy other root classes such as the Duck protocol type a root type, as given to most classes a nsobject root class. To say an episode, because the OBJC class is also id type, id<UITableViewDataSource> the shape of the duck type can be used as class object to play, only need to replace the instance method into a class method, such as:

DataSource
+ (Nsinteger) Numberofsectionsintableview: (UITableView *) TableView {
0;
}
+ (Nsinteger) TableView: (uitableview *) TableView numberofrowsinsection: (nsinteger) Section {
0;
}
@end

Set the data source for table view:

Self.tableView.dataSource = (class<uitableviewdatasource>) [DataSource Class];

This non-mainstream writing is legitimate and functioning properly, thanks to the OBJC Plus and minus methods are not reflected in the, but also in the form of a @selector @protocol fake, this code I believe no one really write, but it does reflect the flexibility of duck type.

[Demo] A class implements JSON Entity

Entityobject represents the structure of a pure data , such as:

  @interface xxuserentity: nsobject 
@ Property (nonatomic, copy) nsstring *name;
@property (nonatomic, copy) nsstring *sex;
@property (nonatomic, Assign) nsinteger age;
//Balabala ....
@end

In real-world development, this class often corresponds to a JSON string returned by the server, such as:

{"Name": "Sunnyxx", "Sex": "Boy", "age": 24, ...}

Parsing these mappings is a purely repetitive work, building classes, writing properties, parsing ... Now there are jsonmodel,mantle and other good frameworks to help. This demo we are going to use the duck type idea to redesign, to simplify these entity classes into a duck class.

Because of the above UserEntity class, only the getter and setter of the property, this corresponds to the NSMutableDictionary objectForKey: and setObjectForKey: , at the same time, the JSON data will be parsed into a dictionary, which completes the clever docking, the following to implement this class.

The real work is a dictionary that guarantees encapsulation and purity, and this class is used directly NSProxy as a purely proxy class, exposing only one initialization method:

 //XXDuckEntity.h 
@interface xxduckentity: Nsproxy
-(instancetype) initwithjsonstring: ( nsstring *) JSON;
@end
//xxduckentity.m
@interface xxduckentity ()
@property (nonatomic, Strong) nsmutabledictionary *innerdictionary;
@end

The

nsproxy defaults to no initialization method, and eliminates the hassle of avoiding other initialization methods, and the JSON string is unpacked to a dictionary for simple direct initialization (the JSON is an array, for the time being):

-(instancetype) initwithjsonstring: (NSString *) JSON 
{
nsdata *data = [JSON datausingencoding:< Span class= "built_in" >nsutf8stringencoding];
id jsonobject = [nsjsonserialization Jsonobjectwithdata:data options:nsjsonreadingallowfragments error: NIL];
if ([Jsonobject iskindofclass:[nsdictionary Class]] {
self.innerdictionary = [Jsonobject mutablecopy];
return self;

/span>

NSProxyIt can be said that in addition to the overload message forwarding mechanism, there is no other usage, this is the original intention of it was designed to do nothing, to the proxy object is good. To this proxy message is destined to go the message forwarded, first judge is not a getter or setter of the selector:

- (Nsmethodsignature *) Methodsignatureforselector: (SEL) Aselector
{
SEL changedselector = Aselector;
if ([selfpropertynamescanfromgetterselector:aselector]) {
Changedselector = @selector (objectforkey:);
}
Else if ([selfpropertynamescanfromsetterselector:aselector]) {
Changedselector = @selector (setobject:forkey:);
}
return [[Self.innerdictionary class] instancemethodsignatureforselector:changedselector];
}

The signature is replaced with a dictionary of two methods after starting to go forward, where parameters are set and the real call to the internal dictionary:

- (void) Forwardinvocation: (Nsinvocation *) Invocation
{
NSString *propertyname =Nil
Try Getter
PropertyName = [Self PropertyNameScanFromGetterSelector:invocation.selector];
if (PropertyName) {
Invocation.selector =@selector (objectforkey:);
[Invocation setargument:&propertyname Atindex:2];Self, _cmd, key
[Invocation Invokewithtarget:Self.innerdictionary];
return;
//Try setters
propertyname = [self propertyNameScanFromSetterSelector:invocation.selector];
if (propertyname) {
Invocation.selector = @selector (setobject:forkey:);
[invocation setargument:&propertyname Atindex:3]; //self, _cmd, obj, key
[invocation invokewithtarget: self.innerdictionary];
return;
[super forwardinvocation:invocation];

/span>

And, of course, these two essential helpers to get property names from getter and setter:

- (NSString *) Propertynamescanfromgetterselector: (SEL) Selector
{
NSString *selectorname =Nsstringfromselector (selector);
Nsuinteger parametercount = [[Selectorname componentsseparatedbystring:@ ":"] count]-1;
if (Parametercount = =0) {
return selectorname;
}
ReturnNil
}
- (NSString *) Propertynamescanfromsetterselector: (SEL) Selector
{
NSString *selectorname =Nsstringfromselector (selector);
nsuinteger parametercount = [[Selectorname componentsseparatedbystring:< Span class= "string" >@ ":"] count]-1;
if ([Selectorname hasprefix:@ "set"] && Parametercount = = 1) {
nsuinteger Firstcolonlocation = [Selectorname rangeofstring:@ ":"].location;
return [selectorname substringwithrange: Nsmakerange (3, firstcolonlocation-3)].lowercasestring;
return nil;

/span>

A simple duck entity is completed, and then all the entity can be defined in a way that is @protocol not subclass, such as:

@protocolXxuserentity <Nsobject>
@property (Nonatomic,CopyNSString *name;
@property (nonatomic, copy) nsstring *sex;
@property (nonatomic, Strong) nsnumber *age;
@protocol xxstudententity <XXUSERENTITY>
@property (nonatomic, copy) nsstring *school;
@property (nonatomic, copy) nsstring *teacher;
@end

When the data comes back from the network layer, the duck type makes this object as good as it really is:

-(void) requestfinished: (xxduckentity<xxstudententity> *) Student {
NSLog (@ "name:%@, school:%@", Student.name, Student.school);
}

At this point, all the entity is represented as n <Protocol> .h files plus a XXDuckEntity class, and the rest depends on the imagination.
This demo's source code will be given after the next half

http://blog.sunnyxx.com/2014/08/24/objc-duck/

OBJC and Duck object (upper)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.