A clean code

Source: Internet
Author: User

Reprinted from: HTTP://WWW.JIANSHU.COM/P/2DB0E6B6ECDB

Recently in review the entire project code, because the code is very large, the number of people involved in the development, so the code is not written in many places concise. Here is a summary of some code snippets to simplify the code.

1, let the TableView unnecessary cell is not visible.
The original implementation:
Add an empty Footerview to the TableView. But when this requirement is needed in many places, similar code repeats itself.

UIView *view = [UIView new];view.backgroundColor = [UIColor clearColor];[tableView setTableFooterView:view];

An improved implementation:
Add a uitableview category so that only one line is needed where it is called.

@implementation UITableView(Addtions)- (void)hideEmptyCells{    UIView *view = [UIView new];    view.backgroundColor = [UIColor clearColor];    [self setTableFooterView:view];}

Use

[self.tableView hideEmptyCells];

2, let TableView cell separation line between the left spacing of 0
This problem is iOS7 after the emergence of iOS7 solution to the iOS8 and problems, so every time to use the TableView, to TableView set a will, but also to Tableviewcell set again, code a lot of scattered.

//设置tableViewif ([self.tableView respondsToSelector:@selector(setSeparatorInset:)]) {    [self.tableView setSeparatorInset:UIEdgeInsetsZero];}if ([self.tableView respondsToSelector:@selector(setLayoutMargins:)]) {    [self.tableView setLayoutMargins:UIEdgeInsetsZero];}//设置tableviewcellif ([cell respondsToSelector:@selector(setSeparatorInset:)]) {    [cell setSeparatorInset:UIEdgeInsetsZero];}if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {    [cell setLayoutMargins:UIEdgeInsetsZero];}

An improved implementation:
Add a category method to UITableView and UITableViewCell:

//UITableView- (void)hideSeparatorLeftInset{    if ([self respondsToSelector:@selector(setSeparatorInset:)])    {        [self setSeparatorInset:UIEdgeInsetsZero];    }    if ([self respondsToSelector:@selector(setLayoutMargins:)])    {        [self setLayoutMargins:UIEdgeInsetsZero];    }}//UITableViewCell- (void)hideSeparatorLeftInset{    if ([self respondsToSelector:@selector(setLayoutMargins:)]) {        [self setLayoutMargins:UIEdgeInsetsZero];    }}

Then it's OK to call the UITableView and UITableViewCell where they were created.

//创建Table_newsTable = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT - 64 -49) style:UITableViewStylePlain];_newsTable.delegate = self;_newsTable.dataSource = self;[_newsTable hideSeparatorLeftInset];//创建Cellif (cell == nil) {    cell = [[FindBigImageTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleCell];    [cell setSelectionStyle:UITableViewCellSelectionStyleNone];    [cell hideSeparatorLeftInset];}

The benefits of doing this:

    • The code is simple, just one line. Because in many similar pages there will be duplicated code, so different people write often inconsistent, causing the bug.
    • After the API upgrade, just change a place, do not need to find the code and then modify.

Summary: When you write code, you need to copy and paste the time, there must be no encapsulation. Think about whether you can use the Util method and category to abstract, the invariant stripping out, the formation of a new method, which is better than copying and pasting too much.

