北京总部

IOS开发系列--Objective-C之协议、代码块、分类

IOS开发系列--Objective-C之协议、代码块、分类

2017-03-07

概述 ObjC的语法主要基于smalltalk进行设计的,除了提供常规的面向对象特性外,还增加了很多其他特性,这一节将重点介绍ObjC中一些常用的语法特性。当然这些内容虽然和其他高级语言命名不一样,但是我们都可以在其中找到他们的影子,在文章中我也会对比其他语言进行介绍,这一节的重点内容如下: 协议protocol 代码块block 分类category 协议protocol 在ObjC中使用@protocol定义一组方法规范,实现此协议的类必须实现对应的方法。熟悉面向对象的童鞋都知道接口本身是对象行为描述的协议规范。也就是说在ObjC中@protocol和其他语言的接口定义是类似的,只是在ObjC中interface关键字已经用于定义类了,因此它不会再像C#、Java中使用interface定义接口了。 假设我们定义了一个动物的协议AnimalDelegate,人员Person这个类需要实现这个协议,请看下面的代码: AnimalDelegate.h // //  AnimalDelegate.h //  Protocol&Block&Category // //  Created by Kenshin Cui on 14-2-2. //  Copyright (c) 2014年 Kenshin Cui. All rights reserved. //     //定义一个协议 @protocol AnimalDelegate   @required //必须实现的方法 -(void)eat;   @optional //可选实现的方法 -(void)run; -(void)say; -(void)sleep;   @end   Person.h // //  Person.h //  Protocol&Block&Category // //  Created by Kenshin Cui on 14-2-2. //  Copyright (c) 2014年 Kenshin Cui. All rights reserved. //   #import #import "AnimalDelegate.h"   @interface Person : NSObject   -(void)eat;   @end Person.m // //  Person.m //  Protocol&Block&Category // //  Created by Kenshin Cui on 14-2-2. //  Copyright (c) 2014年 Kenshin Cui. All rights reserved. //   #import "Person.h"   @implementation Person   -(void)eat{     NSLog(@"eating..."); }   @end 这里需要说明几点: 一个协议可以扩展自另一个协议,例如上面AnimalDelegate就扩展自NSObject,如果需要扩展多个协议中间使用逗号分隔; 和其他高级语言中接口不同的是协议中定义的方法不一定是必须实现的,我们可以通过关键字进行@required和@optional进行设置,如果不设置则默认是@required(注意ObjC是弱语法,即使不实现必选方法编译运行也不会报错); 协议通过<>进行实现,一个类可以同时实现多个协议,中间通过逗号分隔; 协议的实现只能在类的声明上,不能放到类的实现上(也就是说必须写成@interface Person:NSObject而不能写成@implementation Person); 协议中不能定义属性、成员变量等,只能定义方法; 事实上在ObjC中协议的更多作用是用于约束一个类必须实现某些方法,而从面向对象的角度而言这个类跟接口并不一定存在某种自然关系,可能是两个完全不同意义上的事物,这种模式我们称之为代理模式(Delegation)。在Cocoa框架中大量采用这种模式实现数据和UI的分离,而且基本上所有的协议都是以Delegate结尾。 现在假设需要设计一个按钮,我们知道按钮都是需要点击的,在其他语言中通常会引入事件机制,只要使用者订阅了点击事件,那么点击的时候就会触发执行这个事件(这是对象之间解耦的一种方式:代码注入)。但是在ObjC中没有事件的定义,而是使用代理来处理这个问题。首先在按钮中定义按钮的代理,同时使用协议约束这个代理(事件的触发者)必须实现协议中的某些方法,当按钮处理过程中查看代理是否实现了这个方法,如果实现了则调用这个方法。 KCButton.h // //  KCButton.h //  Protocol&Block&Category // //  Created by Kenshin Cui on 14-2-2. //  Copyright (c) 2014年 Kenshin Cui. All rights reserved. //   #import @class KCButton;   //一个协议可以扩展另一个协议,例如KCButtonDelegate扩展了NSObject协议 @protocol KCButtonDelegate   @required //@required修饰的方法必须实现 -(void)onClick:(KCButton *)button;   @optional //@optional修饰的方法是可选实现的 -(void)onMouseover:(KCButton *)button; -(void)onMouseout:(KCButton *)button;   @end   @interface KCButton : NSObject   #pragma mark - 属性 #pragma mark 代理属性,同时约定作为代理的对象必须实现KCButtonDelegate协议 @property (nonatomic,retain) iddelegate;   #pragma mark - 公共方法 #pragma mark 点击方法 -(void)click;   @end KCButton.m // //  KCButton.m //  Protocol&Block&Category // //  Created by Kenshin Cui on 14-2-2. //  Copyright (c) 2014年 Kenshin Cui. All rights reserved. //   #import "KCButton.h"   @implementation KCButton   -(void)click{     NSLog(@"Invoke KCButton's click method.");     //判断_delegate实例是否实现了onClick:方法(注意方法名是"onClick:",后面有个:)     //避免未实现ButtonDelegate的类也作为KCButton的监听     if([_delegate respondsToSelector:@selector(onClick:)]){         [_delegate onClick:self];     } }   @end MyListener.h // //  MyListener.h //  Protocol&Block&Category // //  Created by Kenshin Cui on 14-2-2. //  Copyright (c) 2014年 Kenshin Cui. All rights reserved. //   #import @class KCButton; @protocol KCButtonDelegate;   @interface MyListener : NSObject -(void)onClick:(KCButton *)button; @end MyListener.m // //  MyListener.m //  Protocol&Block&Category // //  Created by Kenshin Cui on 14-2-2. //  Copyright (c) 2014年 Kenshin Cui. All rights reserved. //   #import "MyListener.h" #import "KCButton.h"   @implementation MyListener -(void)onClick:(KCButton *)button{     NSLog(@"Invoke MyListener's onClick method.The button is:%@.",button); } @end main.m // //  main.m //  Protocol&Block&Category // //  Created by Kenshin Cui on 14-2-2. //  Copyright (c) 2014年 Kenshin Cui. All rights reserved. //   #import #import "KCButton.h" #import "MyListener.h"   int main(int argc, const char * argv[]) {     @autoreleasepool {                 KCButton *button=[[KCButton alloc]init];         MyListener *listener=[[MyListener alloc]init];         button.delegate=listener;         [button click];         /* 结果:          Invoke KCButton's click method.          Invoke MyListener's onClick method.The button is:.          */     }     return 0; } 我们通过例子模拟了一个按钮的点击过程,有点类似于Java中事件的实现机制。通过这个例子我们需要注意以下几点内容: id可以表示任何一个ObjC对象类型,类型后面的”<协议名>“用于约束作为这个属性的对象必须实现该协议(注意:使用id定义的对象类型不需要加“*”); MyListener作为事件触发者,它实现了KCButtonDelegate代理(在ObjC中没有命名空间和包的概念,通常通过前缀进行类的划分,“KC”是我们自定义的前缀) 在.h文件中如果使用了另一个文件的类或协议我们可以通过@class或者@protocol进行声明,而不必导入这个文件,这样可以提高编译效率(注意有些情况必须使用@class或@protocol,例如上面KCButton.h中上面声明的KCButtonDelegate协议中用到了KCButton类,而此文件下方的KCButton类声明中又使用了KCButtonDelegate,从而形成在一个文件中互相引用关系,此时必须使用@class或者@protocol声明,否则编译阶段会报错),但是在.m文件中则必须导入对应的类声明文件或协议文件(如果不导入虽然语法检查可以通过但是编译链接会报错); 使用respondsToSelector方法可以判断一个对象是否实现了某个方法(需要注意方法名不是”onClick”而是“onClick:”,冒号也是方法名的一部分);    学习更多IOS开发知识就到中软国际!

