【千锋3G 学院】
来源:互联网 发布:mac ps字体包下载 编辑:程序博客网 时间:2024/04/30 14:23
第01讲:基本语法
主要内容:
1> 类的声明
2> 函数/ 消息的定义方法
3> 字段作用域
语法纵览
1> OC 是C 语言的面向对象的一个超集。
2> OC 最初只是为了给C 设计一款最小化的面向对象的语法。同时完全兼容C 语言。
3> 为了避免和已有的C、C++ 关键字冲突。所有OC关键字都以@开始,如:
@class, @interface, @implementation, @public, @private, @protected, @try, @catch, @throw, @finally, @end, @protocol, @selector, @synchronized, @encode, @defs
4> OC2.0 引入的关键字
@optional, @required, @property, @dynamic, @synthesize
基本面向过程
面向对象概述
和C/C++ 一些比较
1> OC 和 C/C++ 一样,都是用如下:
/* */ 和 // 作为注释
2> BOOL, YES, NO
在C++ 中,布尔类型是bool,在OC中,布尔类型是BOOL,布尔值有YES 和 NO 两种。
3> id 类型
OC 中,每个目标都可以表达为id 类型,范型,可以认为NSObject * 或者 void *
4> nil
nil 等同于null,表示一个目标的指针
类定义
OC 类分为2 种文件,一种是.h ,另一种是.m 文件。
.h 文件存放类,函数声明
.m 文件存放类的具体实现
类声明使用关键字@interface @end 来声明
类实现使用关键字@implementation @end 来实现
对象方法和类方法
如果声明和实现一个类的函数,需要使用 + 或 - 来用在函数开始。
+ 表示类的方法。
- 表示对象的方法。
类声明 < Dog.h >
#import <Foundation / Foundation.h >
@interface Dog: NSObject
{ }
@end
类实现< Dog.m >
#import "DOg.h"
@implementation Dog
@end
To import or include ?
OC 语言包含头文件格式:#import head.h
C/C++ 语言包含头文件格式:
#ifndef _HEAD_H_
#define _HEAD_H_
#endif
1> C/C++ 使用 #include 来包含头文件。缺点就是可能同一个头文件被包含多次。
2> OC 使用了#import 来包含头文件。优点就是同一个头文件只能包含一次。
创建 / 销毁OC 对象
创建对象
Dog *dog = [ Dog alloc ];
初始化构造函数
[ dog init ];
销毁对象
[ dog release];
类中字段和函数
@interface Dog: NSObject
{ // 字段定义在左右花括号之间
int age;
}
-(void) setAge:(int)newAge; // 函数定义在右花括号和@end 之间。
@end
字段定义
C++ 和OC 在变量声明一样,都有public、protected、private 三种作用域。
C++: public: protected: private:
OC: @public @protected @private
OC 缺省是@protected
C++ 和OC 在函数声明不一样
OC 函数全部都是public 类型(用另外方式实现private 化)
变量必须定义在类{ }之间的地方
变量作用域声明
// OC 中 文件 Dog.h
@interface Dog: NSObject
{
@public
int age;
@protected
int ID;
@private
float price;
}
@end
字段作用域解释
@public 对象该字段是全局,均可访问
@protected 对象该字段是保护类型,只有在类本身或者子类中可以访问
@private 只能在类内部才可以访问
类声明比较
所有OC类,接口声明必须要带*
这里* 即表示指针也表示引用
OC 中
Dog * myDog;
可以通过myDog->dog 或者myDog.dog 这些方法来访问
一个典型的类定义和实现
扩充Dog 类实现基本的变量和函数
类声明 < Dog.h >
#import <Foundation/Foundation.h>
@interface Dog: NSObject
{
int age;
}
-(id) init;
-(id) initWithAge:(int)newAge;
-(int) getAge;
-(void) setAge:(int) newAge;
@end
// Dog.m
#import "Dog.h"
@implementation Dog
-(id) init { return [self initWithAge:10 ]:}
-(id) initWithAge: (int) newAge
{ self = [super init ];
if( self ) {
age = newAge;
}
return self;
}
-(int) getAge
{
return age;
}
-(void) setAge:(int) newAge
{
age = newAge;
}
@end
函数定义
在OC中属性是声明只能在@interface { 和 } 之间。
属性的使用和C 语言类似
在@interface { 和 } 之间不能定义方法。
方法的定义是:
-(int) f: (int) x;
这里 - 表示对象的方法, + 表示类的方法和C ++ 类似
返回值或参数的类型声明是使用() 包含
参数分割使用:来分开
函数定义例子
典型的函数和变量定义
// 文件 Foo.h
@interface Foo: NSObject
{
double x;
}
-(int) f:(int) x;
-(float) g:(int) x :(int) y;
@end
// 文件Foo.m
@import "Foo.h"
@implementation Foo
-(int) f:(int) x {...}
-(float) g:(int) x :(int) y {...}
@end
多参数情况
1> 函数不带参数(函数名:f)
-(int) f // 类似C int f() 函数
2> 带一个参数(函数名:f: x )
-(int) f:(int) x // 类似C 的 int f(int x) 函数
3> 带两个参数(函数名:f::)
-(float) f:(int) x :(int) y // 类似C 的 float f(int x, int y) 函数
多参数方法
1> 带两个参数(函数名:f::)
-(float) f:(int) x :(int) y
参数能够在冒号(:) 前面设置一个标签label,标签label 也是函数名的一部分,标签是为了方便阅读(不带标签实际上也有一个匿名标签)。
比如上述函数可以改成
-(float) f:(int) x g:(int) y // 这里g 表示标签,函数名是 f: g:
第一个参数不能有标签,事实上函数名就是第一个参数的标签。
函数调用对别
三个参数例子
C 例子
int insertObjectAtIndexBefore( Object o, int index, boolean before );
int ret = obj -> insertObjectAtIndexBefore( str, 2, true );
OC 例子
-(int) insertObject:(NSObject * ) o AtIndex:(int) index Before:(BOOL) before
int ret = [obj insertObject:10 AtIndex:2 Before: TRUE ];
多参数的方法调用
函数重载
OC 不是严格的函数重载
@interface Foo: NSObject
{ }
-(int) g:(int) x;
-(int) g:(float) x; // 错误,这个方法和前一个方法冲突(因为没有标签)
-(int) g:(int) x :(int) y; // 正确,两个匿名的标签
-(int) g:(int) x :(float) y; // 错误,也是两个匿名的标签
-(int) g:(int) x andY:(int) y; // 正确,第二个标签是andY
-(int) g:(int) x andY:(float) y; // 错误,第二个标签是andY
-(int) g:(int) x andAlsoY:(int) y; // 正确,第二个标签是andAlsoY
@end
各类函数名
@interface Foo: NSObject
{ }
// 函数名是 g
-(int) g;
// 函数名是 g:
-(int) g: (float) x;
// 函数名是 g::
-(int) g:(float) x :(float) y;
// 函数名是 g:andY:
-(int) g: (float) x andY:(float) y;
// 函数名是 g:andZ:
-(int) g:(float) x andZ:(float) z
@end
Messages 消息机制(函数、方法、消息本质一样,OC 术语严格的称为消息)
1> 使用发送目标对象一个消息来达到处理函数
2> 使用如下的格式来发送消息
[ object message]
object.message
3> 因为是动态绑定,消息和接受者都是在运行时动态绑定在一起。
函数作用域声明
1> OC 在.h 头文件定义的所有函数都是public 类型
2> OC 通过Categories 来实现函数的私有化
4> object 表示一个对象或一个类
5> message 消息也可以认为是一个函数。
练习
Xcode 4.2 -- Create a new Xcode project -- Mac OS X --Application -- Command Line Tool -- Next -- Product Name --
第02 讲:点语法 Dot Syntax
主要内容
1> 为什么需要点语法、点语法好处是什么?
2> @property @synthesize 如何使用?
3> @property @synthesize 编译器如何展开?
4> 如何使用点语法?
5> @property 其它属性
为什么要设计点语法
1> 为了方便别的程序员转到OC开发上来。
2> 为了让程序设计简单化。
3> 隐藏了内存管理细节。
4> 隐藏了多线程、同步、加锁细节。
点语法
1> 属性可以在不使用括号的情况下使用点语法
2> 无需调用[foo value] 可以使用foo.value 来访问。虽然foo.value 看起来像是直接访问value变量,但是属性始终调用方法,而这些方法又可以访问对象的属性。
// Dog.h 头文件声明
@interface Dog: NSObject
{
int age;
}
-(void) setAge: (int) newAge;
-(void) age;
@end
// Dog.m 实现
@import "Dog.h"
@implementation Dog
-(void) setAge:(int) newAge
{
age = newAge;
}
-(int) age
{
return age;
}
@end
setter 和 getter 函数
-(void) setAge:(int) newAge;
-(int) age;
类似于setAge: 设置新值一般叫做setter 函数。
类似于age 取值一般叫做getter 函数。
使用经典调用和点语法
Dog *dog = [ [Dog alloc] init ];
[dog setAge: 100 ];
int dogAge = [dog age];
NSLog(@"Dog Age is %d", dogAge);
dog.age = 200;
dogAge = dog.age;
NSLog(@"Dog new Age is %d", dogAge);
点语法是编译器级别
dog.age = 200;
dogAge = [dog age ];
编译器会把 dog.age = 200; 展开成 [dog setAge: 200 ];
会把 dogAge = dog.age; 展开成dogAge = [dog age];
函数调用
点语法setter 和 getter 规范
1> 属性一般需要提供赋值方法setter 和取值方法getter
2> 赋值方法用于设置信息,取值方法用于获取信息,可以使用任意名字定义赋值方法和取值方法,也可使用OC约定的方法。
3> 属性前面带有set 前缀的设置方法,如:
@property int age; [ 在类声明中]
@synthesize age; [ 在类实现中]
@property
@property 是让编译器自动产生函数声明
不用写下面2行代码
-(void) setAge:(int) newAge;
-(int) age;
只需要下列一行就可以代替
@property int age;
@property 进一步说明
@interface Dog: NSObject
{
int _age;
}
@property int age;
@end
@synthesize age = _age;
目的是避免函数名和字段重复
@synthesize
@synthesize 就是编译器自动实现 getter 和 setter 函数
不用写下列代码
-(void) setAge: (int) newAge
{
age = newAge;
}
-(int) age
{
return age;
}
只需要写
@synthesize age;
总结:
类内部age 和 self.age 是不一样的
1> 在Dog 类内部可以直接访问 age 变量
2> 直接访问age 相当于 age 字段
3> self.age 是调用getter 或者 setter 函数
Dog.m @synthesize 展开实现
#import "Dog.h"
@implementation Dog
-(void) setAge:(int) newAge
{
_age = newAge;
}
-(int) age
{
return _age;
}
@end
属性可以是:
1> readwrite(缺省),readonly 表示属性是可读写的,也就是可以使用getter 和 setter, 而readonly 只能使用 getter。
2> assign(缺省),retain, copy 表示属性如何存储。
3> getter= ..., setter = ... 重新设置getter 函数和 setter 函数名。
第03讲:内存管理1
主要内容
1> OC 内存管理原理?
2> OC 内存管理相对C/C++ 有何好处?
3> OC 内存管理的alloc、retain、release
4> 遛狗原理
5> OC 对象生命周期
内存管理---- 黄金法则
The basic rule to apply is Everything that increases the reference counter with alloc, [mutable] copy [WithZone:] or retain is in charge of the corresponding [auto] release.
1> when you explicitly instantiate an object with alloc;
2> when you explicitly clone the object with copy [WithZone: ] or mutableCopy[WithZone:] (whatever the copy is: a real or a pseudo-clone. This should not have any importance)
3> when you explicitly use retain.
黄金法则 简述版
如果对一个对象使用了alloc,[mutable] copy,retain, 那么你必须使用相应的 release 或 qutorelease.
内存管理 类型定义
1> 基本类型 任何C 的类型,如:int、short、char、long、long long、struct、enum、union 等属于基本类型或结构体。
2> 内存管理对于C 语言基本类型无效。
3> OC 类型(非基本类型)。
4> 任何继承于 NSObject 类的对象都属于 OC 类型。
5> 也就是除了C 之外的其他类型。
OC 对象结构
1> 所有OC 对象都有一个计数器
2> 保留着当前被引用的数量
C/C++ 内管原理
C / C++ 内存管理代码
int *p1 = malloc (100);
int *p2 = p1;
int *p3 = p1;
free(p2);
free(p2);
内存管理对象
1> 对于OC 的对象,非基本对象(int、short、struct )。
2> NSObject ,凡是继承于NSObject。
3> 每一个对象都有一个retainCount 计数器。表示当前的被应用的计数。如果计数为0, 那么就真正的释放这个对象。
内存管理图示
1> 这就是引用计数的理论。在实际应用中,通常只有两个原因我们才会创建一个对象:
a: 作为一个实例变量保留。
b: 在函数内部作为临时变量使用。大多数情况下,一个实例变量的设置器(setter) 会自动释放(autorelease)。
2> 原来引用的对象,同时保留(retain)新的。你只需要保证在 dealloc 函数中释放(release)了它就行了。
遛狗原理
OC 内存管理
1> OC 类中实现了引用计数器,对象知道当前被引用的次数。
2> 最初对象的计数器是1。
3> 如果需要引用对象,可以给对象发送一个retain消息,这样对象计数器就加1。
4> 当不需要引用对象了,可以给对象发送release 消息,这样对象计数器就减1。
5> 当计数器减到0,自动调用对象的dealloc 函数,对象就会释放内存。
6> 计数器为0 的对象不能再使用release 和其他方法。
alloc 、retain、release 函数
1> alloc 函数是创建对象使用,创建完成后计算器为1
只用一次
2> retain 函数是对一个对象的计数器+ 1
可调用多次
3> release 函数是对一个对象计数器- 1
减到0 对象就会从内存中释放
retain / release 例子
NSMutableString *str = [[NSMutableString alloc] init ];
// str 计数器为1
[ str retain]; // str 计数器为2
[ str retain]; // str 计数器为3
[ str release]; // str 计数器为2
[ str release]; // str 计数器为1
[ str release]; // str 计数器为0, 对象释放内存
内存管理总结
1> OC 的内存管理机制与.Net / Java 那种全自动的垃圾回收机制是不同的,它本质上还是C 语言中的手动管理方式,只不过稍微加了一些自动方法。
2> OC 的内存管理是基于引用计数的。要做的事情只是关注的引用,而释放内存的工作实际上由运行环境完成。
3> 在最简单的情形中,分配的(alloc)对象,或是保留(retain)在一些地方的对象,都需要发送一个 release 消息。这也意味着,如果使用了一次 alloc ,然后又retain 了一次,那你需要release 两次才能释放该对象的内存。
下面三种增加对象计数器
1> 当明确的使用alloc 方法来分配对象。
2> 当明确的使用copy[WithZone: ] 或 mutableCopy[WithZone:] 来copy 对象时。
3> 当明确使用retain 消息。
上述三种方法使得计数器增加,那么就需要使用[auto] release 来明确释放对象, 也就是递减计数器。
第04讲:内存管理2
内存管理---- retain / copy
主要内容
1> retain 属性主要作用。
2> @property (retain) 编译器如何申请?
3> @synthesize 编译器如何展开实现。
4> dealloc 需要注意内容。
5> copy 属性的主要作用。
属性可以是:
1> readwrite(缺省),readonly 表示属性是可读写的,也就是可以使用getter 和 setter ,而readonly 只能使用 getter。
2> assign(缺省),retain, copy 表示属性如何存储。
3> nonatomic 表示不用考虑线程安全问题。
4> getter = ..., setter = ... 重新设置getter 函数 和 setter 函数名。
OC 内存管理和点语法
1> OC 内存管理正常情况要使用大量的retain 和 release 操作。
2> 点语法可以减少使用retain 和 release 的操作。
// Person.h 头文件声明
@interface Person:NSObject
{
Dog *_dog;
}
@property (retain) Dog *dog;
@end
// Person.m 实现文件
@implementation Person
@synthesize dog = _dog;
-(void) dealloc
{
self.dog = nil;
[super dealloc];
}
@end
编译器对于retain 展开形式
1> 编译器对于@property 中的retain 展开是不一样的。
2> 主要是要释放上一次的值,增加本次计数器。
@property 展开(retain 属性)
@property (retain) Dog *dog;
仍然是展开为:
-(void) setDog:(Dog *) aDog;
-(Dog *) dog;
@synthesize(retain 属性)
@synthesize dog = _dog;
展开为:
-(void) setDog:(Dog *)aDog
{
if(_dog != aDog)
{
[ _dog release ];
_dog = [ aDog retain ];
}
}
-(Dog * )dog
{
return _dog;
}
dealloc 必须要释放dog (retain)
-(void) dealloc
{
self.dog = nil;
[super dealloc ];
}
copy 属性
1> copy 属性是完全把对象重新拷贝了一份,计数器重新设置为1, 和之前拷贝的数据完全脱离关系。
@property (copy) NSString * str;
// 表示属性的getter 函数
-(double) str
{ return str; }
// 表示属性的setter 函数
-(void) setStr: (NSString *) newStr
{ str = [newStr copy ]; }
assign, retain, copy
1> foo = value; // 简单的引用赋值
2> foo = [value retain ]; // 引用赋值,并且增加value 的计数器
3> foo = [value copy ]; // 将value 复制了一份给foo,复制后,foo 和 value 就毫无关系
第05讲:内存管理3
内存管理 --- 自定义MyArray
主要内容
1> 了解NSMutableArray 如何实现?
2> 进一步深入内存管理
NSMutableArray 典型用法
NSMutableArray *array = [[NSMutableArray alloc] init ];
for(int i = 0; i < 10; i++)
{
Dog *dog = [[Dog alloc ] init ];
[dog setID: i ];
[array addObject: dog ];
[dog release];
}
for(Dog * d in array )
{
NSLog(@"dog is %d", [d ID]);
}
[array release];
MyArray 提供方法
-(NSInteger) addObject: (id) object;
-(id) objectAtIndex:(NSUInteger) index;
-(void) removeObjectAtIndex: (NSUInteger) index;
-(void) removeAll;
第06讲:内存管理4
内存管理----自动释放池(AutoreleasePool)
主要内容
1> 什么是自动释放池?
2> 自动释放池的好处?
3> 如何创建一个自动释放池?
4> 自动释放池如何释放对象内存?
5> 自动释放池栈式结构管理?
Autorelease Pool
1> 自动释放池(Autorelease Pool)是OC 的一种内存自动回收机制,可以将一些临时变量通过自动释放池来回收统一释放。
2> 当自动释放池本身销毁的时候,池子里面所有的对象都会做一次 release 操作。
autorelease
任何OC 对象只要调用autorelease 方法,就会把该对象放到离自己最近的自动释放池中(栈顶的释放池)。
创建自动释放池
// iOS 5.0 新方式
@autoreleasepool
{
}
// iOS 5.0 之前老方式
NSAutoreleasePool * pool = [[ NSAutoreleasePool alloc ] init ];
[pool release ];
遛狗原理
典型例子(正确)
Dog *dog1 = [[Dog alloc ] init ];
[xiaoLi setDog:dog1];
[dog1 release];
典型例子(正确)
Dog *dog1 = [[[Dog alloc ] init] autorelease ];
[xiaoLi setDog:dog1];
// 这里不能 [dog1 release];
典型例子(错误)
[xiaoLi setDog: [[Dog alloc] init ] ]; // 该代码有内存泄露。
遛狗原理
黄金法则
1> 如果对一个对象使用了alloc, [mutable] copy , ratain, 那么必须使用相应的 release 或者 autorelease。
典型例子(正确)
[xiaoLi setDog: [[[Dog alloc] init ] autorelease ] ];
Point 2D 类
看一个例子(错误)
-(Point2D*) add:(Point2D*) p1 and:(Point2D*)p2
{
Point2D* result = [[Point2D alloc] init ];
result.x = p1.x + p2.x;
result.y = p1.y + p2.y;
return result;
}
// 错误:该函数使用了alloc , 它创建了对象,并且计数器为1,根据规定,它应该明确的使用release 来释放它。
// 下面代码执行就会导致内存泄露:会产生3个匿名的对象
[calculator add:[calculator add:p1 and:p2 ] and:p3 ];
例子的另外一种写法(错误)
-(Point2D*) add:(Point2D*) p1 and:(Point2D*)p2
{
Point2D* result = [[Point2D alloc] init ];
result.x = p1.x + p2.x;
result.y = p1.y + p2.y;
[result release ];
return result;
}
// 错误:显然,刚使用alloc 创建了就release 了,所以返回的result 是无效的。
看一个例子(正确)
-(Point2D*) add:(Point2D*) p1 and:(Point2D*)p2
{
Point2D* result = [[Point2D alloc] init ];
result.x = p1.x + p2.x;
result.y = p1.y + p2.y;
[result autorelease ];
return result;
}
[calculator add:[calculator add:p1 and:p2] and:p3 ];
//正确:[result autorelease] 可以认为是等一会儿在调用release 消息。“等一会儿”的意思是等[calculator add:[calculator add:p1 and: p2] and: p3]; 执行完了就调用release 消息。
自动释放池原理
一个例子
int index;
for(index = 0; index < 1000000; index++ )
{
NSMutableString *str = [[NSMutableString alloc ] init ];
[str autorelease];
}
// 该程序要迭代100万次,会产生100万个str 自动释放的对象。但这100万个对象在该循环体内不会自动销毁。只会放在一个最近的自动释放池内。只有当自动释放池销毁了,这100万个对象才能收到release 消息。所以在这个循环体内,这100 万个对象还是在内存中。
解决方法
NSAutoreleasePoll *pool;
pool = [[NSAutoreleasepoll alloc] init ];
int index;
for(index = 0; index < 1000000; index++)
{
NSMutableString *str = [[NSMutableString alloc] init ];
[str autorelease];
if(index % 1000 == 0)
{
[pool release];
pool = [[ NSAutoreleasePoll alloc ] init ];
}
}
[pool release];
// 该程序每执行1000次,就把pool 销毁,同时也会销毁在pool 上注册的自动释放对象。也就是str 累计不会超过1000个对象。
iPhone 典型的main 函数开头
int main(int argc , char * argv[ ] )
{
NSAutoreleasePool * pool = [[ NSAutoreleasePool alloc] init ];
//....
[pool release]; // [pool drain ]
return 0;
}
类的构造函数
+(id) dog
{
return [[[Dog alloc] init ] autorelease];
}
可以通过
Dog *dog2 = [Dog dog];
xiaoMing.dog = dog2;
或
xiaoMing.dog = [Dog dog];
选择好的构造函数
// 麻烦
NSNumber * zero_a = [[NSNumber alloc] initWIthFloat: 0.0f ] ;
// 使用zero_a 变量
...
[zero_a release];
...
// 方便
NSNumber *zero_b = [NSNumber numberWithFloat:0.0f ];
...
// 决不能[zero_b release];
使用完毕就 release
另外一种写法
使用
第07讲:协议(protocol)
主要内容
1> 什么是协议?
2> 如何定义协议?
3> 如何使用协议?
什么是协议
1> 协议是多个对象之间协商的一个接口对象。
2> 协议提供一系列方法用来在协议的实现者和代理者之间的一种通信方式。
3> 协议类似于C++ 中的纯虚函数,或者Java 中的接口。
协议声明
// 文件foo.h
@protocol MyProtocol <NSObject>
// 要定义的变量
-(void) init;
-(int) update:(int) time;
@end
协议
1> protocol 声明一系列方法,这些放在实现protocol 中实现。
2> 协议方法可以实现optional,可选实现。
3> @required
4> @optional
5> 协议需要继承于 基协议NSObject
6> 协议可以多继承
协议声明
// 文件Foo.h
@protocol MyProtocol <NSObject>
// 要定义的变量
@optional
-(void) init;
-(void) exit;
@required
-(int) update:(int) time;
@end
OC 定义协议和实现协议
// 文件Foo.h
@protocol MouseListener
@optional
-(BOOL) mousePressed;
-(BOOL) mouseClicked;
@end
@protocol KeyboardListener
-(BOOL) keyPressed;
@end
@interface Foo: NSObject < MouseListener, KeyboardListener >
{
...
}
@end
一个简单协议例子
协议使用例子
判断某个对象是否响应方法
1> 既然接口可以部分实现,OC 对象提供了动态判断某个方法是否实现的方法
2> respondsToSelector
if([test respondsToSelector:@selector(showInfo)])
{
[test showInfo];
}
respondsToSelector
-(BOOL) doWork
{
if([test respondsToSelector:@selector(showInfo)])
{
[test showInfo];
return YES;
}
return NO;
}
第08讲:协议代理设计模式
协议 Delegate 代理模式
主要内容
1> 协议的具体用法?
2> 如何实现代理?
3> 代理2 端如何通讯?
案例
- 【千锋3G 学院】
- 千锋3G学院-iOS开发视频教程
- 千锋3G 课程名称
- 移动平台 iPhone开发基础视频教程-第1季_千锋学院出品
- 千元Android 3G手机普及是场梦
- 手机游戏市场分析-3G手机开发公开课-东方尚智,3g数字内容学院
- j2me打包,FPS射击类游戏的实现-3G手机开发公开课-东方尚智,3g数字内容学院
- j2me记录仓库,手机电子书实现-3G手机开发公开课-东方尚智,3g数字内容学院
- 千锋swift培训教程
- 3G
- 3G
- 3G
- 3G
- 3G
- 3G
- 3G
- 3G
- 3G
- 黑马程序员——类加载器
- 记一次薪酬谈判的教训
- MySQL 5.5.30 发布
- expdp 使用parfile时出现在LRM-00112错误‘user——id不允许多个值'
- 排序问题-《编程珠玑》 ch1 开篇_ 1.6.3
- 【千锋3G 学院】
- 判断字符串是否包含中文的正则表达式
- Taxi Fare
- 牛人给出的编译Linux内核的详细过程
- 百度地图Android sdk开发笔记五修改定位位置的图标
- 内核态文件操作
- 三种嵌入式操作系统的分析与比较
- 限制对比度自适应直方图均衡化算法原理、实现及效果
- .net中AspNetPager的使用方法