3, the package of network request
The current code in the network request, is based on HTTP, mainly divided into the following several processes:
1. Set Request parameters
2. Call the encapsulated HTTP method to make the request
3, the processing of the results of the Qing seeking
Typical usage is as follows:

 mbprogresshud* hudprogress; __block int result; Hudprogress = [[Mbprogresshud alloc] initwithwindow:[uiapplication Sharedapplication].keywindow]; Hudprogress.labeltext = @ "XXX"; Apipackagelogingoheader *gohead = [[Apipackagelogingoheader alloc]init]; Apipackageloginbackheader *backhead = [[Apipackageloginbackheader alloc]init];gohead.loame = @ "XXXX"; GoHead.paord = @ " XXXX "; gohead.surce = @" Xxxxgohead.sin = @ "xxxx"; Gohead.versno = @ "xxxx"; [Gohead Makedictionary]; Nsmutabledictionary *dicback = [[Nsmutabledictionary alloc]init]; [hudprogress showanimated:no whileexecutingblock:^{result = [Gmpostserver getserverback:server_login path_Param:nil Q    Uery_Param:goHead.dicGo Body_param:nil Method:gm_network_method_post Returnvalue:dicback];     [Backhead Getbodydataitems:dicback];        }completionblock:^{if (result = = gm_postback_success) {[Userinfoentity Shareentity].pne = backhead.ph;        [Userinfoentity shareentity].niame = Backhead.name; [Userinfoentity Shareentity].hasLogin = YES;        [Userinfoentity Shareentity].userid = [NSString stringwithformat:@ "%@", Backhead.userid];         [Userinfoentity shareentity].state = backhead.state; if ([Launchoptions objectforkey:@ "Uiapplicationlaunchoptionsremotenotificationkey"]! = nil) {Self.pushinfo =             [Launchoptions objectforkey:@ "Uiapplicationlaunchoptionsremotenotificationkey"];             Basichomeviewcontroller *BASICVC = (basichomeviewcontroller*) Self.window.rootViewController; Uinavigationcontroller *viewcontroller = (Uinavigationcontroller *) [[BasicVc.tabbar.buttonData Objectatindex:             BasicVc.tabbar.selectIndex] Viewcontroller];             [Viewcontroller Dismissviewcontrolleranimated:no Completion:nil];             [[Pusheventmanager sharedinstance] PushEvent:self.pushInfo Target:viewcontroller];             [Apservice setbadge:0];            [UIApplication sharedapplication].applicationiconbadgenumber = 0;     } [self requestuserinfo];   } else  {showerromsg (backhead.errormsg); }}];

The above code is the user login, inside the Viewcontroller, there is a big feature: long. It also sets up parameter preparation, requests, requests for results processing, and UI coupling.
Imagine that the user login is not only in one interface, if there are multiple places in the situation, this piece of code will appear multiple times, and the approximate structure is similar? Only the parameter value and the processing logic of success failure is not the same, then the rest of the fixed logic: parameter copy, HUD, request put into a method:

+ (void) Userloginwithusername: (nsstring*) userName password: (nsstring*) password su Ccess: (void (^) (apipackageloginbackheader*)) Sucblock failure: (void (^) (apipackageloginbackheader*)) fail                       Block animated: (BOOL) animated Loadingtext: (nsstring*) Loadingtext InView: (uiview*) Containerview;    {mbprogresshud* hudprogress;    __block Nsinteger result;    Hudprogress = [[Mbprogresshud alloc] initwithwindow:[uiapplication Sharedapplication].keywindow];        if (animated) {[Containerview addsubview:hudprogress];        [Containerview bringsubviewtofront:hudprogress];    Hudprogress.labeltext = Loadingtext;    } apipackagelogingoheader *gohead = [[Apipackagelogingoheader alloc]init];    Apipackageloginbackheader *backhead = [[Apipackageloginbackheader alloc]init];    Gohead.logame = UserName;    Gohead.pard = password;    Gohead.sodde = @ "iphone";  GOHEAD.SWN = @ "ios";  Gohead.versdddo = [Lcsystemutil appversion];    [Gohead Makedictionary];    Nsmutabledictionary *dicback = [[Nsmutabledictionary alloc]init]; [hudprogress showanimated:animated whileexecutingblock:^{result = [Gmpostserver getserverback:server_login path_Pa        Ram:nil query_Param:goHead.dicGo body_param:nil method:gm_network_method_post Returnvalue:dicback];    [Backhead Getbodydataitems:dicback]; }completionblock:^{if (result = = gm_postback_success) {[Userinfoentity Shareentity].phone = BAC            khead.pe;            [Userinfoentity shareentity].nikename = Backhead.niccdame;            [Userinfoentity shareentity].haslogin = YES;            [Userinfoentity Shareentity].userid = [NSString stringwithformat:@ "%@", Backhead.uddrid];            [Userinfoentity shareentity].state = BACKHEAD.STCDE;            if (sucblock) {sucblock (backhead); }} else {if (failblock) {Failblock (BackheAD); }        }    }];}

External calls, as long as one line of code:

[HJUserProvider userLoginWithUserName:userName                                 password:password                                  success:^(APIPackageLoginBackHeader *backHeader) {                                    [self backButtonPressed:nil];                                    [HJUserProvider requestUserInfoWithSuccess:nil failure:nil];                                  }                                  failure:^(APIPackageLoginBackHeader *backHeader) {                                    [HJUIUtil showFailedMsg:backHeader.errorMsg];                                  }                                 animated:YES                              loadingText:NSLocalizedString(@"Logging now...", nil)                                   inView:self.view];