更多>
数据结构中二叉树的基本操作

数据结构中二叉树的基本操作

2017-03-06

二叉树的基本操作,可能包括: 创建,遍历,转化,复制,删除等。 遍历:前中后三种顺序的遍历,已经是各数据结构与算法教程的最基础内容,在此不重复。 创建:大多数据结构教程当中的二叉树创建程序,都是采用的递归方式,递归方式创建的二叉树与遍历的过程相似,所创建的二叉树,也是采用左右子节点方式,后续进行遍历操作十分方便。 转化:直觉上,最简单的二叉树存储方式其实是如下图的数组: *此图出自某高校数据结构ppt,但实在难以查证是哪个学校,无法直接感谢,请谅解。 首先,提供个满二叉树大小的数组,然后其中数值按完全二叉树存储。 显然,此种顺序存储方法:第i号(这里编号指对应的完全二叉树的位序)结点的左右孩子一定保存在第2i及2i+1号单元中。 故此,为兼顾存储的直观与遍历等操作的方便,从顺序数组向左右子节点存储方式的转化也就十分重要。 1-转化方法 分为几个步骤: (1)准备原始数组 (2)分析数组中的有效值,对应二叉树节点非空; (3)创建二叉树节点; (4)计算除最后一层子节点外,构造节点间父子关系时的循环次数; (5)构造二叉树节点间的父子关系; (6)确实二叉树根节点; 主要代码: (1)准备原始数组 1. //原始数组  2.     int intBiTreeInit[ARR_COUNT];  3.   4.      5.     //初始化原始数组至无效值  6.     for(int i=0;i<=ARR_COUNT-1;i++)  7.         intBiTreeInit[i]=NVALUE;  8.   9.     //本if条件确保ARR_COUNT是否是的乘方-1  10.     if(0==(ARR_COUNT & (ARR_COUNT+1)))  11.     {  12.         for(int i=0;i<=ARR_COUNT-1;i++)  13.             intBiTreeInit[i]=2*(i+1);  14.     }  15.     else  16.         return RET_ERR;  17.   18.     //使最后两数为无效值  19.     intBiTreeInit[ARR_COUNT-1]=NVALUE;  20.     intBiTreeInit[ARR_COUNT-2]=NVALUE;  (2)分析数组中的有效值 1. //开始获得数组中有效值位置  2.    int intRel=0;  3.    int intArr=0;  4.    for(intArr=0;intArr<=intCount-1;intArr++)  5.    {  6.        if(elemArr[intArr]!=elemNValue)  7.        {  8.            intRel++;  9.            vecIntEffPos.push_back(intArr);  10.        }  11.        }  (3)创建二叉树节点  1. //数组中有效值对应创建节点  2. //同时初始化父子节点为NULL  3. for(intArr=0;intArr<=intRel-1;intArr++)  4. {  5.     pBiTreeTemp=(PBiTreeNode)malloc(sizeof(BiTreeNode));;  6.       7.     if(NULL==pBiTreeTemp)                                //判断是否有足够的内存空间  8.     {  9.         cout<<"Memory alloc failure"<

更多>
中软国际-.NET入门知识问答

中软国际-.NET入门知识问答

2017-02-27

