设计模式与代码重构——ios篇

有一阵子没写技术分享文了,最近每个月写一篇个人空间日记。主要是觉得自己技术比较一般写不出有质量的东西,误人子弟。互联网信息膨胀,让我们获取信息更加便捷,然而获取个人所需的正确信息,却需要每个人具备更强的搜索能力。搜索能力作为代码,就需要更优的算法。算法就像是程序的CPU,决定着程序的运行效率。

与其说电脑改变了世界,不如说是电脑改变了人类改变世界的效率。电脑其实是根据人脑设计的,而程序思想和人的思想相通,所以一个程序员在学会一门语言后,学习第二门语言会来的容易很多,因为编程思想是相通的。我认为,这和学外语有相通之处。

和一个爱武侠的朋友谈论程序,觉得写程序也像是练武,代码编辑器是武器,编程语言是武功秘籍,算法是功力,设计模式是招式。

做IOS开发,无非是XCode一种代码编辑器,由于apple公司的封闭,XCode目前除了Mac系统下没有其他系统下的版本。XCode也随着iOS系统升级不断改良,GDI(Graphics
Device Interface)不断完善,由起初的一个页面对应一个控制器的XIB编辑器,演变为模块化试图编辑的storyBoard,加之设备屏幕的丰富性,增加了图形界面可视化约束,以及数据模型视图CoreData的可视化编辑。功能的强大需要程序员更加深入的学习及掌握。然而人性的本能惰性使得很多老程序员并不喜欢使用新兴的工具,而选择纯代码实现,所以也得不到GDI所提供的视图编辑便利。是否使用GDI不关系一个程序员的编程思想,GDI在多数是客户端视图编码用到,它本身是由代码实现的,做项目可以没有GDI,但离不开编码,在多人协同开发的情况下越来越多的出现了多样化的混编。而CoreData的可视化数据模型也存在缺陷,其定义的模型属性,头字母必须是小写的。

程序员何其多,做算法的没有几个,多数程序员是做界面的,做业务的。业务的复杂性,或设备硬件的限制才需要由算法提高运行效率。算法意味着接触更底层的东西,指针、位、汇编、机器语言。至于黑客种种,是一群对网络安全极其了解且对算法了如指掌的人把算法运用于攻击网络安全防线的神,他们不是人,我也见不到他们。对于目前的我,还是扎扎实实学精设计模式,运用于编程,让编程效率更高,运行效率更优。而我始终相信:会设计得码农,是工程师,不会设计得工程师是码农。精通算法的工程师,是架构师,不懂算法的工程师,只是代码的搬运工。

下面我针对编程设计模式和苹果App开发常用设计模式对设计模式进行简单介绍,也算是自己设计模式的读书笔记。

一、编程设计模式

第一次我看《Head First,Design patterns》这本书的时候并不知道Head Frist的意思,因为知道自己看的是设计模式的书,联想到面向对象编程,以为它就是“头文件先写”的意思,后来才知道Head First是一个系列的丛书,所以应该与设计模式没有关系。于是百度一下,原来翻译为“深入浅出”。然而,“头文件先写”不但让我认识到自己需要加强英语学习,而且成为我编写代码的第一要务,于是后来慢慢有了一点面向对象的认识。代码设计遵循以下原则:

a、找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。

b、针对接口编程,而不是针对实现编程。

c、多用组合,少用继承。

d、别调用我们,我们会调用你。

e、一个类应该只有一个引起变化的原因。

下面就介绍一下常用设计模式和其对应的生活中的模式应用:

1,观察者模式(Subject、Observer):气象台、报纸杂志

天气->各种布告板;报纸杂志->订阅人、读者

2,装饰者模式:星巴克咖啡

3,工厂模式:披萨工厂、红团印、盖章

4,抽象工厂模式:披萨店

5,单例模式:巧克力工厂锅炉

6,命令模式:遥控器开关、订单

7,适配器模式:插座转接头

8,模板方法模式:泡茶、咖啡

9,迭代器和组合模式:餐厅并购煎饼屋,菜单的遍历

10,状态模式:糖果机、饮料机

11,代理模式:代表辅助完成某功能

12,复合模式:结合两个或多个模式,解决一般或重复发生的问题。