This way, the network request is separated from the Viewcontroller, and there is no coupling. The request logic for the same interface only needs to be written once (copy, paste, because the code is not unique, so different people, different times to change one place, will cause differences, causing unknown bugs). Another benefit is that the various request logic is concentrated in one place, easy to read and modify.

4. Data is data, UI is UI
Essentially, the program is divided into two parts: Data and UI. From the perspective of Viewcontroller, it is state and view. View changes as the state changes, so the two should be separated to make the viewcontroller structure clearer.
For example: Viewdidload method, what should be written in this method?

This method was called after the view Controller had loaded its view hierarchy into memory. This method is called regardless of whether the view hierarchy were loaded from a nib file or created programmatically in T He Loadview method. You usually override the This method to perform additional initialization on the "were loaded from nib files."

The official recommendation is to write the additional initialization work on the view, and the initialization work that is not related to the view should not be written here (digression, IOS6, before encountering a memory warning, Viewdidload is going to be tuned multiple times, so it is problematic to write the initialization of the object here. After the iOS6 has not found the viewdidload call multiple times, then the initialization of the object (state variable replication) should be written where? --Initialize Method! Do not because the base class provides the default initialization method and lazy do not write, any class, unless simple can not be simpler, there must be an initialization method, even if nothing is written. The problem with this piece of code is that the work part code should appear in the initialization method.

-(void) viewdidload {[Super viewdidload];    _newsdataary = [[Nsmutablearray alloc] init];    _currentpage = 0;    Get Cache article Nsarray *arr = [[Articlesqlitedata Sharemanager] datagetheadarticle];    [_newsdataary Addobject:arr];    Nsarray *arrnewsinfo = [[Articlesqlitedata Sharemanager] datahomeviewisfirstget:yes];    [_newsdataary Addobjectsfromarray:arrnewsinfo];        if ([Arrnewsinfo count]! = 0) {Articlemodel *model = [Arrnewsinfo lastobject];    _isexpire = [self calculationTime:model.updateTime];    } else{_isexpire = YES;    }//The code above is related to the state of the object and should not appear here [self addtableview];    [Self settitleviewwithtext:@ "discover"];    [Self setleftbuttonwithtitle:@ "cheats" Action: @selector (Showcheats)];    [Self setrightbuttonwithimagename:@ "find_xiala.png" Action: @selector (Showcatagory)];    Self.showcategory = no;//This line is also a state/do any additional setup after loading the view from its nib. /** * Initialize category page */Self.categoryview = [[Hjfindcategoryview alloc] IniTwithframe:cgrectmake (0, Screen_width, screen_height)];    [Self.categoryview Addbordertopline];    Self.categoryView.hjFindCategoryViewDelegate = self;    Self.categoryView.hidden = Yes;//ui should depend on state rather than write dead [[Appdelegate Appdelegate].window AddSubview:self.categoryView]; [Self getbannernewstitle];}

5. Member method and Util method
One reason a class code is much more is to add a member method that should not be added. A method is called a member method because it operates on the state of an object, and if it does not manipulate the state of the object, it does not have a close relationship with the object, and it cannot be implemented in the class. As an example:

-(BOOL)calculationTime:(NSDate *)date{    NSDateFormatter *dateFormatter=[[NSDateFormatter alloc] init];    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];    NSDate *  senddate=[NSDate date];    //结束时间    NSDate *endDate = date;    //当前时间    NSDate *senderDate = [dateFormatter dateFromString:[dateFormatter stringFromDate:senddate]];    //得到相差秒数    NSTimeInterval time=[senderDate timeIntervalSinceDate:endDate];    int days = ((int)time)/(3600*24);    if (days < 0) {        return YES;    }    else{        return NO;    }}

The above method has nothing to do with the object, but it should be abstracted into a Util method, which can be called in this class, and can be called in more places.

6. Single entry of Function point
In code, some functional logic is relatively fixed, but in many places it repeats itself.
For example, the login function, in addition to user active login, and in the non-logged in state to use some of the features required to log in, will call the login page. I looked at the current code, and there were 14 calls to the login page. Code duplication is one aspect, and there is the problem of locating bugs. For example, when entering the homepage inexplicably pop up a login page, because the first page logic complex, I have to hit a lot of breakpoints to locate the code that produces the problem.
There is also the operation of the Tabbar, also appeared in the more out of place. In fact, just figure out what kind of tabbar is managed, and then let this class encapsulate a public method, control Tabbar hidden or not.

So a function point we only keep one exit, other places as long as the method can be called. The same place is written in the method interior, different places as the parameters open to the outside.

A clean code

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.