关于.NET入门知识你知道多少? 1.重载(Overload)和覆写(override)的区别 答:方法重载:当类包含两个名称相同但签名不同(方法名相同,参数列表不相同)的方法时发生方法重载。用方法重载来提供在语义上完成相同而功能不同的方法。 覆写:在类的继承中使用,通过覆写子类方法可以改变父类虚方法的实现。 2.接口与继承的区别?什么时候使用接口,什么时候使用继承? 答:(1)接口定义一个类型需要实现的方法,属性,索引和事件,包括可能的参数类型和返回值类型,而把具体的实现交由相应的类或结构来做,从而为组件提供多态能力。 (2)继承常用于在一个现有父类的基础上的功能扩展,往往是我们将几个类中相同的成员提取出来放在父类中实现,然后在各自的子类中加以继承。 (3)接口可以实现多接口继重,而继承只能实现单继承。 (4)实现继承可继承父类型的实现,由于接口中没有定义方法的实现,因此必须实现继承后该接口的所有方法。 (5)为父类型添加方法可能不影响使用继承自该类型实现的用户,而为接口添加方法导致用户必须为新方法添加实现。 (6)当派生类和基类是is-a的关系是使用"继承",典型案例"苹果is-a水果",存在can-do的关系时使用"接口" 3.ado,ado.net的区别 答:您可以通过将ADO.NET的各项功能与ActiveX数据对象(ADO)的特定功能进行比较来理解ADO.NET的功能。 数据的内存中表示形式 在ADO中,数据的内存中表示形式为记录集。在ADO.NET中,它为数据集。它们之间有重要的差异。 表的个数 记录集看起来像单个表。如果记录集将包含来自多个数据库表的数据,则它必须使用JOIN查询,将来自各个数据库表的数据组合到单个结果表中。 相反,数据集是一个或多个表的集合。数据集内的表称为数据表;明确地说,它们是DataTable对象。如果数据集包含来自多个数据库表的数据,它通常将包含多个DataTable对象。即,每个DataTable对象通常对应于单个数据库表或视图。这样,数据集可以模仿基础数据库的结构。 数据集通常还包含关系。数据集内的关系类似于数据库中的外键关系,即它使多个表中的行彼此关联。例如,如果数据集包含一个有关投资者的表和另一个有关每个投资者的股票购买情况的表,则数据集可能还包含一个关系来连接投资者表的各个行和购买表的对应行。 由于数据集可以保存多个独立的表并维护有关表之间关系的信息,因此它可以保存比记录集丰富得多的数据结构,包括自关联的表和具有多对多关系的表。 数据导航和游标 在ADO中,您使用ADOMoveNext方法顺序扫描记录集的行。在ADO.NET中,行表示为集合,因此您可以像依次通过任何集合那样依次通过表,或通过序号索引或主键索引访问特定行。DataRelation对象维护有关主记录和详细资料记录的信息,并提供方法使您可以获取与正在操作的记录相关的记录。例如,从Investor表的"NateSun"的行开始,可以定位到Purchase表中描述其购买情况的那组行。 "游标"是数据库元素,它控制记录导航、更新数据的能力和其他用户对数据库所做更改的可见性。ADO.NET不具有固有的游标对象,而是包含提供传统游标功能的数据类。例如,在ADO.NETDataReader对象中提供只进、只读游标的功能。有关游标功能的更多信息,请参见数据访问技术。 将打开连接的时间降至最低 在ADO.NET中,打开连接的时间仅足够执行数据库操作,例如"选择"(Select)或"更新"(Update)。您可以将行读入数据集中,然后在不保持与数据源的连接的情况下使用它们。在ADO中,记录集可以提供不连接的访问,但ADO主要是为连接的访问设计的。 ADO和ADO.NET中的不连接处理之间存在一个显著差异。在ADO中,通过调用OLEDB提供程序来与数据库通信。但在ADO.NET中,您通过数据适配器(OleDbDataAdapter、SqlDataAdapter、OdbcDataAdapter或OracleDataAdapter对象)与数据库通信,这将调用OLEDB提供程序或基础数据源提供的API。ADO和ADO.NET之间的主要区别在于:在ADO.NET中,数据适配器允许您控制将对数据集所做的更改传输到数据库的方式,方法是实现性能优化、执行数据验证检查或添加其他任何额外处理。 注意数据适配器、数据连接、数据命令和数据读取器是组成.NETFramework数据提供程序的组件。Microsoft和第三方供应商可能会提供其它提供程序,这些提供程序也可集成到VisualStudio中。有关不同.NET数据提供程序的信息,请参见.NET数据提供程序。 在应用程序间共享数据 在应用程序间传输ADO.NET数据集比传输ADO不连接的记录集要容易得多。若要将ADO不连接的记录集从一个组件传输到另一个组件,请使用COM封送。若要在ADO.NET中传输数据,请使用数据集,它可以传输XML流。 相对于COM封送,XML文件的传输提供以下便利之处: 更丰富的数据类型 COM封送提供一组有限的数据类型(由COM标准定义的那些类型)。由于ADO.NET中的数据集传输基于XML格式,所以对数据类型没有限制。因此,共享数据集的组件可以使用这些组件一般会使用的任何丰富的数据类型集。 性能 传输大型ADO记录集或大型ADO.NET数据集会使用网络资源;随着数据量的增长,施加于网络的压力也在增加。ADO和ADO.NET都使您可以最大限度地降低所传输的数据。但ADO.NET还提供另一个性能优势:ADO.NET不需要数据类型转换。而需要COM封送来在组件间传输记录集的ADO,则需要将ADO数据类型转换为COM数据类型。 穿透防火墙 防火墙可以影响试图传输不连接的ADO记录集的两个组件。请记住,防火墙通常配置为允许HTML文本通过,但防止系统级请求(如COM封送)通过。 因为组件使用XML交换ADO.NET数据库,所以防火墙可以允许数据集通过。 4.asp.net页面在什么时候产生?又在什么时候销毁? 答:(1)Page_Init();---初始化对象 这一过程主要是初始化包括页面本身的所有控件,每次的页面载入就会执行一次初试过程,而在这里面访问到的也是控件的初始值。还有就是可以通过OnInit()来重载初试化事件。 (2)LoadViewState---导入Viewstate数据 在初试化事件后,在loadvireState事件中所有控件将获得他们的第一个属性ViewState属性,这个属性最终将被返回给服务器以判断这个页面是已经被用户访问完毕还是仍然在被用户所访问。也可重载loadvireState事件对相应的控件进行值设定。 (3)LoadPostbackdata;---用LoadPostData处理Postback数据 Postback数据也可以理解成就是服务器页面提交的表单数据,每一次表单数据的提交都会触发执行IPostBackDataHandler接口操作的控件。 (4)Page_Load();---导入对象 这个过程就比较熟悉了,也是在页面的每次载入时一定会执行,但是注意和PageInit()之间的区别,所有的对象第一次被布置在DOM页面(在Asp.net中称控件树)里了并且可以通过代码或是相关的位置被引用。这样,对象就可以很容易的从客户端获得诸如宽度、高度、值、可见性等在Html中的属性值。经常会用到的Page.IsPostBack()指示该页是否正为响应客户端回发而加载,或者它是否正被首次加载和访问. (5)Handlecontrolevents;---具体的控件事件 这个过程执行的是相应具体控件事件,比如按钮事件..等。 (6)Page_PreRender();---预先呈递对象 预先呈递对象可以改变对象并将改变保存的最后时刻.可以对控件的属性、控件树的结构等做出最后的修改,同时还不用考虑Asp.net对其作出任何改变,因为此时已经脱离了数据库调用以及viewstate更新了,也可以通过OnPreRender来重载。 (7)Page_Render();---呈递对象呈递页面 所有对页面控件的修改完成后viewstate就被保存了。运用Html创建给浏览器输出的页面的时候Render事件就发生了。在Render事件过程中,页面调用其中的对象将它们呈递给Html。然后,页面就可以以Html的形式被用户的浏览器访问了。当Render事件被重载时,开发者可以编写自定义的Html代码使得原先生成的Html都无效而按照新的Html来组织页面。Render方法将一个HtmlTextWriter对象作为参数并用它将Html在浏览器上以网页的形式显示。这时仍然可以做一些修改动作,不过它们只是客户端的一些变化而已了。亦可以重载Render事件。 (8)Unloadevent;---卸载对象 当想服务器请求一个对象的时候,就会在内存里生成一个继承页面对象,也就是页面的类,它继承自System.Web.UI.Page. 当页面对象从内存中卸载时发生,将触发该事件. (9)Disposemethodcalled 在呈递给Html完成后,所有的对象都应被销毁。在Dispose事件中,你应该销毁所有在建立这个页面时创建的对象。这时,所有的处理已经完毕,所以销毁任何剩下的对象都是不会产生错误的,包括页面对象。你可以重载Dispose事件。 5.Session,ViewState,Application,cookie的区别? 答:Session:Session用于保持状态的基于Web服务器的方法。Session允许通过将对象存储在Web服务器的内存中在整个用户会话过程中保持任何对象。主要用于保持代码隐藏类中对象的状态。为每个用创建的,用于存储单个用户,因为他是相对每个用户的.所以可能来取得在线人数等。 ViewState:主要用于保持Web页上控件的状态。当Web页上的控件被绑定到代码隐藏类中的对象。 Application用于存储所有用户都可视的信息.所以它存储的是要让所有用户共享的一些信息.如总访问数等; Cache:页面缓存。 cookie:通常我们都把它放在客户端,也可以存储在服务器端。主要用它存储用户的个性设制,和登陆信息。 6.面向对象的思想主要包括什么? 答:开发人员应该熟悉面向对象软件开发(OOP)基本概念,熟悉面向对象软件开发中的类、继承、封装、多态等概念,具备良好的面向对象软件开发思想和设计原则。 7.什么是ASP.net中的用户控件? 答:用户控件。用户控件是能够在其中放置标记和Web服务器控件的容器。然后,可以将用户控件作为一个单元对待,为其定义属性和方法。 8.什么叫应用程序域?什么是受管制的代码?什么是强类型和强类型系统?什么是装箱和拆箱?什么是重载?CTS、CLS和CLR分别作何解释? 答:(1)应用程序域为隔离正在运行的应用程序提供了一种灵活而安全的方法。 (2)受管制的代码:在.NET环境中运行的任何代码都称为受管制的代码(unmanagedcode),.NET外部的其他代码也运行在Windows上,这些代码称为未受管制的代码(unmanagedcode)。 (3)强类型和弱类型的区别在与,在编码过程中是否要指定数据类型,作为强类型必须指定数据类型,编译器为其分配相应的存储空间(如c,pascal)否则编译出错。而弱类型不一定需要指定数据类型,编译器会用相同的空间去分配各种类型,除非你指定了(如basic)。作为强类型语言,在编译阶段的安全性要高于弱语言型。 强类型系统:RTTI:类型识别系统。 (4)装箱就是隐式的将一个值型转换为引用型对象。比如: inti=0; Syste.Objectobj=i; 这个过程就是装箱!就是将i装箱! 拆箱就是将一个引用型对象转换成任意值型!比如: inti=0; System.Objectobj=i; intj=(int)obj; 这个过程前2句是将i装箱,后一句是将obj拆箱! 再写个代码,看看进行了几次装拆箱! inti=0; System.Objectobj=i; Console.WriteLine(i+","+(int)obj); 其中共发生了3次装箱和一次拆箱!^_^,看出来了吧?! 第一次是将i装箱,第2次是输出的时候将i转换成string类型,而string类型为引用类型,即又是装箱,第三次装箱就是(int)obj的转换成string类型,装箱! 拆箱就是(int)obj,将obj拆箱!! (5)重载,是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。 (6)CLR的全称是公共语言运行库(CommonLanguageRuntime),读者可以把CLR理解为一个包含运行.NET程序的引擎和一堆符合公共语言基础结构的类库的集合。CLR是一个规范的实现,我们开发的几乎所有的.NET程序都基于CLR的类库来实现,并且运行在CLR提供的运行引擎之上。所谓.NET框架,指的就是公共语言运行库。 公共语言基础(CLI)是微软公司向ECMA提交的一份语言和数据格式规范,CLR是目前为止唯一一个公共语言基础的实现版本。 CTS的全称是通用类型系统(CommonTypeSystem)。前文已经介绍了公共语言基础(CLI)的概念,微软公司提交的CLI规范,包括了公共类型系统(CTS)、公共中间语言(CIL)、底部文件格式以及元数据格式等。公共类型系统定义了一个能够在CLR上运行的语言规范。尽管有很多语言本身不符合CTS规范,但是通过加强编译器,改变语言附加规范等手段,使得许多语言能够编写出能在CLR上运行的程序。 一种语言编写的程序编译能够在CLR上运行,并不代表这种语言本身完全符合CTS的规范。例如C++语言,仍然保持了其不符合CTS规范的部分,并且在编译时把这部分不符合CTS的代码编译成原始代码而非中间代码。 最后来看一下CLS的概念。公共语言规范(CLS)是CTS的一个子集,它定义了希望编写在.NET平台上运行的程序的语言所需符合的最小规范。正因为.NET允许由不同语言编写的程序一起执行,所以才制定出CLS规范,用以避免不同语言特性产生的错误。 9.列举一下你所了解的XML技术及其应用 答:xml可以用来做网页(xslt)xml可以当作数据库xml可以用来保存对象的系列化 10.值类型和引用类型的区别?写出C#的样例代码。 答:值类型包括简单类型、结构体类型和枚举类型,引用类型包括自定义类、数组、接口、委托等 关于.NET入门知识问答,了解更多热门.NET问题就到中软国际!

