简介

  当我开始为iOS写代码的时候,我意识到,作为一个C++开发者,我必须花费更多的时间来弄清楚Objective-C中怪异的东西。这就是一个帮助C++专家的快速指南,能够使他们快速的掌握Apple的iOS语言。

  请注意这绝不是一个完整的指南,但是它让你避免了阅读100页的手册。除此之外,我知道你喜欢我的写作风格。

  背景

  需要C++的技能,我会比较C++和Objective-C的东西。此外,COM编程也是有用的,因为Objective-C有类似于IUnkown的东西,因此基础的COM编程是有帮助的(但不是必须的)

  Objective C++是C++和Objective C的组合。你也能使用任何C++的东西混合到Objective C中,但是记住重新命名你的文件从.m到.mm

  铛 - 铛!

  我们马上就开始我们的教程. 首先我会介绍 Objective-C 的东西,然后是C++中与它对等的东西.

  成员函数

1
2
3
4
5
6
7
8
9
10
11
12
// Objective-C
- (int) foo : (int) a : (char) b {}
+ (int) foo : (int) a : (char) b {}
 
// C++
int foo(int a,char b) {} 
static int foo(int a,char b) {}
 
// Objective-C
- (void) foo2  val1:(int) a; // named argument
// <span id="22_nwp" style="width: auto; height: auto; float: none;"><a id="22_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=18&is_app=0&jk=b2645dbfe197c88d&k=call&k0=call&kdi0=0&luki=1&n=10&p=baidu&q=06011078_cpr&rb=0&rs=1&seller_id=1&sid=8dc897e1bf5d64b2&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1922429&u=http%3A%2F%2Fwww%2Eadmin10000%2Ecom%2Fdocument%2F4400%2Ehtml&urlid=0" target="_blank" mpid="22" style="text-decoration: none;"><span style="color:#0000ff;font-size:14px;width:auto;height:auto;float:none;">call</span></a></span>
[obj foo2 val1:5];  // merely helper: You remember that 5 is assigned to param name val1.

  - 表示的是一个一般的成员函数(通过一个对象实体访问), 而 + 则表示一个静态成员函数, 不需要使用实体就能访问. 当然,像C++, 静态成员不能访问实体变量.

  此外,Objective-C函数函数可以有赋予了名称的参数,这样让什么参数获得什么值会更一目了然. 理论上,被赋予了名称的参数允许程序员按任何顺序传入参数,但是Objective-C却规定要按声明的顺序传参.

  通过一个指针或者一个静态成员调用一个成员

1
2
3
4
5
6
7
8
9
// Objective-C
NSObject* ptr = ...; // some pointer
[ptr foo:5:3]; // <span id="19_nwp" style="width: auto; height: auto; float: none;"><a id="19_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=18&is_app=0&jk=b2645dbfe197c88d&k=call&k0=call&kdi0=0&luki=1&n=10&p=baidu&q=06011078_cpr&rb=0&rs=1&seller_id=1&sid=8dc897e1bf5d64b2&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1922429&u=http%3A%2F%2Fwww%2Eadmin10000%2Ecom%2Fdocument%2F4400%2Ehtml&urlid=0" target="_blank" mpid="19" style="text-decoration: none;"><span style="color:#0000ff;font-size:14px;width:auto;height:auto;float:none;">call</span></a></span> foo member with arguments 5 and 3
[NSObject staticfoo:5:3];  // call static function of NSOBject with arguments 4 and 3
 
// C++
CPPObject* ptr = ...; // some pointer
ptr->foo(5,3);
CPPObject::staticfoo(5,3);

  Objective-C 使用 [ ] 来调用成员函数并传入用:分割开的参数, 其对于ObjectiveC中ptr为nil的情况非常友好,在这种情况下“调用”将会被忽略掉(而在C++中,这种情况会抛出一个指针冲突异常 ). 这使得消除对nil对象的检查成为可能.

  协议VS接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Objective-C
@protocol foo
- (void) somefunction;
@end
 
@interface c1 : NSObject<foo>
 
@end
 
@implementation c1
- (void) somefunction { ... }
@end
 
// C++
class foo
{
virtual void somefunction() = 0;
};
 
class c1 : public NSObject, public foo
{
void somefunction() { ... }
}

  协议= 抽象类. Objective-C 和 C++ 之间的区别在于,在 Objective-C 中, 函数并不是必须要被实现的. 你可以让一个可选的方法被动的被声明,而这仅仅只是向编译器发出暗示而已,并不是编译必须的.

  检查一个方法是否被实现了