由于本篇主要讲述ios设计模式,这里不对编程模式展开叙述,后期会对编程模式写一篇学习笔记。这里就简要介绍一下。

二、苹果App开发常用设计模式及架构探索

1,设计模式的起源:MVC设计模式

1.1在模型对象中封装数据和基本行为

1.2使用视图对象向用户展示信息

1.3用控制器对象联系其模型和视图

2,针对接口编程,而不是针对实现编程

2.1.类和类型的差别:一个对象可以具有多个类型,而不同的类的对象可以有相同的类型

2.2.类型的所有对象,包括其子类的对象,都可以针对接口(协议、抽象类的虚方法)请求作出应答。

2.3.协议@protocol与抽象基类

2.3.1协议并不定义任何实现,而只声明方法,以确定符合协议的类的行为。

如我们最常用的UITableViewDataSource && UITableViewDelegate。

@protocol UITableViewDataSource<NSObject>

@required

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

@optional

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;

- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;

……

@end

@protocol UITableViewDelegate<NSObject, UIScrollViewDelegate>//协议本身可以遵守其他协议

@optional

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;

- (CGFloat) tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;

……

@end

3, 对象组合与类继承

3.1类继承是白箱复用,对象组合是黑箱复用

3.2 优先使用组合而不是类继承(http://blog.csdn.net/liaoqianchuan00/article/details/24838427)这里举一个项目里“发言”用的组合例子:

有多种发言,1、文字2、图文+文字3、音频(视频)4、带“@”的发言 5、带地址的发言 6、带发送范围的发言等,这个时候我们很难抽象出一个CELL基类满足各种“发言”的显示需求,即便可以,每种发言有自己相应的操作,这样就会导致耦合度也非常高,这个时候我们就需要用到组合,每个CELL实现自己的代理方法实现对应的操作。如下:

//

//  YYHomeRecorderTableViewCell.h

//  SuperCrm

//

//  Created by bill on 15/7/30.

//  Copyright (c) 2015年 Yonyouup Information Technology Co., Ltd. All rights reserved.

//

#import <UIKit/UIKit.h>

#import "YYHomeRecorderRowView.h"

#import "YYBaseViewController.h"

#import "YYHomeBusiDetailViewController.h"

#import "YYCustomAnalysisViewController.h"

#import "YYHomeBusinessViewController.h"

#import "YYHomeModel.h"

#import "WFTextView.h"

#import "WFHudView.h"

#pragma mark 最有价值的生意

@interface YYHomeRecorderTableViewCell : UITableViewCell

@property (nonatomic, strong) UILabel *h_titleLable;

@property (nonatomic, strong) UILabel *h_contentLable;

@property (nonatomic, strong) UIButton *h_arrrowButton;

@property (nonatomic, strong) UIImageView *h_imgview;

- (void)hanleData:(NSString *)contentStr;

@end

#pragma mark 具体生意

@protocol YYHomeRecorderSecondTableViewCellDelegate <NSObject>

- (void)secondTableIntoNextPage:(YYBaseViewController *)baseVC;

- (void)selectChangeScroll;//删除选择框

@end

@interface YYHomeRecorderSecondTableViewCell : UITableViewCell<YYHomeRecorderRowViewDelegate,UIScrollViewDelegate>

@property (nonatomic, assign) id<YYHomeRecorderSecondTableViewCellDelegate> delegate;

@property (nonatomic, strong) NSArray *h_dataArray;

- (void)handleData:(NSArray *)opportunitySummary;

@end

#pragma mark 客户分类信息

@protocol YYHomeRecorderThirdTableViewCellDelegate <NSObject>

- (void)thirdTableIntoNextPage:(YYBaseViewController *)baseVC;

@end

@interface YYHomeRecorderThirdTableViewCell : UITableViewCell

@property (nonatomic, assign) id<YYHomeRecorderThirdTableViewCellDelegate> delegate;

@property (nonatomic, strong) UIScrollView *h_scrollView;

//加载数据

- (void)handleData:(NSArray *)accountSummary;

@end

#pragma mark 客户生命周期

@interface YYHomeRecorderThirdOneTableViewCell : UITableViewCell

@property (nonatomic, strong) UILabel *h_titleLable;

@property (nonatomic, strong) UIButton *h_arrrowButton;

@end

#pragma mark 记录

@interface YYHomeRecorderForthTableViewCell : UITableViewCell<WFCoretextDelegate>

@property (nonatomic, strong) UIImageView *h_leftImg;

@property (nonatomic, strong) UILabel *h_contentLable;

@property (nonatomic, strong) UILabel *h_timeLable;

@property (nonatomic, strong) NSMutableArray *h_dataArray;

/*

* 是侧滑出现的右视图时,h_rightImg出现,h_timeLable隐藏

*

*/

@property (nonatomic, strong) UIButton *h_rightImgButton;

- (void)handelData:(YYDynamicResultListModel *)resultListModel;

@end

@interface YYHomeRecorderLeftViewTableViewCell : UITableViewCell

@property (nonatomic, strong) UILabel * H_leftLable;

@property (nonatomic, strong) UIButton *h_arrowButton;

@end

4, OC开发常用的其他设计模式

4.1单例:通常用于用户数据、行为的管理

+ (id)shareUserManager{

//Singleton instance

static SCRMUserManager *userManager;

//Dispatching it once.

static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{

//  Initializing keyboard manger.

userManager = [[self alloc] init];

userManager.clientDevice = [[YYClientDeviceModel alloc] init];

userManager.accountInfo = [[AccountInfoModel alloc] init];

});

//Returning kbManager.

return userManager;

}