更多>
IOS开发系列-C语言之基础知识-中软国际教育

IOS开发系列-C语言之基础知识-中软国际教育

2017-02-21

当前移动开发的趋势已经势不可挡,这个系列希望浅谈一下个人对IOS开发的一些见解,这个IOS系列计划从几个角度去说IOS开发: ·        C语言 ·        OC基础 ·        IOS开发(iphone/ipad) ·        Swift 这么看下去还有大量的内容需要持续补充,但是今天我们从最基础的C语言开始,C语言部分我将分成几个章节去说,今天我们简单看一下C的一些基础知识,更高级的内容我将放到后面的文章中。 今天基础知识分为以下几点内容(注意:循环、条件语句在此不再赘述): 既然是IOS开发系列首先看一下在Mac OS X中的C的运行 打开Xcode 选择命令行程序 填写项目名称并选择使用C语言 选择保存目录 自动生成如下代码 OK,在Xcode上我们编写自己的程序如下 // //  main.c //  C语言基础 // //  Created by Kenshin Cui on 14-7-12. //  Copyright (c) 2014年 cmjstudio. All rights reserved. //   #include   void showMessage(){     printf("Hello,World! "); }   int main(int argc, const char * argv[]) {     showMessage();     return 0; } 在上面的程序中我们需要解释几点: main函数是程序入口,一个程序只能有一个main()函数,需要有一个整型返回值(事实上返回值int可以省略,但是这并不代表不返回值,而是默认为int;我们也可以在main()函数中不提供return,这是因为c语言语法要求不够严格); #include是预处理指令,用于包含指定文件(注意在编译前即处理),它实际做的工作就是把对应文件复制到指定的位置; 包含的内容可以是任何类型的文件,而不仅仅是.h文件; 上面的showMessage函数必须写在main()函数上面,如果写在下面则必须在main()函数之前声明; 注意:#include 包含文件时有两种方式:使用<>和””。区别就是<>包含只会查找编译器库函数文件,因此适用于包含库函数;而“”包含则首先查找程序当前目录,如果没有找到则查找库函数路径,因此适用于自定义文件; 运行过程 C语言的运行分为两大步:编译和链接 ·        编译:编译阶段会将对应的xxx.c源文件(ASCII格式)编译成目标文件xxx.obj,它是二进制格式(当然一般我们会有多个.c文件,也就会生成多个对应的.obj);在编译之前要进行预处理(例如#include指令),在编译的同时还要进行语法检查;生成的.obj文件并不能单独执行,因为各个.obj之间是有关联的,而且他们还各自引用了C语言库函数; ·        链接:链接的过程就是将各个.obj文件和C语言库函数一起组合生成一个可执行文件的过程; 扩展 在大型项目开发中程序中所有的代码都写到一个文件中是不现实的,我们通常将一个子操作分为两个文件:.c文件和.h文件。在.c文件中实现对应的函数,在.h中进行函数声明,这样只要在主函数上方包含对应的头文件就可以将子操作分离出来而且不用考虑顺序问题。例如改写“Hello World”的例子(注意message对应的.c和.h文件名完全可以不相同,但是出于规范的目的我们还是取相同的文件名): message.h // // Message.h // C语言基础 // // Created by Kenshin Cui on 14-7-12. // Copyright (c) 2014年 cmjstudio. All rights reserved. // void showMessage(); message.c // // Message.c // C语言基础 // // Created by Kenshin Cui on 14-7-12. // Copyright (c) 2014年 cmjstudio. All rights reserved. //   #include   void showMessage(){    printf("Hello,World!"); } main.c // // main.c // C语言基础 // // Created by Kenshin Cui on 14-7-12. // Copyright (c) 2014年 cmjstudio. All rights reserved. //   #include #include "Message.h"   int main(intargc, const char *argv[]) {    showMessage();     return 0; } 可以发现程序仍然可以正常运行,但是我们思考一个问题:如果我们不分成两个文件,直接在主函数文件中包含message.c是否也可以正常运行呢?答案是否定的,原因是由于编译生成的两个文件main.obj和 message.obj在链接时会发现main.obj中已经有message.obj中定义的showMessage函数,抛出“标示符重复”的错误。 了解更多IOS开发、C语言、OC基础、Swift等知识欢迎访问中软国际教育集团官网!