1
2
3
4
5
6
7
// Objective-C
NSObject* ptr = ...; // some pointer
[ptr somefunction:5:3]; // NSObject 不必一定为其编译而实现somefunction. 如果没有被实现的话,会引发异常.
 
// C++
CPPObject* ptr = ...; // some pointer
ptr->somefunction(5,3); // CPPObject 必须实现 somefunction() 否则程序根本就不会被编译.

  Objective-C 成员函数就是(Smalltalk中的) "消息"  而在Objective-C中时,我们则说接收者 (即指针) 会向一个选择器做出回应, 这意味着其实现了我们尝试去调用的虚函数. 当有一个接口是, C++ 对象必须实现其所有的成员函数. 而在 Objective-C 中这并不是必须的,因此我们可以向并不必须要实现它的某个地方发送一个”消息“  (如此就会引发一个异常).

1
2
3
4
// Objective-C
NSObject* ptr = ...; // some pointer
if ([ptr respondsToSelector:@selector(somefunction::)]
    [ptr somefunction:5:3];

  现在我们就可以确定接收者向选择器做出回应, 我们因此就可以调用它了. 在 C++ 中不需要这样的检查, 因为实现必须常常”向选择器做出回应“, 否则源代码根本就不会被编译. 请注意我们必须知道选择器获取了多少个参数(因此在该@selector中是2个 ::s

  向下转型

1
2
3
4
5
6
7
8
9
10
// Objective-C
NSObject* ptr = ...; // some pointer
if ([ptr isKindOfClass:[foo class]]
    [ptr somefunction:5:3];
 
// C++
CPPObject* ptr = ...; // some pointer
foo* f = dynamic_cast<foo*>(ptr);
if (f)
  f->somefunction(5,3);

  现在只有使用NSObject的"isKindOfClass"助手——所有Object-C类的基础,才能像在C++中那样向下转型.

  符合协议?

1
2
3
4
5
6
7
8
9
// Objective-C
NSObject* ptr = ...; // some pointer
if ([ptr conformsToProtocol:@protocol(foo)]
    [ptr somefunction:5:3];
 
// C++
CPPObject* ptr = ...; // 某个也继承自foo的指针
foo* f = ptr; // 或者<span id="15_nwp" style="width: auto; height: auto; float: none;"><a id="15_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=18&is_app=0&jk=b2645dbfe197c88d&k=%B1%E0%D2%EB%C6%F7&k0=%B1%E0%D2%EB%C6%F7&kdi0=0&luki=8&n=10&p=baidu&q=06011078_cpr&rb=0&rs=1&seller_id=1&sid=8dc897e1bf5d64b2&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1922429&u=http%3A%2F%2Fwww%2Eadmin10000%2Ecom%2Fdocument%2F4400%2Ehtml&urlid=0" target="_blank" mpid="15" style="text-decoration: none;"><span style="color:#0000ff;font-size:14px;width:auto;height:auto;float:none;">编译器</span></a></span>会警告我们说ptr不能同foo兼容.
f->somefunction(5,3);

  现在我们要检查接收器是否 符合一个协议 (或者说,在C++就是实现一个接口), 以便我们可以发送这个协议包含的消息. 嘿嘿,它像极了Java的类和接口,而在C++中,完全被实现的类和一个“接口”之间没有技术上的差别.

  void* 、 id 或者 SEL?

1
2
3
4
5
6
7
8
9
10
11
// Objective-C
id ptr = ...; // some pointer
if ([ptr conformsToProtocol:@protocol(foo)]
    [ptr somefunction:5:3];
SEL s = @selector(foo:); // a pointer to a function foo that takes 1 parameter
 
// C++
void* ptr = ...; // some pointer
foo* f = dynamic_cast<foo*>(ptr);
if (f)
  f->somefunction(5,3);

  id 是通用的用于Objective-C类的类似于 void* 的东西. 你只能使用id而不是 void* 因为id可以通过ARC(稍后会详细介绍到它)编程一个可被管理的指针,而因此编译器需要在元指针类型和Objective-C指针之间做出区分. SEL 是一个用于选择器(C++函数指针)的通用类型,而你一般可以通过使用关键字@selector带上函数名字和:::::s的一个数字来创建一个选择器, 这取决于可以传入多少参数. 选择器实际上就是一个字符串,它会在运行时绑定到一个方法识别器.

  类定义,方法,数据,继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// Objective C
@class f2; // forward declaration
@interface f1 : NSOBject // Objective-C supports only public and single inheritance
{
 int test; // default = protected
@public
 int a;
 int b;
 f2* f;
}
- (void) foo;
@end
 
@implementation f1
- (void) foo
{
 a = 5; // ok
 self->a = 5; // ok
super.foo(); // parent <span id="11_nwp" style="width: auto; height: auto; float: none;"><a id="11_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=18&is_app=0&jk=b2645dbfe197c88d&k=call&k0=call&kdi0=0&luki=1&n=10&p=baidu&q=06011078_cpr&rb=0&rs=1&seller_id=1&sid=8dc897e1bf5d64b2&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1922429&u=http%3A%2F%2Fwww%2Eadmin10000%2Ecom%2Fdocument%2F4400%2Ehtml&urlid=0" target="_blank" mpid="11" style="text-decoration: none;"><span style="color:#0000ff;font-size:14px;width:auto;height:auto;float:none;">call</span></a></span>
}
@end
 
// C++
class f1 : public CPPObject
{
 int test; // default = private
public:
 class f2* f; // forward declaration
 int a;
 int b;
 void foo();
}
 
void f1 :: foo()
{
 a = 5; // ok
 this->a = 5; // ok
 CPPOBject::foo(); // parent call
}

  Objective-C中的实现范围在@implementation/@end 标记 (在 C++ 中我们可以将实现放在任何带有::范围操作符的地方)之中. 它使用@class关键字用于事先声明. Objective-C 默认带有 私有(private)保护, 但仅用于数据成员(方法必须是公共的). Objective-C 使用 self 而不是 this ,并且它还可以通过super关键字调用它的父类.

  构造器和析构器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Objective-C
NSObject* s = [NSObject alloc] init]; // can return nil if construction failed
[s retain]; // Increment the ref count
 
// C++
CPPObject* ptr = new CPPObject();   // can throw
ptr->AddRef();
 
// Objective-C
NSObject* s = [NSObject alloc] initwitharg:4];
[s release];
 
// C++
CPPOBject* ptr = new CPPOBject(4);
ptr->Release();

  Objective-C中的内存分配是通过静态成员方法alloc来实现的,所有 (做为NSObject后裔)的对象都有这个方法. self 在Objective-C中是可以被赋值的,而如果构建失败的话它就会设置成nil(而在C++中则会被抛出一个异常). 内存分配之后实际被构造器调用的是一个公共的成员函数,在Objective-C中默认的是init方法.

  Objective-C 使用同COM益阳的引用计数方法, 而它也使用 retain 和 release (等同于IUnknown的 AddRef() 和 Release() 方法). 当引用计数到了0,则对象会从内存中被移除掉.

  多线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Objective C
@interface f1 : NSOBject // Objective-C supports only public and single inheritance
{
}
- (void) foo;
- (void) threadfunc :(NSInteger*) param;
- (void) mt;
 
@end
 
@implementation f1
 
- (void) threadfunc : (NSInteger*) param
{
[self performSelectorOnMainThread: @selector(mt)];
}
 
- (void) mt
{
}
 
- (void) foo
{
[self performSelectorInBackground: @selector(thradfunc:) withObject:1 waitUntilDone:false];
<div></div>}
@end

  Objective-C 有一些针对NSObject的内建功能,可以在另外一个线程中操作一个选择器 (== 调用一个成员), 在主线程中,等待一次调用等等 . 在NSObject 参见更多信息.

  内存和ARC

1
2
3
4
5
// Objective-C
@interface f1 : NSObject
{
}
@property (weak) NSAnotherObject* f2; // 当没有其它强引用存在的时候,它将会被自动设置成.
1
2
3
4
5
6
7
8
@end
 
-(void)foo
{
NSObject*s = [NSObject alloc]&nbsp;init]; // 如果构造失败的话会返回nil
// use s
// end. Hooraah! Compiler will automati<span id="9_nwp" style="width: auto; height: auto; float: none;"><a id="9_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=18&is_app=0&jk=b2645dbfe197c88d&k=call&k0=call&kdi0=0&luki=1&n=10&p=baidu&q=06011078_cpr&rb=0&rs=1&seller_id=1&sid=8dc897e1bf5d64b2&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1922429&u=http%3A%2F%2Fwww%2Eadmin10000%2Ecom%2Fdocument%2F4400%2Ehtml&urlid=0" target="_blank" mpid="9" style="text-decoration: none;"><span style="color:#0000ff;font-size:14px;width:auto;height:auto;float:none;">call</span></a></span>y call[s release] for us!
}

  这里需要你忘记自己良好的 C++ 习惯. OK Objective-C 使用了一个垃圾收集机制,这种东西我们C++很讨厌,因为它很慢并会让我们想到Java. 但是 ARC (自动进行引用计算) 是一种 编译时间 特性,它会告诉编译器 "这里是我的对象:请帮我算算啥时候它们才要被销毁吧". 使用ARC你就不需要发送 retain/release 消息给你的对象了; 编译器会自动帮你代劳的.

  为了能帮助编译器决定保留一个对象多长时间,你还要一个弱引用指向一个变量. 默认的,所有的变量都是强引用(==只要强引用还存在,被引用的对象就会存在下去) . 你也可以获取一个弱引用,它会随着每个强引用消失而失去它的值. 这在类成员从XCode的Builder Interface(像RC 编辑器)处获取它们的值时,会很有用,当类被销毁时,那些成员也会失去它们的值.

  Strings

1
2
3
4
5
// Objective-C
NSString* s1 = @"hello";
NSString* s2 = [NSString stringWithUTF8String:"A C String"];
sprintf(buff,"%s hello to %@","there",s2);
const char* s3 = [s2 UTF8String];

  NSString 是一个Objective-C字符串的不可变表示. 你可以使用其一个静态方法,或者是一个带有@前缀的字符串文本来创建NSString. 你也可以使用 %@  来向printf家族函数来表示一个NSString,

  数组

1
2
3
// Objective-C
NSArray* a1 = [NSArray alloc] initWithObjects: @"hello",@"there",nil];
NSString* first = [a1 objectAtIndex:0];

  NSArray和NSMutableArray是在Objective-C中处理数组的 两个类(两者的差异是,NSArray元素构造时必须通过构造函数,而NSMutableArray可以在之后更改)。典型构造函数的生效,你必须通过nil去作为“结尾元素”。排序/搜索/插入函数对于NSArray和NSMutableArray来说是一样的,在第一行中的例子它返回一个新的NSArray,而在NSMutableArray的例子里,它修改的是一个存在的对象。

  分类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// C++
class MyString : public string
{
public:
  void printmystring() { printf("%s",c_str()); }
};
 
 
// Objective-C
@interface MyString (NSString)
- (void) printmystring;
@end
 
@implementation MyString (NSString)
- (void) printmystring
{
 printf("%@",self);
}
@end
 
// C++
MyString s1 = "hi";
s1.printmystring(); // ok
string s2 = "hello";
s2.printmystring(); // error, we must change s2 from string to MyString
 
// Objective-C
NSString* s2 = @"hello";
[s2 printmystring]; // valid. We extended NSString without changing types.

  C++依赖 继承机制来实现一个已知的类。这是很麻烦的,因为所有用户的实现类必须使用另外的类型名称(在例子中,MyString用来代替string)。Object-C通过使用 分类(Categories)允许扩展一个已知的类内 同型(same type )。上面链接中所有源代码在extension.h文件 (具有代表性的是像NSString+MyString.h这样的)中可以查看,上面例子中,我们立即就有可以调用新的成员函数,而不需要改变NSString类型为MyString。

  块 和 Lambda

1
2
3
4
5
6
// Objective-C
// member function
-(void)addButtonWithTitle:(NSString*)title <span id="4_nwp" style="width: auto; height: auto; float: none;"><a id="4_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=18&is_app=0&jk=b2645dbfe197c88d&k=block&k0=block&kdi0=0&luki=3&n=10&p=baidu&q=06011078_cpr&rb=0&rs=1&seller_id=1&sid=8dc897e1bf5d64b2&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1922429&u=http%3A%2F%2Fwww%2Eadmin10000%2Ecom%2Fdocument%2F4400%2Ehtml&urlid=0" target="_blank" mpid="4" style="text-decoration: none;"><span style="color:#0000ff;font-size:14px;width:auto;height:auto;float:none;">block</span></a></span>:(void(^)(AlertView*, NSInteger))block;
 
// <span id="5_nwp" style="width: auto; height: auto; float: none;"><a id="5_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=18&is_app=0&jk=b2645dbfe197c88d&k=call&k0=call&kdi0=0&luki=1&n=10&p=baidu&q=06011078_cpr&rb=0&rs=1&seller_id=1&sid=8dc897e1bf5d64b2&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1922429&u=http%3A%2F%2Fwww%2Eadmin10000%2Ecom%2Fdocument%2F4400%2Ehtml&urlid=0" target="_blank" mpid="5" style="text-decoration: none;"><span style="color:#0000ff;font-size:14px;width:auto;height:auto;float:none;">call</span></a></span>
[object addButtonWithTitle:@"hello" block:[^(AlertView* a, NSInteger i){/*DO SOMETHING*/}];

  是Objective-C 用来模拟lambda功能的一种方式. 查看Apple的文档,从AlertView的示例 (使用块的UIAlertView)可以获得更多有关块的技术.

  C++ 开发者使用 Objective-C 和 ARC 的重要提示

1
2
3
4
5
6
7
8
9
10
11
12
13
// C++
class A
{
public:
 
   NSObject* s;
   A();
};    
 
A :: A()
 {
 s = 0; // 可能会奔溃,这是常发生在发布模式下!
 }

  你已经知道给所有的顾客都打两折对你而言有多痛苦了,因为你bug重重的软件会在发布模式下奔溃,而在调试模式下总是妥妥的. 没有用户会理解程序员,是不是?

  让我们来看看这里发生了什么.  s = 0 这一行将 0 赋值给了一个变量,而因此不管这个变量之前取值是什么,首先都会被释放掉,所以编译器在赋值之前执行了一次 [s release] . 如果 s 之前已经是 0 了,假设是在调试构建的话,不会发生任何不好的事情; 如果 s 是一个nil的话,使用[s release] 是再好也不过的. 然而,在发布模式下, s可能是一个野指针,所以它可能在被“初始化”为0之前包含任何值(这很危险是不是?).

  在C++中,这并不是一个问题,因为它里面是不存在ARC的. 而在Objective-C中编译器并没有办法了解这是一次"赋值" 还是一次 "初始化" (如果是后者,它就不会发送发布消息).

  下面是正确的方式:

1
2
3
4
5
6
7
8
9
10
11
12
// C++
class A
{
public:
 
   NSObject* s;
   A();
};    
 
A :: A() :s(0) // 现在编译器就知道确定 it&apos;s 是一次初始化了, 一次就不存在 [s release]
 {
 }

  现在编译器就不会去尝试调用一个 [s release] 因为它知道它是这个对象的第一次初始化. 请小心!

  从Objective-C 对象到 C++ 类型的转换

1
2
3
4
5
// Objective-C
NSObject* a = ...;
void* b = (__bridge void*)a; // 你必须在Objective-C和C类型支架使用 __bridge
void* c = (__bridge_retained void*)a; // 现在是一个+1的保留计数,而你必须在稍后释放这个对象
NSObject* d = (__bridge_transfer NSObject*)c; // 现在ARC取得了对象c的”拥有权“, 将其装换成一个ARC管理的NSObject.

  我可以分析这一切,而我的建议是简单的. 不要 将ARC类型和非ARC类型混在一起. 如果你必须转换一些Objective-C对象的话,使用id而不是void*. 否则,你将会遇到严重的内存故障.

  Objective-C 有而 C++ 没有的

  • 分类Categories

  • 基于NSObject的操作

  • YES 和 NO (等价于true和false)

  • NIL 和 nil (等价于0)

  • 可命名的函数参数

  • self (等价于 this) 而其可以在一个构造器中被改变

 C++ 有而 Objective-C 没有的

  • 静态对象. Objective-C 中的对象不能被初始化成静态的,或者是存在于栈中. 只能是指针.

  • 多重继承

  • 命名空间

  • 模板

  • 操作符重载

  • STL 和算法 ;

  • 方法可以是受保护的( protected )或者私有的( private ) (在Obj-C中,只能是公共的)

  • const/mutable 项

  • friend 方法

  • 引用

  • 匿名函数签名 (没有变量名称)

 阅读更多

  从C++ 到 Objective-C 指南, 这里.

 历史记录

  • 10/05/2014 : 第一次发布.

  原文地址:http://www.codeproject.com/Articles/770577/From-Cplusplus-to-Objective-C-A-quick-guide-for-pr

从 C++ 到 Objective-C 的快速指南的更多相关文章

  1. [译] MongoDB Java异步驱动快速指南

    导读 mongodb-java-driver是mongodb的Java驱动项目. 本文是对MongoDB-java-driver官方文档 MongoDB Async Driver Quick Tour ...

  2. 转:C++ Boost/tr1 Regex(正则表达式)快速指南

    C++ Boost/tr1 Regex(正则表达式)快速指南 正则表达式自Boost 1.18推出,目前已经成为C++11(tr1)的标准部分. 本文以Boost 1.39正则表达式为基础,应该广泛适 ...

  3. (译)快速指南:用UIViewPropertyAnimator做动画

    翻译自:QUICK GUIDE: ANIMATIONS WITH UIVIEWPROPERTYANIMATOR 译者:Haley_Wong iOS 10 带来了一大票有意思的新特性,像 UIViewP ...

  4. JUnit5 快速指南

    JUnit5 快速指南 version: junit5 1. 安装 2. JUnit 注解 3. 编写单元测试 3.1. 基本的单元测试类和方法 3.2. 定制测试类和方法的显示名称 3.3. 断言( ...

  5. 【SFA官方翻译】使用 Kubernetes、Spring Boot 2.0 和 Docker 的微服务快速指南

    [SFA官方翻译]使用 Kubernetes.Spring Boot 2.0 和 Docker 的微服务快速指南 原创: Darren Luo SpringForAll社区 今天 原文链接:https ...

  6. Emacs 快速指南(中文翻译)

      Emacs 快速指南 目录 1. 小结(SUMMARY) 2. 基本的光标控制(BASIC CURSOR CONTROL) 3. 如果 EMACS 失去响应(IF EMACS STOPS RESP ...

  7. 29 A Quick Guide to Go's Assembler 快速指南汇编程序:使用go语言的汇编器简介

    A Quick Guide to Go's Assembler 快速指南汇编程序:使用go语言的汇编器简介 A Quick Guide to Go's Assembler Constants Symb ...

  8. Emacs 快速指南 - 原生中文手册

    Emacs 快速指南 -折叠目录 1. 小结(SUMMARY) 2. 基本的光标控制(BASIC CURSOR CONTROL) 3. 如果 EMACS 失去响应(IF EMACS STOPS RES ...

  9. Docker网络基础:快速指南

    Docker网络基础:快速指南 原文连接:http://blogxinxiucan.sh1.newtouch.com/2017/07/30/Docker网络基础:快速指南/ 了解有关扩展网络功能的默认 ...

随机推荐

  1. spring boot file上传

    用Spring Boot写读取Excel文件小工具的时候遇到的一些小坑已经填平,复制即可满足普通的文件上传功能POI方面只需一个包,其他通用包工程中一般都会带TIPS:前端为了扩展我用ajax异步请求 ...

  2. springboot application.properties

    verify if you have this items: @Bean public CommonsMultipartResolver multipartResolver() { CommonsMu ...

  3. 《Java设计模式》之状态模式

    状态模式,又称状态对象模式(Pattern of Objects for States),状态模式是对象的行为模式. 状态模式同意一个对象在其内部状态改变的时候改变其行为.这个对象看上去就像是改变了它 ...

  4. 移动端 js 实现图片上传 预览

    方法一: <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv=&q ...

  5. [转]chrome 的devtools 中setting 开启workspace , 也有点用处。不是很大

    转载的,原文: http://wiki.jikexueyuan.com/project/chrome-devtools/saving-changes-with-workspaces.html ---- ...

  6. [Javascript] Flattening nested arrays: a little exercise in functional refactoring

    In this lesson we write an imperative function to flatten nested arrays, and then use the popular ma ...

  7. 神马都是浮云,unity中自己写Coroutine协程源代码

    孙广东   2014.7.19 无意之间看到了,Unity维基上的一篇文章,  是关于自己写协程的介绍. 认为非常好,这样能更好的了解到协程的执行机制等特性.还是不错的. 原文链接地址例如以下: ht ...

  8. 在head里的CSS link 竟然粗如今body里了?

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVhY2Vfb2Zfc291bA==/font/5a6L5L2T/fontsize/400/fill/I0 ...

  9. jquery.validate自己定义验证--成功提示与择要提示

    1. 自己定义验证--成功提示 1) 加入选项 errorClass: "unchecked". validClass: "checked", errorEle ...

  10. web 开发之js---js 实现地址栏的表单提交加密编码

    以前在做嵌入式web时,曾经想过cgi加密,原来js可以直接实现,太好了,这里js在客户端实现编码和解码 一.在地址栏直接输入:javascript:str=encodeURI("笃行天下& ...