4.2 观察者:类互相依赖,或一对多,接受响应的情况下使用。NSNotificationCenter && NSNotification 同名配对使用,如:

[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_LOGIN_LOGOUT object:nil];

[[NSNotificationCenter defaultCenter] removeObserver:self];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loginOrLogout:)

name:NOTIFICATION_LOGIN_LOGOUT object:nil];

4.3代理:为其他对象提供一种代理以控制对这个对象的访问。

A’ a类实现了b类里定义的协议,那a类实际上也是b类型的代理。

B’ 代理和BLOCK的选择(详见:http://www.cocoachina.com/ios/20150927/13525.html)

a如果对象有超过一个以上不同的事件源,使用delegation。

b如果一个对象是单例,不要使用delegation”

c如果对象的请求带有附加信息,更应该使用delegation

d如果你使用block去请求一个可能失败的请求,你应当只使用一个block。如下:

[fetcher makeRequest:^(id result) {

// do something with result

} error:^(NSError *err) {

// Do something with error

}];

三、设计模式与代码重构

设计模式是封装、继承、与多态,是编写代码之前需要考虑的问题。在编写代码过程中,特别是明捷开发的过程中会有很多重复代码出现,既增加了代码导致可读性减弱,再需求变更时往往由于编写过程中代码没有注释,越来越多的代码在一个方法里堆叠,导致最终只有编写代码的人才能读懂代码,并进行修改。

1,方法传参

只有参数(特别是参数为类对象时)是变动的时候,才需传参,否则便可放入方法里,在调用时减少获取参数进行传递。如:

UIBarButtonItem *item = [self.navigationItem.rightBarButtonItems objectAtIndex:0];

UIButton *buttonItem = item.customView;

[self rightViewHidden:buttonItem];

- (void)rightViewHidden:(UIButton *)sender {

}

这里该这么写,

[self rightViewHidden]

- (void)rightViewHidden {

UIBarButtonItem *item = [self.navigationItem.rightBarButtonItems objectAtIndex:0];

UIButton *buttonItem = item.customView;

}

2,数据、视图初始化

当控制器由一个controller 推到另一个controller的时,如果数据源来至网络,那么应该在viewDidLoad里对数据、视图进行初始化,这样即便网络请求出问题,视图也会有默认的显示,不至于显示空白,如下:

- (void)viewDidLoad {

[super viewDidLoad];

[self initData];

[self initView];

}

3,减少没有意义的参数,如正整形数据类型TAG等,定义有意义的名称进行代替,如:

typedef NS_ENUM(NSUInteger, HeaderViewTag) {

HeaderViewTagBackImage = 400,     // 背景图

HeaderViewTagImportantImage,//重要生意图标

HeaderViewTagBussinessName, // 生意名称

HeaderViewTagBussinessAmount,// 生意金额

HeaderViewTagBussinessAvatar,// 客户头像

HeaderViewTagBussinessCustomer,// 客户名称

HeaderViewTagDiscoverTime, // 发现日期

HeaderViewTagEstimateTime   // 预计成交日期

};

4,简化中间过程增加公用类可扩展性

如YYTypeChooseViewController的tableView.frame计算:

- (UITableView *)tableView

{

if (!_tableView) {

_tableView = [[UITableView alloc] init];

if([self needObjNumber]){

if (_objType == YYObjTypeClue) {

_tableView.frame = CGRectMake(0,- (kTypeCellHeight*3)-64, self.view.width, kTypeCellHeight *3);

} else {

if (_isMaster) {

_tableView.frame = CGRectMake(0, - (kTypeCellHeight*kTypeCount)-64, self.view.width, kTypeCellHeight *kTypeCount);

}else{

_tableView.frame = CGRectMake(0, - (kTypeCellHeight*(kTypeCount-1))-64, self.view.width, kTypeCellHeight *(kTypeCount-1));

}

}

}else if(_objType == YYObjTypeBriefing){

_tableView.frame = CGRectMake(0, - (kTypeCellHeight*kBriefingTypeCount)-64, self.view.width, kTypeCellHeight *kBriefingTypeCount);

}else if (_objType == YYObjTypeRelationCustomer)

{

_tableView.frame = CGRectMake(0,- (kTypeCellHeight*kRelaitonCount), self.view.width, kTypeCellHeight *kRelaitonCount);

}else if(_objType == YYObjTypeBusinessDept || _objType==YYObjTypeLifeForm || _objType == YYObjTypeBusinessStage){

_tableView.frame = CGRectMake(0, -(kTypeCellHeight*kBusinessDeptTypeCount)-64, self.view.width, kTypeCellHeight *kBusinessDeptTypeCount);

}else if (_objType == YYObjTypeAttList || _objType == YYObjTypeAttListTa)

{

_tableView.frame = CGRectMake(0, - (kTypeCellHeight*kBriefingTypeCount)-64, self.view.width, kTypeCellHeight *kBriefingTypeCount);

}else if (_objType == YYObjTypeAttChartAll ||_objType == YYObjTypeAttChartExternal||

_objType == YYObjTypeAttChartInner)

{

_tableView.frame = CGRectMake(0, - (kTypeCellHeight*2)-64, self.view.width, kTypeCellHeight *2);

}

_tableView.tableFooterView = [UIView new];

_tableView.delegate = self;

_tableView.dataSource = self;

_tableView.backgroundColor = [UIColor colorWithRed:255.0 green:255.0 blue:255.0 alpha:0.5];

}

return _tableView;

}

- (void)viewWillAppear:(BOOL)animated

{

[super viewWillAppear:animated];

self.navigationController.navigationBar.translucent = NO;

[UIView animateWithDuration:0.6 delay:0 usingSpringWithDamping:0.7 initialSpringVelocity:10 options:UIViewAnimationOptionCurveEaseInOut animations:^{

if([self needObjNumber]){

if (_objType == YYObjTypeClue) {

_tableView.frame = CGRectMake(0,- (kTypeCellHeight*3)-64, self.view.width, kTypeCellHeight *3);

} else {

if (_isMaster) {

_tableView.frame = CGRectMake(0, - (kTypeCellHeight*kTypeCount)-64, self.view.width, kTypeCellHeight *kTypeCount);

}else{

_tableView.frame = CGRectMake(0, - (kTypeCellHeight*(kTypeCount-1))-64, self.view.width, kTypeCellHeight *(kTypeCount-1));

}

}

}else if(_objType == YYObjTypeBriefing){

_tableView.frame = CGRectMake(0, - (kTypeCellHeight*kBriefingTypeCount)-64, self.view.width, kTypeCellHeight *kBriefingTypeCount);

}else if (_objType == YYObjTypeRelationCustomer)

{

_tableView.frame = CGRectMake(0,- (kTypeCellHeight*kRelaitonCount), self.view.width, kTypeCellHeight *kRelaitonCount);

}else if(_objType == YYObjTypeBusinessDept || _objType==YYObjTypeLifeForm || _objType == YYObjTypeBusinessStage){

_tableView.frame = CGRectMake(0, -(kTypeCellHeight*kBusinessDeptTypeCount)-64, self.view.width, kTypeCellHeight *kBusinessDeptTypeCount);

}else if (_objType == YYObjTypeAttList || _objType == YYObjTypeAttListTa)

{

_tableView.frame = CGRectMake(0, - (kTypeCellHeight*kBriefingTypeCount)-64, self.view.width, kTypeCellHeight *kBriefingTypeCount);

}else if (_objType == YYObjTypeAttChartAll ||_objType == YYObjTypeAttChartExternal||

_objType == YYObjTypeAttChartInner)

{

_tableView.frame = CGRectMake(0, - (kTypeCellHeight*2)-64, self.view.width, kTypeCellHeight *2);

}

} completion:^(BOOL finished) {

}];

}

此类起初只有两三个显示类型,后来随着开发的深入,显示类型越来越多,判断开始变得越来越复杂。认真查看代码,此处不过根据各种类型以及各种类型时用友显示的controller的导航栏是否透明,来计算tableView高度,计算中心点位置,从而使tableView处于正确位置。于是重构为:

//导航栏是否透明

- (BOOL)navBarAlphaIsZero {

return (self.objType == YYObjTypeCustomer || self.objType == YYObjTypeBusiness || self.objType == YYObjTypeContact || self.objType == YYObjTypeBriefing || self.objType == YYObjTypeAttList
||self.objType == YYObjTypeAttListTa);

}

- (UITableView *)tableView

{

if (!_tableView) {

_tableView = [[UITableView alloc] init];

CGRect frame = self.view.frame;

[_tableView setFrame:CGRectMake(0, -frame.size.height, frame.size.width, frame.size.height)];

_tableView.tableFooterView = [UIView new];

_tableView.delegate = self;

_tableView.dataSource = self;

_tableView.backgroundColor = [UIColor clearColor];

}

return _tableView;

}

- (void)viewWillAppear:(BOOL)animated

{

[super viewWillAppear:animated];

self.navigationController.navigationBar.translucent = NO;

[UIView animateWithDuration:0.6 delay:0 usingSpringWithDamping:0.7 initialSpringVelocity:10

options:UIViewAnimationOptionCurveEaseInOut animations:^{

CGRect tableViewFrame = self.tableView.frame;

if ([self navBarAlphaIsZero]){

tableViewFrame.origin.y = 64;

}

else{

tableViewFrame.origin.y = 0;

}

[self.tableView setFrame:tableViewFrame];

} completion:^(BOOL finished) {

}];

}

这里简单举几个重构的例子。“设计模式”是在编写代码前应该考虑的问题,而“重构”则是在代码编写过程中,功能实现完成后,去优化。如果说编程界只有一个真理,那一定是“改变”,我们应该计划改变,迎接改变,同时挑战改变增强代码可读性,这样才能不断提高自己作为一名程序员的职业素养的一件事。

参考书目:

《Head First,Design patterns》、《Objectvie-C 编程之道,iOS设计模式解析》

时间: 2024-10-11 06:37:54

设计模式与代码重构——ios篇的相关文章

iOS UI进阶-1.1网易彩票框架搭建-代码重构

在上一篇中,我们基本已经把整个框架都搭建出来了,下面进行代码重构一下. 思路: 导航按钮,按下时,会变灰,那是系统自带了,通过自定义UIButton,实现按下按钮立即切换效果. MJTabBarController管得太多了,只需要传图片过去,即创建好一个TabBar. 通过代理实现底部tabbar的切换. 一.自定义UIButton,继承自UIButton.MJTabBarButton.m #import "MJTabBarButton.h" @implementation MJTa

妮子的iOS 代码重构1

昨天面试,被问了个代码重构,直接愣住了... 回来稍微看了下,对代码重构有了一点了解...就是让自己的代码有更好的结构,更简洁易读吧,是提高代码质量的一种方法吧!Xcode提供了几个代码重构功能,有Rename(重命名).Extract.Create Superclass.Move Up.Move Down.Encapsulate. 使用:在代码区右击——Refactor,调出重构功能.Rename用于对类名.方法名.属性名等重命名,Extract用于将自己写的一段代码变成一个方法,Create

【iOS开发-44】通过案例谈iOS代码重构:合并、格式化输出、宏变量、利用数组字典存储数据,以及利用plist的终极知识

首先我们今天的案例就是如下5个页面通过上一张下一张来切换: (1)第一步,基本是以很傻很直接的方式来创建,这里用到的主要点有: --把对象变量设置为全局变量使得可以在其他方法中调用来设置它们的属性 --设置了一个全局变量index,默认是0,然后通过增加减少这个index值并结合switch来调用不同的数据. --利用先调用一次change方法初始化页面,使得页面定格在第一帧. --利用按钮的enabled属性来设置按钮是否可以被点击,然后结合index的值分别在第1张和第5张时分别把上一张和下

代码重构(二):类重构规则(Swift版)

在上篇博客<代码重构(一):函数重构规则(Swift版)>中,详细的介绍了函数的重构规则,其中主要包括:Extract Method, Inline Method, Inline Temp, Replace Temp with Query, Introduce Explaining Variable, Split Temporary Variable, Remove Assignments to Parameters, Replace Method with Method Object等.关于

代码重构(一):函数重构规则

重构是项目做到 一定程度后必然要做的事情.代码重构,可以改善既有的代码设计,增强既有工程的可扩充.可维护性.随着项目需求的不断迭代,需求的不断更新,我们在项目中 所写的代码也在时时刻刻的在变化之中.在一次新的需求中,你添加了某些功能模块,但这些功能模块有可能在下一次需求中不在适用.或者你因为需求迭代与变 更,使你原有的方法或者类变得臃肿,以及各个模块或者层次之间耦合度增加.此时,你要考虑重构了. 重构,在<重构,改善既有代码的设计>这本经典的书中给出了定义,大概就是:在不改变代码对外的表现的情

记一次完整的系统业务代码重构(1)——why

记一次完整的系统业务代码重构(1)——why 0.为什么烂 优秀的代码优秀的出奇一致,烂代码却烂的千奇百怪.至于原因嘛,无非如下几种: 1.迭代和变更需求快,比翻书变脸还快,而且没有统一规划和为未来预留考虑. 2.公司人员流动快,代码换了一届又一届的主人,七朝元老都没站出来,三朝元老的代码都弱爆了. 3.神坑的技术人员,零注释.迷魂阵.障眼法没有最晕的代码只有更晕的代码. 1.烂在何处 让所有的开发人员吐槽自己维护的代码烂在何处,估计说个3天3夜都说不完.这里总结下自身项目的缺点.由于项目内容涉

设计模式学习笔记(目录篇)

设计模式学习笔记(目录篇) 为了方便查看,特此将设计模式学习笔记系列单独做一个目录. 1   设计模式学习笔记(一:命令模式) 2   设计模式学习笔记(二:观察者模式) 3   设计模式学习笔记(三:装饰模式) 4   设计模式学习笔记(四:策略模式) 5   设计模式学习笔记(五:适配器模式) 6   设计模式学习笔记(六:责任链模式) 7   设计模式学习笔记(七:外观模式) 8   设计模式学习笔记(八:迭代器模式) 9   设计模式学习笔记(九:中介者模式) 10  设计模式学习笔记(

代码重构方向原则指导

http://www.aqee.net/hill-climbing-wonkish/ 重构是一种对软件进行修改的行为,但它并不改变软件的功能特征,而是通过让软件程序更清晰,更简洁和更条理来改进软件的质量.代码重构之于软件,相当于结构修改之于散文.每次人们对如何对代码进行重构的讨论就像是讨论如果对一篇文学作品进行修订一样无休无止.所有人都知道应该根据项目的自身情况来对代码进行重构,而重构是无止境的.莫扎特从来不不对他的作品进行修订,特罗洛普对自己作品修订的恰到好处,大多数作家认为他们俩这样做都是合

Unity3D如何接入第三方的SDK - iOS篇

来源:http://blog.csdn.net/smlisi2/article/details/8786485 授人以鱼,不如授人以渔”,以UNITY3D调用iOS版的91SDK为例,利用C# / C / OBJ-C 交互原理,本文将详细介绍UNITY3D与iOS之间交互的解决方案. 首先,打开XCODE新建一个空项目,参照91SDK开发文档将91SDK引入并进行环境配置. 配置完毕后创建一个名为“LsSdkConector”的OBJ-C CLASS文件.完毕后,当前项目应如图: LsSdkCo