更多>
中软国际教育:关于Java内存管理的几个小技巧

中软国际教育:关于Java内存管理的几个小技巧

2017-02-21

这里将介绍几则Java内存管理的小技巧,让你让你从JAVA入门开始告别陋习,为Java程序提速。有不少人都说“Java完了,只等着衰亡吧!”,为什么呢?最简单的的例子就是Java做的系统时非常占内存!一听到这样的话,一定会有不少人站出来为Java辩护,并举出一堆的性能测试报告来证明这一点。其实从理论上来讲Java做的系统并不比其他语言开发出来的系统更占用内存,那么为什么却有这么多理由来证明它确实占内存呢?两个字,陋习。 1、用StringBuffer代替字符串相加。 这个我就不多讲了,因为已经被 人讲过N次了。我只想将一个不是笑话的笑话,我在看国内某“著名”java开发的WEB系统的源码中,竟然发现其中大量的使用字符串相加,一个拼装SQL 语句的方法中竟然最多构造了将近100个string实例。无语中! 2、别用new Integer。 和Boolean类似,java开发中使用Integer封装int的场合也非常 多,并且通常用int表示的数值通常都非常小。SUN SDK中对Integer的实例化进行了优化,Integer类缓存了-128到127这256个状态的Integer,如果使用 Integer.valueOf(int i),传入的int范围正好在此内,就返回静态实例。这样如果我们使用Integer.valueOf代替new Integer的话也将大大降低内存的占用。如果您的系统要在不同的SDK(比如IBM SDK)中使用的话,那么可以自己做了工具类封装一下,比如IntegerUtils.valueOf(),这样就可以在任何SDK中都可以使用这种特性。 3、别用new Boolean()。 在很多场景中Boolean类型是必须的,比如JDBC中boolean类型的set与get都是通过Boolean封装传递的,大部分ORM也是用Boolean来封装boolean类型的,比如: 以下是引用片段: ps.setBoolean(“isClosed”,new Boolean(true)); ps.setBoolean(“isClosed”,new Boolean(isClosed)); ps.setBoolean(“isClosed”,new Boolean(i==3)); 通常这些系统中构造的Boolean实例的个数是相当多的,所以系统中充满了大量Boolean实例小对象,这是相当消耗内存的。Boolean类实际上只要两个实例就够了,一个true的实例,一个false的实例。 Boolean类提供两了个静态变量: 以下是引用片段: public static final Boolean TRUE = new Boolean(true); public static final Boolean FALSE = new Boolean(false); 因为valueOf的内部实现是:return (b ? TRUE : FALSE); 所以可以节省大量内存。相信如果Java规范直接把Boolean的构造函数规定成private,就再也不会出现这种情况了。 4、过滥使用哈希表 有一定开发经验的开发人员经常会使用hash表(hash 表在JDK中的一个实现就是HashMap)来缓存一些数据,从而提高系统的运行速度。比如使用HashMap缓存一些物料信息、人员信息等基础资料,这 在提高系统速度的同时也加大了系统的内存占用,特别是当缓存的资料比较多的时候。其实我们可以使用操作系统中的缓存的概念来解决这个问题,也就是给被缓存的分配一个一定大小的缓存容器,按照一定的算法淘汰不需要继续缓存的对象,这样一方面会因为进行了对象缓存而提高了系统的运行效率,同时由于缓存容器不是无限制扩大,从而也减少了系统的内存占用。现在有很多开源的缓存实现项目,比如ehcache、 oscache等,这些项目都实现了FIFO、MRU等常见的缓存算法。 5、避免过深的类层次结构和过深的方法调用。 因为这两者都是非常占用内存的(特别是方法调用更是堆栈空间的消耗大户)。 6、对频繁使用的对象采用对象池技术。 7、尽量避免使用static变量,类内私有常量可以用final来代替。 8、变量只有在用到它的时候才定义和实例化。 9、保证每个IO操作,connection及时关闭。         做好以上几点,确保Java入门养成良好编程习惯。  了解更多java入门知识欢迎访问中软国际教育集团技术知识库

更多>
中软国际教育:如何获取控件坐标?

中软国际教育:如何获取控件坐标?

2017-02-21

getLocationOnScreen ,计算该视图在全局坐标系中的x,y值,(注意这个值是要从屏幕顶端算起,也就是索包括了通知栏的高度)//获取在当前屏幕内的绝对坐标  getLocationInWindow ,计算该视图在它所在的widnow的坐标x,y值,//获取在整个窗口内的绝对坐标 (不是很理解= =、) getLeft , getTop, getBottom, getRight, 这一组是获取相对在它父亲里的坐标 如果在Activity的OnCreate()事件输出那些参数,是全为0,要等UI控件都加载完了才能获取到这些。 了解更多精彩内容欢迎登陆中软国际教育集团官网!

更多>
中软国际教育:Android方向技术问答

中软国际教育:Android方向技术问答

2017-02-20

1.请描述下Activity的生命周期。 必调用的三个方法:onCreate() -->onStart()-->onResume(),用AAA表示 (1)父Activity启动子Activity,子Actvity退出,父Activity调用顺序如下 AAA -->onFreeze() -->onPause() -->onStop() -->onRestart()-->onStart(),onResume()… (2)用户点击Home,Actvity调用顺序如下 AAA -->onFreeze() -->onPause() -->onStop() -- Maybe -->onDestroy()– Maybe (3)调用finish(), Activity调用顺序如下 AAA -->onPause() -->onStop() -->onDestroy() (4)在Activity上显示dialog,Activity调用顺序如下 AAA (5)在父Activity上显示透明的或非全屏的activity,Activity调用顺序如下 AAA -->onFreeze() -->onPause() (6)设备进入睡眠状态,Activity调用顺序如下 AAA -->onFreeze() -->onPause() 2.如果后台的Activity由于某原因被系统回收了,如何在被系统回收之前保存当前状态?onSaveInstanceState() 当你的程序中某一个Activity A在运行时,主动或被动地运行另一个新的Activity B,这个时候A会执行onSaveInstanceState()。B完成以后又会来找A,这个时候就有两种情况:一是A被回收,二是A没有被回收,被回收的A就要重新调用onCreate()方法,不同于直接启动的是这回onCreate()里是带上了参数savedInstanceState;而没被收回的就直接执行onResume(),跳过onCreate()了。 3. 如何将一个Activity设置成窗口的样式。 在AndroidManifest.xml 中定义Activity的地方一句话android:theme="@android:style/Theme.Dialog"或android:theme="@android:style/Theme.Translucent"就变成半透明的 4.如何退出Activity?如何安全退出已调用多个Activity的Application? 对于单一Activity的应用来说,退出很简单,直接finish()即可。当然,也可以用killProcess()和System.exit()这样的方法。但是,对于多Activity的应用来说,在打开多个Activity后,如果想在最后打开的Activity直接退出,上边的方法都是没有用的,因为上边的方法都是结束一个Activity而已。 现提供几个方法,供参考: 1、抛异常强制退出: 该方法通过抛异常,使程序ForceClose。 验证可以,但是,需要解决的问题是,如何使程序结束掉,而不弹出Force Close的窗口。 2、记录打开的Activity: 每打开一个Activity,就记录下来。在需要退出时,关闭每一个Activity即可。 3、发送特定广播: 在需要结束应用时,发送一个特定的广播,每个Activity收到广播后,关闭即可。 4、递归退出 在打开新的Activity时使用startActivityForResult,然后自己加标志,在onActivityResult中处理,递归关闭。 除了第一个,都是想办法把每一个Activity都结束掉,间接达到目的。 但是这样做同样不完美。 你会发现,如果自己的应用程序对每一个Activity都设置了nosensor,在两个Activity结束的间隙,sensor可能有效了。但至少,我们的目的达到了,而且没有影响用户使用。为了编程方便,最好定义一个Activity基类,处理这些共通问题。 5.    请介绍下Android中常用的五种布局。 FrameLayout(框架布局),LinearLayout(线性布局),AbsoluteLayout(绝对布局),RelativeLayout(相对布局),TableLayout(表格布局) 6.    请介绍下Android的数据存储方式。 一.SharedPreferences方式 二.文件存储方式 三.SQLite数据库方式 四.内容提供器(Content provider)方式 五. 网络存储方式 7.     请介绍下ContentProvider是如何实现数据共享的。 创建一个属于你自己的Content provider或者将你的数据添加到一个已经存在的Contentprovider中,前提是有相同数据类型并且有写入Content provider的权限。 8.    如何启用Service,如何停用Service。 Android中的service类似于windows中的service,service一般没有用户操作界面,它运行于系统中不容易被用户发觉,可以使用它开发如监控之类的程序。 步骤: 第一步:继承Service类 public class SMSService extends Service { } 第二步:在AndroidManifest.xml文件中的节点里对服务进行配置: 二。Context.startService()和Context.bindService 服务不能自己运行,需要通过调用Context.startService()或Context.bindService()方法启动服务。这两个方法都可 以启动Service,但是它们的使用场合有所不同。 1.使用startService()方法启用服务,调用者与服务之间没有关连,即使调用者退出了,服务仍然运行。 使用bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止。 2.采用Context.startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onStart()方法。如果调用startService()方法前服务已经被创建,多次调用startService()方法并不会导致多次创建服务,但会导致多次调用onStart()方法。 采用startService()方法启动的服务,只能调用Context.stopService()方法结束服务,服务结束时会调用onDestroy()方法。 3.采用Context.bindService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onBind()方法。这个时候调用者和服务绑定在一起,调用者退出了,系统就会先调用服务的onUnbind()方法,。接着调用onDestroy()方法。如果调用bindService()方法前服务已经被绑定,多次调用bindService()方法并不会导致多次创建服务及绑定(也就是说onCreate()和onBind()方法并不会被多次调用)。如果调用者希望与正在绑定的服务解除绑定,可以调用unbindService()方法,调用该方法也会导致系统调用服务的onUnbind()-->onDestroy()方法。 三、Service的生命周期 1.Service常用生命周期回调方法如下: onCreate() 该方法在服务被创建时调用,该方法只会被调用一次,无论调用多少次startService()或bindService()方法,服务也只被创建一次。onDestroy()该方法在服务被终止时调用。 2. Context.startService()启动Service有关的生命周期方法 onStart() 只有采用Context.startService()方法启动服务时才会回调该方法。该方法在服务开始运行时被调用。 多次调用startService()方法尽管不会多次创建服务,但onStart()方法会被多次调用。 3. Context.bindService()启动Service有关的生命周期方法 onBind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法被多次调用。onUnbind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务解除绑定时被调用。 备注: 1. 采用startService()启动服务      Intent intent =newIntent(DemoActivity.this, DemoService.class); startService(intent); 2.Context.bindService()启动     Intent intent =newIntent(DemoActivity.this, DemoService.class); bindService(intent, conn, Context.BIND_AUTO_CREATE);    //unbindService(conn);//解除绑定 9.    请解释下在单线程模型中Message、Handler、MessageQueue、Looper之间的关系。Handler简介: 一个Handler允许你发送和处理Message和Runnable对象,这些对象和一个线程的MessageQueue相关联。每一个线程实例和一个单独的线程以及该线程的MessageQueue相关联。当你创建一个新的Handler时,它就和创建它的线程绑定在一起了。这里,线程我们也可以理解为线程的MessageQueue。从这一点上来看,Handler把Message和Runable对象传递给MessageQueue,而且在这些对象离开MessageQueue时,Handler负责执行他们。 Handler有两个主要的用途:(1)确定在将来的某个时间点执行一个或者一些Message和Runnable对象。(2)在其他线程(不是Handler绑定线程)中排入一些要执行的动作。 Scheduling Message,即(1),可以通过以下方法完成: post(Runnable):Runnable在handler绑定的线程上执行,也就是说不创建新线程。 postAtTime(Runnable,long): postDelayed(Runnable,long): sendEmptyMessage(int): sendMessage(Message): sendMessageAtTime(Message,long): sendMessageDelayed(Message,long): post这个动作让你把Runnable对象排入MessageQueue,MessageQueue受到这些消息的时候执行他们,当然以一定的排序。sendMessage这个动作允许你把Message对象排成队列,这些Message对象包含一些信息,Handler的hanlerMessage(Message)会处理这些Message.当然,handlerMessage(Message)必须由Handler的子类来重写。这是编程人员需要作的事。 当posting或者sending到一个Hanler时,你可以有三种行为:当MessageQueue准备好就处理,定义一个延迟时间,定义一个精确的时间去处理。后两者允许你实现timeout,tick,和基于时间的行为。当你的应用创建一个新的进程时,主线程(也就是UI线程)自带一个MessageQueue,这个MessageQueue管理顶层的应用对象(像activities,broadcastreceivers等)和主线程创建的窗体。你可以创建自己的线程,并通过一个Handler和主线程进行通信。这和之前一样,通过post和sendmessage来完成,差别在于在哪一个线程中执行这么方法。在恰当的时候,给定的Runnable和Message将在Handler的MessageQueue中被Scheduled。 Message简介: Message类就是定义了一个信息,这个信息中包含一个描述符和任意的数据对象,这个信息被用来传递给Handler.Message对象提供额外的两个int域和一个Object域,这可以让你在大多数情况下不用作分配的动作。 尽管Message的构造函数是public的,但是获取Message实例的最好方法是调用Message.obtain(),或者Handler.obtainMessage()方法,这些方法会从回收对象池中获取一个。 MessageQueue简介: 这是一个包含message列表的底层类。Looper负责分发这些message。Messages并不是直接加到一个MessageQueue中,而是通过MessageQueue.IdleHandler关联到Looper。 你可以通过Looper.myQueue()从当前线程中获取MessageQueue。 Looper简介: Looper类被用来执行一个线程中的message循环。默认情况,没有一个消息循环关联到线程。在线程中调用prepare()创建一个Looper,然后用loop()来处理messages,直到循环终止。 大多数和message loop的交互是通过Handler。 下面是一个典型的带有Looper的线程实现。   class LooperThread extends Thread {       public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() {               publicvoidhandleMessage(Message msg) {                   // processincomingmessages here               }           }; Looper.loop(); } 10.       AIDL的全称是什么?如何工作?能处理哪些类型的数据?AIDL的英文全称是Android InterfaceDefine Language 当A进程要去调用B进程中的service时,并实现通信,我们通常都是通过AIDL来操作的 A工程: 首先我们在net.blogjava.mobile.aidlservice包中创建一个RemoteService.aidl文件,在里面我们自定义一个接口,含有方法get。ADT插件会在gen目录下自动生成一个RemoteService.java文件,该类中含有一个名为RemoteService.stub的内部类,该内部类中含有aidl文件接口的get方法。 说明一:aidl文件的位置不固定,可以任意 然后定义自己的MyService类,在MyService类中自定义一个内部类去继承RemoteService.stub这个内部类,实现get方法。在onBind方法中返回这个内部类的对象,系统会自动将这个对象封装成IBinder对象,传递给他的调用者。 其次需要在AndroidManifest.xml文件中配置MyService类,代码如下: 为什么要指定调用AIDL服务的ID,就是要告诉外界MyService这个类能够被别的进程访问,只要别的进程知道这个ID,正是有了这个ID,B工程才能找到A工程实现通信。 说明:AIDL并不需要权限 B工程: 首先我们要将A工程中生成的RemoteService.java文件拷贝到B工程中,在bindService方法中绑定aidl服务 绑定AIDL服务就是将RemoteService的ID作为intent的action参数。 说明:如果我们单独将RemoteService.aidl文件放在一个包里,那个在我们将gen目录下的该包拷贝到B工程中。如果我们将RemoteService.aidl文件和我们的其他类存放在一起,那么我们在B工程中就要建立相应的包,以保证RmoteService.java文件的报名正确,我们不能修改RemoteService.java文件         bindService(newInten("net.blogjava.mobile.aidlservice.RemoteService"),serviceConnection,Context.BIND_AUTO_CREATE); ServiceConnection的onServiceConnected(ComponentName name,IBinderservice)方法中的service参数就是A工程中MyService类中继承了RemoteService.stub类的内部类的对象。 了解更多Android开发知识欢迎访问中软国际教育官网

更多>
中软国际教育:云计算知识问答

中软国际教育:云计算知识问答

2017-02-20

1、什么是shell,以及作用? shell就是命令解释器,它提供了用户与操作系统之间基于命令行的交互界面,用户命令行输入命令,由shell对它们进行解释,并将其送往操作系统执行。 2、常用磁盘阵列类型及优缺点 Raid 0 又叫磁盘分条,需要大于等于2块磁盘完成,速度最快,没有容错功能,因为数据是分成奇数条和偶数条分条同时在两个硬盘中同时写入,所以速度最快,磁盘空间利用率100%。 Raid 1 镜像卷,两块硬盘实现,速度不快,有容错功能,空间利用率50%。因为把相同的数据写入了2遍所以有容错功能。 Raid 5 大于等于3块硬盘实现,有容错功能,速度较快。磁盘空间利用率(n-1)/n.因为三块磁盘,其中2块磁盘在做raid 0,剩下的一块硬盘是校验。 一块硬盘中刨除主分区以外剩余所有的空间都是扩展分区,所有的逻辑分区之和组成扩展分区。linux中1-4是预留给主分区和扩展分区的,主分区至少要有1个,之多可以有4个,扩展分区至多只能有1个或者没有,但是主分区加上扩张分区数量不能超过4个。扩展分区下必须再分逻辑分区,不然空间不能被格式化,逻辑分区的数量没有限制。 更多软件编程知识欢迎登陆中软国际教育集团官网www.zretc.com!

更多>

推荐阅读

更多

中软卓越java培训地址:北京市海淀区科学院南路2号融科资讯中心C座北楼12层 联系电话:400-666-3775 邮箱账号:etc-marketing@chinasofti.com

©2008-2016 北京中软国际教育科技股份有限公司 京ICP备14058756号-2