iOS块语法详解(block编程)

——译自Apple Reference Library《Blocks Programming Topic》

简介

块对象是C语言的句法和运行时特性。它类似于标准C函数,但可以将代码、变量绑定到堆(heap)、栈(stack)。一个块还维护了一系列的状态,这些状态或数据影响着执行的结果。

可以把块组成函数表达式,用于传递给API,或者使用在多线程里。*有用的是回调,因为块在回调时能把代码和数据一起传送。

在OSX 10.6的Xcode中,可以使用块,它随GCC和 Clang 一起集成。在OSX 10.6及iOS 4.0以后支持块语法。 块运行时是开源的,它能被集成到 LLVM’s compiler-rt subproject repository 中。标准C工作组的 N1370: Apple’s Extensions to C 中 ( 其中也包括垃圾回收 ) 对块进行了定义。O-C和C++都来自于C,块在3种语言(包括O-C++)都能工作。

这篇文档中,你会学习到什么是块对象,以及怎样在C,C++和O-C中使用它,使代码的性能和可维护性更高。

开始

声明块

^ 操作符声明一个块变量的开始(跟C一样用; 来表示表达式结束),如代码所示:

int multiplier = 7;

int (^myBlock)(int) = ^(int num) {

return num * multiplier;

};

解释 :

%title插图%num

 

注意,块可以使用同一作用域内定义的变量。

 

一旦声明了块,你可以象使用函数一样调用它:

int multiplier = 7;

int (^myBlock)(int) = ^(int num) {

return num * multiplier;

};

printf(“%d”, myBlock(3));

直接使用块

很多情况下,你不必声明块变量,而简单地写一个行内块并把它当作一个参数,如下面的代码所示。

gsort_b类似标准的 gsort_r 函数,但它*后一个参数是一个块。

char *myCharacters[3] = { “TomJohn”, “George”, “Charles Condomine” };

qsort_b(myCharacters, 3, sizeof(char *), ^(const void *l, const void *r) {

 

char *left = *(char **)l;

 

char *right = *(char **)r;

 

return strncmp(left, right, 1);

 

});

// myCharacters is now { “Charles Condomine”, “George”, TomJohn” }

Cocoa 和块

在Cocoa框架中,有几种把块作为参数的方法。典型的是在集合中进行一个操作,或者在操作完成后作为一个回调。下列代码显示如何在NSArray的sortedArrayUsingComparator方法中使用块。这个方法使用了一个块参数。为了演示,在这里把块定义为一个NSComparator本地变量。

 

NSArray *stringsArray = [NSArray arrayWithObjects:                                 @”string 1″,  @”String 21″,@”string 12″,

@”String 11″, @”String 02″, nil];

static NSStringCompareOptions comparisonOptions = NSCaseInsensitiveSearch | NSNumericSearch |

NSWidthInsensitiveSearch | NSForcedOrderingSearch;

NSLocale *currentLocale = [NSLocale currentLocale];

NSComparator finderSortBlock = ^(id string1, id string2) {

NSRange string1Range = NSMakeRange(0, [string1 length]);

return [string1 compare:string2 options:comparisonOptions range:string1Range locale:currentLocale];

};

NSArray *finderSortArray = [stringsArray sortedArrayUsingComparator:finderSortBlock];

NSLog(@”finderSortArray: %@”, finderSortArray);

 

/*Output:

finderSortArray: (

“string 1”,

“String 02”,

“String 11”,

“string 12”,

“String 21″

)*/

块变量

块的一个强大功能它可以改变在同一作用域内的变量。用__block修饰符来标识一个变量能够被块改变。使用下面的代码,你可以用一个块变量计算进行比较的字符串中有多少是相同的。为了演示,块是直接使用的,同时currentLocal变量对于块来说是只读的。

NSArray *stringsArray = [NSArray arrayWithObjects:

@”string 1″,  @”String 21″, // <-

@”string 12″,  @”String 11″,@”Strîng 21″, // <-

@”Striñg 21″, // <-

@”String 02″, nil];

NSLocale *currentLocale = [NSLocale currentLocale];

__block NSUInteger orderedSameCount = 0;

NSArray *diacriticInsensitiveSortArray = [stringsArray sortedArrayUsingComparator:^(id string1, id string2) {

NSRange string1Range = NSMakeRange(0, [string1 length]);

NSComparisonResult comparisonResult = [string1 compare:string2 options:NSDiacriticInsensitiveSearch range:string1Range locale:currentLocale];

 

 

 

if (comparisonResult == NSOrderedSame) {

orderedSameCount++;

}

return comparisonResult;

}];

NSLog(@”diacriticInsensitiveSortArray: %@”, diacriticInsensitiveSortArray);

NSLog(@”orderedSameCount: %d”, orderedSameCount);

/*Output:

diacriticInsensitiveSortArray: (

“String 02”,

“string 1”,

“String 11”,

“string 12”,

“String 21”,

“Str/U00eeng 21”,

“Stri/U00f1g 21”

)

orderedSameCount: 2

*/

相关概念

块提供了一种方法,允许你创建一种特殊的函数体,在C及C派生语言如O-C和C++中,可以把块视为表达式。其他语言中,为了不与C术语中的块混淆,块也被称作closure(国内译作闭包),这里它们都称做blocks。

块的功能

 

块是行内的代码集合:

▪        同函数一样,有类型化参数列表

▪        有返回结果或者要申明返回类型

▪        能获取同一作用域(定义块的相同作用域)内的状态

▪        可以修改同一作用域的状态(变量)

▪        与同一范围内的其他块同享变量

▪        在作用域释放后能继续共享和改变同一范围内的变量

甚至可以复制块并传递到其他后续执行的线程。编译器和运行时负责把所有块引用的变量保护在所有块的拷贝的生命周期内。对于C和C++,块是变量,但对于O-C ,块仍然是对象。

块的使用

块通常代表小段的、自包含的代码片段。

因此,它们封装为可以并行执行的工作单元额外有用,要么用于在集合中进行遍历,要么在其他操作完成使作为回调。

块代替传统回调函数的意义有两个:

1.             它们允许在方法实现的调用中就近地写入代码。而且块经常被作为框架中一些方法的参数。

2.             它们允许访问本地变量。在进行线程操作时,相比回调函数需要把所需的上下文信息植入数据结构中而言,块直接访问本地变量显然更加简单。

 

块的声明和创建

声明块变量

块变量引用了块。它的声明语法类似函数指针,除了需要使用^代替*。

void (^blockReturningVoidWithVoidArgument)(void);

int (^blockReturningIntWithIntAndCharArguments)(int, char);

void (^arrayOfTenBlocksReturningVoidWithIntArgument[10])(int);

块支持可变参数(…)。如果块没有参数,则必需使用void来代替整个参数列表。

块是类型安全的,通过设置编译选项,编译器会检查块的调用、参数和返回类型。可以把块变量转换为指针类型,但不能使用*对其解除引用——块的长度在编译时无法确定。

可以创建一个块类型,这样你就可以把块当作一个可以反复多次使用的符号:

typedef float (^MyBlockType)(float, float);

MyBlockType myFirstBlock = // … ;

MyBlockType mySecondBlock = // … ;

创建块

块以^开始,以;结束。下面显示了块的定义:

int (^oneFrom)(int);

oneFrom = ^(int anInt) {

return anInt – 1;

};

如果未显式地声明块的返回值类型,可能会自动从块代码中推断返回类型。如果参数列表为void,而且返回类型依靠推断,你可以省略参数列表的void。否则,当块中存在return语句时,它们应当是精确匹配的(可能需要必要的类型转换)。

全局块

可以把块定义为全局变量,在文件级别上使用。

#import <stdio.h>

int GlobalInt = 0;

int (^getGlobalInt)(void) = ^{ return GlobalInt; };

 

块和变量

本节描述块和变量之间的交互,包括内存管理。

变量类型

在块代码内部,变量会被处理为5种不同情况。

就像函数一样,可以引用3种标准的变量:

▪        全局变量,包括静态变量

▪        全局函数

▪        本地变量及参数(在块范围内)

此外块还支持两种变量:

1.    在函数级别,是__block变量。它们在块范围内是可变的,如果所引用的块被复制到堆后,它们也是被保护的。

2.    const imports.

在方法体内,块还可以引用O-C 实例变量,见 “ 对象和块变量 ”.

在块中使用变量有以下规则:

1.      可访问在同一范围内的全局变量包括静态变量。

2.      可以访问传递给块的参数(如同函数参数)。

3.      同一范围的栈(非static)变量视作const变量。它们的值类似块表达式。嵌套块时,从*近的作用域取值。

4.      在同一范围内声明的变量,如果有__block修饰符修饰,则值是可变的。在该范围内包括同一范围内的其他块对该变量的改变,都将影响该作用域。具体见“__block 存储类型”。

5.      在块的范围内(块体)声明的本地变量,类似于函数中的本地变量。块的每次调用都会导致重新拷贝这些变量。这些变量可作为const或参考(by-reference)变量。

下面演示本地非静态变量的使用:

int x = 123;

void (^printXAndY)(int) = ^(int y) {

printf(“%d %d/n”, x, y);

};

printXAndY(456); // prints: 123 456

注意,试图向x进行赋值将导致错误:

int x = 123;

void (^printXAndY)(int) = ^(int y) {

x = x + y; // error

printf(“%d %d/n”, x, y);

};

要想在块内改变x的值,需要使用__block修饰x。见“__block存储类型”。

__block 存储类型

你可以规定一个外部的变量是否可变——可读写——通过使用__block存储类型修饰符。__block存储类似但不同于register,auto和static存储类型。

__block变量在变量声明的作用域、所有同一作用域内的块,以及块拷贝之间同享存储。而且这个存储将在栈帧(stack frame)释放时得以保留,只要同一帧内申明的块的拷贝仍然存活(例如,被入栈以便再次使用)。在指定作用域内的多个块能同时使用共享变量。

作为一种优化,块存储使用栈存储,就如同块自身一样。如果使用Block_copy拷贝块(或者在O-C向块发送copy消息),变量被拷贝到堆里。而且,__block变量的地址随后就会改变。

__block变量有两个限制:不能是可变长度的数组,也不能是包含C99可变长度数组的结构体。

下面显示了__block变量的使用:

__block int x = 123; //  x lives in block storage

void (^printXAndY)(int) = ^(int y) {

x = x + y;

printf(“%d %d/n”, x, y);

};

printXAndY(456); // prints: 579 456

// x is now 579

下面显示了在块中使用多种类型的变量:

extern NSInteger CounterGlobal;

static NSInteger CounterStatic;

{

NSInteger localCounter = 42;

__block char localCharacter;

void (^aBlock)(void) = ^(void) {

++CounterGlobal;

++CounterStatic;

CounterGlobal = localCounter; // localCounter fixed at block creation

localCharacter = ‘a’; // sets localCharacter in enclosing scope

};

++localCounter; // unseen by the block

localCharacter = ‘b’;

aBlock(); // execute the block

// localCharacter now ‘a’

}

对象和块变量

块提供了对O-C和C++对象的支持 。

O-C对象

在引用计数的情况下,当你在块中引用一个O-C对象,对象会被retained。甚至只是简单引用这个对象的实例变量,也是一样的。

但对于__block标记的对象变量,就不一样了。

注意:在垃圾回收的情况下,如果同时用__weak和__block修饰变量,块可能不一定保证它是 可用 的。

如果在方法体中使用块,对象实例变量的内存管理规则 比较微妙:

▪        如果通过对象引用方式访问实例变量,self 被 retained;

▪        如果通过值引用方式访问实例变量,变量是retained;

下面代码演示了这2种情况:

dispatch_async(queue, ^{

// instanceVariable is used by reference, self is retained

doSomethingWithObject(instanceVariable);

});

id localVariable = instanceVariable;

dispatch_async(queue, ^{

// localVariable is used by value, localVariable is retained (not self)

doSomethingWithObject(localVariable);

});

C++ 对象

一般,可以在块中使用C++对象。在成员函数中对成员变量进行引用,俨然是对指针的引用,可以对其进行改变。如果块被拷贝,有两种结果:

如果有__block存储类型的类,该类是基于栈的C++对象,通常会使用复制构造函数;

如果使用了其他块中的基于栈的C++对象,它必需有一个const的复制构造函数。该C++对象使用该构造函数进行拷贝。

拷贝块时,其引用的其它块可能也被拷贝(从顶部开始)。如果有块变量,并且在这个块中引用了一个块,那个块也会被拷贝。

拷贝一个基于栈的块时,你得到的是新的块。拷贝一个基于堆的块时,只是简单的增加了retain数,然后把copy方法/函数的结果返回这个块。

 

 

使用块

块的调用

如果把块申明为变量,可以把它当成函数使用,例如:

int (^oneFrom)(int) = ^(int anInt) {

return anInt – 1;

};

printf(“1 from 10 is %d”, oneFrom(10));

// Prints “1 from 10 is 9”

float (^distanceTraveled) (float, float, float) =

^(float startingSpeed, float acceleration, float time) {

float distance = (startingSpeed * time) + (0.5 * acceleration * time * time);

return distance;

};

float howFar = distanceTraveled(0.0, 9.8, 1.0);

// howFar = 4.9

但时常会将块以参数形式传递给一个函数或方法,这样,就会使用行内(inline)块。

把块作为函数参数

在这种情况下,不需要块申明。简单地在需要把它作为参数的地方实现它就行。如下所示,gsort_b是一个类似标准gsort_r的函数,它的*后一个参数使用了块。

char *myCharacters[3] = { “TomJohn”, “George”, “Charles Condomine” };

qsort_b(myCharacters, 3, sizeof(char *), ^(const void *l, const void *r) {

char *left = *(char **)l;

char *right = *(char **)r;

return strncmp(left, right, 1);

});

// Block implementation ends at “}”

 

 

// myCharacters is now { “Charles Condomine”, “George”, TomJohn” }

注意,块包含在函数的参数列表中。

接下来的例子显示如何在dispath_apply函数中使用块。dispatch_apply的声明是:

void dispatch_apply(size_t iterations, dispatch_queue_t queue, void (^block)(size_t));

这个函数把块提交给dispatch队列以进行调用。它有3个参数:要操作的次数;块被提交到的队列;块——这个块有一个参数——遍历操作的当前次数。

可以用dispatch_apply简单地打印出遍历操作的索引:

#include <dispatch/dispatch.h>

size_t count = 10;

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_apply(count, queue, ^(size_t i) {

printf(“%u/n”, i);

});

把块作为参数使用

Cocoa提供了大量使用块的方法。把块作为参数使用与使用其他类型的参数并无不同。

以下代码判断数组中前5个元素中含有给定filter集合的索引。

NSArray *array = [NSArray arrayWithObjects: @”A”, @”B”, @”C”, @”A”, @”B”, @”Z”,@”G”, @”are”, @”Q”, nil];

NSSet *filterSet = [NSSet setWithObjects: @”A”, @”Z”, @”Q”, nil];

BOOL (^test)(id obj, NSUInteger idx, BOOL *stop);

test = ^ (id obj, NSUInteger idx, BOOL *stop) {

if (idx < 5) {

if ([filterSet containsObject: obj]) {

return YES;

}

}

return NO;

};

NSIndexSet *indexes = [array indexesOfObjectsPassingTest:test];

NSLog(@”indexes: %@”, indexes);

/*Output:

indexes: <NSIndexSet: 0x10236f0>[number of indexes: 2 (in 2 ranges), indexes: (0 3)]

*/

以下代码判断一个NSSet对象中是否包含指定的本地变量,如果是的话把另一个本地变量(found)设置为YES(并停止搜索)。注意found被声明为__block变量,块是在行内声明的:

__block BOOL found = NO;

NSSet *aSet = [NSSet setWithObjects: @”Alpha”, @”Beta”, @”Gamma”, @”X”, nil];

NSString *string = @”gamma”;

[aSet enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {

if ([obj localizedCaseInsensitiveCompare:string] ==NSOrderedSame) {

*stop = YES;

found = YES;

}

}];

 

 

 

// At this point, found == YES

 

块复制

一般,你不需要复制块。只有当你希望在这个块申明的范围外使用它时需要复制它。复制将导致块移动到堆中。

可以使用C函数释放和复制块。

Block_copy();

Block_release();

对于O-C,则可向块发送copy,retain和release(以及autorelease)消息。

为避免内存泄露,一个Block_copy()总是对应一个Block_release()。每个copy/retain总是有对应的release(或autorelease)——使用垃圾回收则例外。

避免的用法

一个块声明(即^{…})是一个本地栈式数据结构(stack-local data structure)的地址,这个地址就代表了块。本地栈式数据结构是{}围住的复合语句,因此应该避免如下用法:

void dontDoThis() {

void (^blockArray[3])(void);// array of 3 block   references

for (int i = 0; i < 3; ++i) {

blockArray[i] = ^{ printf(“hello, %d/n”, i); };

// WRONG: The block literal scope is the “for” loop

}

}

void dontDoThisEither() {

 

void (^block)(void);

int i = random():

if (i > 1000) {

block = ^{ printf(“got i at: %d/n”, i); };

// WRONG: The block literal scope is the “then” clause

}

// …

}

 

调试

可以在块内设置断点,并进行单步调试。在GDB会话中,使用invoke-block调用块,比如:

$ invoke-block myBlock 10 20

如果需要传递C字符串,必需用双引号把它引住。例如,向doSomethignWithString块传递一个字符串:

$ invoke-block doSomethingWithString “/”this string/””

ios自定义控件复选框和单选框的实现

我们先实现单个按钮,为了复用,不管单选还是复选按钮都是使用同一个类来实现,为了区别单选还是复选,我们用一个自定义枚举类型CheckButtonStyle属性style来区别,当其值设置为CheckButtonStyleDefault或CheckButtonStyleBox时,为复选按钮:

  当其值设为CheckButtonStyleRadio时,为单选按钮:

当按钮在选中/反选状态间切换时,文字左边的图片自动转换。

整个控件是由一个ImageView、一个Label、一个BOOL变量及其他变量组成,.h文件如下:

typedef enum {

    CheckButtonStyleDefault 0 ,

    CheckButtonStyleBox 1 ,

    CheckButtonStyleRadio 2

} CheckButtonStyle;

#import <Foundation/Foundation.h>

 

@interface CheckButton : UIControl {

//UIControl* control;

UILabel label ;

UIImageView icon ;

BOOL checked ;

id value , delegate ;

CheckButtonStyle style ;

NSString * checkname ,* uncheckname ; // 勾选/反选时的图片文件名

}

@property ( retain , nonatomic ) id value,delegate;

@property ( retain , nonatomic )UILabel* label;

@property ( retain , nonatomic )UIImageView* icon;

@property ( assign )CheckButtonStyle style;

-( CheckButtonStyle )style;

-( void )setStyle:( CheckButtonStyle )st;

-( BOOL )isChecked;

-( void )setChecked:( BOOL )b;

@end

具体实现如下:

#import “CheckButton.h”

 

 

@implementation CheckButton

@synthesize label,icon,value,delegate;

-( id )initWithFrame:( CGRect ) frame

{

if ( self =[ super initWithFrame : frame ]) {

icon =[[ UIImageView alloc ] initWithFrame :

  CGRectMake ( 10 0 frame . size . height frame . size . height )];

[ self setStyle : CheckButtonStyleDefault ]; // 默认风格为方框(多选)样式

//self.backgroundColor=[UIColor grayColor];

[ self addSubview : icon ];

label =[[ UILabel alloc ] initWithFrame : CGRectMake ( icon . frame . size . width + 24 0 ,

   frame . size . width  icon . frame . size . width  24 ,

   frame . size . height )];

label . backgroundColor =[ UIColor clearColor ];

label . font =[ UIFont fontWithName : @”Arial” size : 20 ];

label . textColor =[ UIColor

  colorWithRed : 0xf9 / 255.0

  green : 0xd8 / 255.0

  blue : 0x67 / 255.0

  alpha : 1 ];

label . textAlignment = UITextAlignmentLeft ;

[ self addSubview : label ];

[ self addTarget : self action : @selector ( clicked forControlEvents : UIControlEventTouchUpInside ];

}

return self ;

}

-( CheckButtonStyle )style{

return style ;

}

-( void )setStyle:( CheckButtonStyle )st{

style =st;

switch ( style ) {

case CheckButtonStyleDefault :

case CheckButtonStyleBox :

checkname = @”checked.png” ;

uncheckname = @”unchecked.png” ;

break ;

case CheckButtonStyleRadio :

checkname = @”radio.png” ;

uncheckname = @”unradio.png” ;

break ;

default :

break ;

}

[ self setChecked : checked ];

}

-( BOOL )isChecked{

return checked ;

}

-( void )setChecked:( BOOL )b{

if (b!= checked ){

checked =b;

}

if ( checked ) {

[ icon setImage :[ UIImage imageNamed : checkname ]];

} else {

[ icon setImage :[ UIImage imageNamed : uncheckname ]];

}

}

-( void )clicked{

[ self setChecked :! checked ];

if ( delegate != nil ) {

SEL sel= NSSelectorFromString ( @”checkButtonClicked” );

if ([ delegate respondsToSelector :sel]){

[ delegate performSelector :sel];

}

}

-( void )dealloc{

value = nil ; delegate = nil ;

[ label release ];

[ icon release ];

[ super dealloc ];

}

@end

使用CheckButton类很简单,构造、设置标签文本等属性,然后addSubview:

CheckButton * cb=[[ CheckButton a lloc initWithFrame : CGRectMake ( 20 60 260 32 )];

  1. label. text = @”checkbutton1″ ;
  2. value=[[ NSNumber alloc ] initWithInt : 18 ];
  3. style= CheckButtonStyleDefault ;

[ self . view addSubview :cb];

二、单选按钮组的实现

复选按钮无所谓“组”的概念,单选按钮则不同。在同一个组中,单选按钮只允许同时选择一个按钮,不能选多个,因此我们要实现一个单选按钮组的类:

#import <Foundation/Foundation.h>

#import “CheckButton.h”

 

@interface RadioGroup : NSObject {

NSMutableArray children ;

NSString text ;

id value ;

}

@property ( readonly )NSString* text;

@property ( readonly ) id value;

-( void )add:( CheckButton *)cb;

-( void )checkButtonClicked:( id )sender;

@end

#import “RadioGroup.h”

 

 

@implementation RadioGroup

@synthesize text,value;

-( id )init{

if ( self =[ super init ]){

children =[[ NSMutableArray alloc ] init ];

}

return self ;

}

-( void )add:( CheckButton *)cb{

  1. delegate= self ;

if (cb. checked ) {

text =cb. label . text ;

value =cb. value ;

}

[ children addObject :cb];

}

-( void )checkButtonClicked:( id )sender{

CheckButton * cb=( CheckButton *)sender;

if (!cb. checked ) {

// 实现单选

for ( CheckButton * each in children ){

if (each. checked ) {

[each setChecked : NO ];

}

}

[cb setChecked : YES ];

// 复制选择的项

text =cb. label . text ;

value =cb. value ;

}

NSLog ( @”text:%@,value:%d” , text ,[( NSNumber *) value intValue ]);

}

-( void )dealloc{

[ text release ];

value = nil ;

[ children release ];

[ super dealloc ];

}

@end

单选按钮组在ViewController中的使用:

-( id )initWithNibName:( NSString *)nibNameOrNil bundle:( NSBundle *)nibBundleOrNil{

if ( self =[ super initWithNibName :nibNameOrNil bundle :nibBundleOrNil]){

// 单选按钮组

rg =[[ RadioGroup alloc ] init ];

// 第 1 个单选按钮

CheckButton * cb=[[ CheckButton alloc ] initWithFrame : CGRectMake ( 20 60 260 32 )];

// 把单选按钮加入按钮组

[ rg add :cb];

  1. label. text = @”★” ;
  2. value=[[ NSNumber alloc ] initWithInt : 1 ];

// 把按钮设置为单选按钮样式

  1. style= CheckButtonStyleRadio ;

// 加入视图

[ self . view addSubview :cb];

[cb release ]; //add 后,会自动持有,可以释放

// 第 2 个单选按钮

cb=[[ CheckButton alloc ] initWithFrame : CGRectMake ( 20 100 260 32 )];

[ rg add :cb];

  1. label. text = @”★★” ;
  2. value=[[ NSNumber alloc ] initWithInt : 2 ];
  3. style= CheckButtonStyleRadio ;

[ self . view addSubview :cb];

[cb release ];

// 第 3 个单选按钮

cb=[[ CheckButton alloc ] initWithFrame : CGRectMake ( 20 140 260 32 )];

// 各种属性必须在 [rg addv] 之前设置,否则 text 和 value 不会被 populate

  1. checked= YES ;
  2. label. text = @”★★★” ;
  3. value=[[ NSNumber alloc ] initWithInt : 3 ];
  4. style= CheckButtonStyleRadio ;

[ self . view addSubview :cb];

[ rg add :cb]; // 属性设置完之后再 add

[cb release ];

// 第 4 个单选按钮

cb=[[ CheckButton alloc ] initWithFrame : CGRectMake ( 20 180 260 32 )];

[ rg add :cb];

  1. label. text = @”★★★★” ;
  2. value=[[ NSNumber alloc ] initWithInt : 4 ];
  3. style= CheckButtonStyleRadio ;

[ self . view addSubview :cb];

[cb release ];

// 第 5 个单选按钮

cb=[[ CheckButton alloc ] initWithFrame : CGRectMake ( 20 220 260 32 )];

[ rg add :cb];

  1. label. text = @”★★★★★” ;
  2. value=[[ NSNumber alloc ] initWithInt : 5 ];
  3. style= CheckButtonStyleRadio ;

[ self . view addSubview :cb];

[cb release ];

}

return self ;

}

运行效果:

%title插图%num

iOS开发经常用到的技术知识点

1.刷新单个tableviewcell

NSIndexPath * indexPat=[NSIndexPath indexPathForRow:indexPlay inSection:0];

NSArray * indexArray=[NSArray arrayWithObject:indexPat];

[self.tableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationAutomatic];

2.   判断该方法是否执行??

BOOL isss=  [cell.queuePlayer respondsToSelector:@selector(play)];

instancesRespondToSelector是指类的实例们是否能响应某一个方法(类操作),respondsToSelector是指类是否能响应某一方法(对象)
3.代码块的使用
int (^oneFrom)(int) = ^(int anInt) {

return anInt -1;

};

NSLog(@”%d”,oneFrom(10));

4.  改变buuton的高亮

UIImageView * iv = [[UIImageView alloc] initWithFrame:CGRectMake(250, 5, 50, 34)];

iv.userInteractionEnabled = YES;

UIButton * navBtn = [UIButton buttonWithType:UIButtonTypeCustom];

navBtn.frame = CGRectMake(0, 0, 50, 34);

[navBtn setImage:[UIImage imageNamed:@”rong_Tian”] forState:UIControlStateNormal];

[navBtn setHighlighted:YES];

[navBtn addTarget:self action:@selector(btnPressed:) forControlEvents:UIControlEventTouchUpInside];

[navBtn setShowsTouchWhenHighlighted:YES];

[iv addSubview:navBtn];

[self.navigationController.navigationBar addSubview:iv];

5. 默认为cell*行

 

NSIndexPath *first=[NSIndexPath indexPathForRow:0 inSection:0];

[self.tableView selectRowAtIndexPath:first animated:YES scrollPosition:UITableViewScrollPositionBottom];

6.一个项目中  ARC和非ARC 的混合使用

 

点击项目–》TARGETS-》Build Phases  -》Compile  Sources   中选择要改的.m   双击   在标签中写:

1.如果是ARC项目,要加入非ARC的代码文件  fobjc-arc

2.如果是非ARC,要加入ARC的代码   -fno-objc-arc       Enter就OK

 

//    NSURL * url=[NSURL URLWithString:str];

//

//      NSURLRequest *requestt = [[NSURLRequest alloc]initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10];

//     NSData *received = [NSURLConnection sendSynchronousRequest:requestt returningResponse:nil error:nil];

//    NSString *strr = [[NSString alloc]initWithData:received encoding:NSUTF8StringEncoding];

//    NSLog(@”这是  成功返回的信息     %@”,strr);

7.距离感应器

UIDeviceOrientation orientation3=  [[UIDevice currentDevice] orientation];

 

NSLog(@”获取当前状态   %d”,orientation3);

[[UIDevice currentDevice] setProximityMonitoringEnabled:YES];

[[NSNotificationCenter defaultCenter] addObserver:self

selector:@selector(sensorStateChange:)

name:@”UIDeviceProximityStateDidChangeNotification”

 

object:nil];

-(void)sensorStateChange:(NSNotificationCenter *)notification;

{

if ([[UIDevice currentDevice] proximityState] == YES) {

 

NSLog(@”Device is close to user”);

//在此写接近时,要做的操作逻辑代码

}else{

NSLog(@”Device is not close to user”);

}

}

8.获得cookie

 

NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];

for (NSHTTPCookie *cookie in [cookieJar cookies]) {

NSLog(@”cookie=====     %@”, cookie);

}

9.从相册中只获得视频文件

 

if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary] == YES)

{

UIImagePickerController *videoLibraryController = [[[UIImagePickerController alloc] init] autorelease];

videoLibraryController.delegate = self;

videoLibraryController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;

videoLibraryController.mediaTypes = [NSArray arrayWithObject:(NSString *)kUTTypeMovie];

[videoLibraryController setAllowsEditing:YES];

[self.navigationController presentViewController:videoLibraryController animated:YES completion:^{

 

}];

}

else

{

[self AlertlogError:@”暂时你还没有视频”];

}

10. 读取全局的Delegate:
KiloNetAppDelegate *appdelegate = (KiloNetAppDelegate *)[[UIApplication sharedApplication] delegate];

11.键盘透明

textField.keyboardAppearance = UIKeyboardAppearanceAlert;
12.URL错误:
Error Domain=ASIHTTPRequestErrorDomain Code=5 “Unable to create request (bad url?)” UserInfo=0x69ba0f0 {NSLocalizedDescription=Unable to create request (bad url?)}

解决办法:

NSString*url =@”http://oerp.xixingsoft.com:8083/oadata/MobileConfig.nsf/GetStandList?openagent&ViewNumber=新闻中心”;

url=[url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

 

NSStringEncodingenc = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);//gbk code–>utf8 code

NSData*data = [url dataUsingEncoding:NSUTF8StringEncoding];//[request responseData];

NSString*utf8str = [[[NSStringalloc] initWithData:data encoding:enc] autorelease];

13.请求中加cookie、 heard

当你需要添加更多的请求信息时,如,添加个请求Header:
[request addRequestHeader:@”name” value:@”Jory lee”];

14 Plist文件的保存 修改    除非在decument是可读可写的(在工程中  可读不可写)

//获取路径对象

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

//获取完整路径

NSString *documentsDirectory = [paths objectAtIndex:0];

NSString *plistPath = [documentsDirectory stringByAppendingPathComponent:@”test.plist”];

NSLog(@”plist  地质   %@”,plistPath);

NSMutableDictionary *dictplist = [[NSMutableDictionary alloc ] init];

[dictplist setObject:self.strWeb_id forKey:@”web_id”];

[dictplist writeToFile:plistPath atomically:YES];

15.获取文件夹的大小

-(long long) fileSizeAtPath:(NSString*) filePath{

NSFileManager* manager = [NSFileManager defaultManager];

if ([manager fileExistsAtPath:filePath]){

return [[manager attributesOfItemAtPath:filePath error:nil] fileSize];

}

return 0;

}

16.改变tablevlewcell点击的颜色

 

cell.selectedBackgroundView = [[[UIView alloc] initWithFrame:cell.frame] autorelease];

cell.selectedBackgroundView.backgroundColor = [UIColor colorWithRed:54/255.0f green:110/255.0f blue:100/255.0f alpha:1.0f];

cell.textLabel.highlightedTextColor = [UIColor xxxcolor];  [cell.textLabel setTextColor:color

 

点击后,过段时间cell自动取消选中
[self performSelector:@selector(deselect) withObject:nil afterDelay:0.5f];

– (void)deselect

{

[self.tableVieww deselectRowAtIndexPath:[self.tableVieww indexPathForSelectedRow] animated:YES];

}

17.改变UITableViewStyleGrouped背景颜色

 

self.tableVieww.backgroundColor =[UIColor colorWithPatternImage:[UIImage imageNamed:@”更多背景图.png”]];

self.tableVieww.backgroundView =nil;

18.视图反转

//水平
queuePlayer.transform = CGAffineTransformScale(queuePlayer.transform, 1.0, -1.0);
//垂直    queuePlayer.transform = CGAffineTransformScale(queuePlayer.transform, -1.0, 1.0);
19.改变icon的阴影圆圈,取消图标上的高光

1.进入plist文件    2.在Supported interface orientations 添加  Icon already includes gloss effects  设置为YES              也就是用自己的icon,不用系统的了

20.动态UIlable后添加图片

self.userNameLabel=[[[UILabel alloc]initWithFrame:CGRectMake(60, 7, 220, 20)]autorelease];

self.userNameLabel.textColor= [UIColor blackColor];

self.userNameLabel.text=self.strNamee;

self.userNameLabel.backgroundColor=[UIColor clearColor];

self.userNameLabel.numberOfLines=0;

UIFont *font = [UIFont fontWithName:@”Helvetica-Bold” size:17.0f];

[self.userNameLabel setFont:font];

[self.contentView addSubview:self.userNameLabel];

CGSize size = [self.strNamee sizeWithFont:font constrainedToSize:CGSizeMake(277, 20.0f)];

NSLog(@”kuang %f  “,size.width);

CGRect rect=self.userNameLabel.frame;

rect.size=size;

NSLog(@”321    %f    %f”,rect.size.width,rect.size.height);

[self.userNameLabel setFrame:rect];

//判断男女

UIImageView * imaSex=[[UIImageView alloc]initWithFrame:CGRectMake(self.userNameLabel.frame.size.width+65, 10, 12, 13)];

21.向自定义的cell中传值,*好用 方法在tableview中来调用 如果有参数  直接来传
22.精确时间差
//时间差

– (NSString *)intervalSinceNow: (NSString *) theDate

{

NSDateFormatter *date=[[NSDateFormatter alloc] init];

[date setDateFormat:@”yyyy-MM-dd HH:mm:ss”];

NSDate *d=[date dateFromString:theDate];

NSTimeInterval late=[d timeIntervalSince1970]*1;

NSDate* dat = [NSDate dateWithTimeIntervalSinceNow:0];

NSTimeInterval now=[dat timeIntervalSince1970]*1;

NSString *timeString=@””;

NSTimeInterval cha=now-late;

if (cha/3600<1) {

timeString = [NSString stringWithFormat:@”%f”, cha/60];

timeString = [timeString substringToIndex:timeString.length-7];

timeString=[NSString stringWithFormat:@”%@分钟前”, timeString];

 

}

if (cha/3600>1&&cha/86400<1) {

timeString = [NSString stringWithFormat:@”%f”, cha/3600];

timeString = [timeString substringToIndex:timeString.length-7];

timeString=[NSString stringWithFormat:@”%@小时前”, timeString];

}

if (cha/86400>1)

{

timeString = [NSString stringWithFormat:@”%f”, cha/86400];

timeString = [timeString substringToIndex:timeString.length-7];

timeString=[NSString stringWithFormat:@”%@天前”, timeString];

 

}

[date release];

return timeString;

}

22.按钮在cell上单击第几行

在cell.contentView上:

//获得row

NSInteger row = [[self.tableView indexPathForCell:(UITableViewCell *)[[sender superview] superview]] row];

//获得section

NSInteger row = [[self.tableView indexPathForCell:(UITableViewCell *)[[sender superview] superview]] section];

//获得indexPath

NSIndexPath *indexPath = [self.tableView indexPathForCell:(UITableViewCell *)[[sender superview] superview]];

直接添加到cell上:
//获得row
NSInteger row = [[self.tableView indexPathForCell:(UITableViewCell *)[sender superview]] row];
//获得section
NSInteger section = [[self.tableView indexPathForCell:(UITableViewCell *)[sender superview]] section];
//获得indexPath
NSIndexPath *indexPath = [self.tableView indexPathForCell:(UITableViewCell *)[sender superview]];
23:判断Home键在哪个方法要执行对应的方法
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(rongTianOrientation:) name:@”UIDeviceOrientationDidChangeNotification” object:nil];

 

– (void) deviceOrientationDidChangeAction:(NSNotification *)note

{

NSInteger currentOrientation = [[note object] orientation];

switch (currentOrientation)  {

case0: {   //未知方向

break;

}

case1: {   //home键向下

break;

}

case2: {   //home键向上

break;

}

case3: {  //home键向左

break;

}

case4: {  //home键向右

break;

}

default:

break;

}

}

24.模拟器不能运行的错误

dyld: Library not loaded: @rpath/SenTestingKit.framework/Versi*****/A/SenTestingKit
Referenced from: /Users/⋯⋯/Application Support/iPhone Simulator/5.0/Applicati*****/F179924C-0EB7-4CCA-88D6-3BA1F68F122D/ILUTU.app/ILUTU
Reason: image not found

 

把SentestingKit。 frameWork 有原来的required改为Optional  就ok

25.还原状态栏

显示原来的状态栏

(1)

[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:YES];

[[UIApplication sharedApplication].keyWindow setFrame:CGRectMake(0, 20, 320, [UIScreen mainScreen].applicationFrame.size.height)];

 

//重新设定标题栏显示的位置

[self.navigationController.navigationBar setFrame:CGRectMake(0, 0, 320, 44)];

(2)

在别的页面[[UIApplication sharedApplication].keyWindow setFrame:CGRectMake(0, 0, 320, [UIScreenmainScreen].applicationFrame.size.height)];

26.获得相册视频的总时间
– (int)getVideopTime:(NSURL * )videourl

{
NSDictionary *opts = [NSDictionary dictionaryWithObject:[NSNumbernumberWithBool:NO]

forKey:AVURLAssetPreferPreciseDurationAndTimingKey];

AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:videourl options:opts]; //初始化视频媒体文件

int minute = 0, second = 0;

second = urlAsset.duration.value / urlAsset.duration.timescale; // 获取视频总时长,单位秒

NSLog(@”movie duration : %d”, second);

if (second >= 60) {
int index = second / 60;

minute = index;

second = second – index*60;

}

return second;

}

27.视频播放器 循环播放 大小……

(1) MPMoviePlayerController

MPMoviePlayerController *player;

NSURL *url =[NSURL URLWithString:fileName];

player = [[MPMoviePlayerController alloc] init];

player.view.frame = CGRectMake(10, 30, 300    , 225);

player.contentURL = url;

player.repeatMode = MPMovieRepeatModeOne;

player.controlStyle = MPMovieControlStyleEmbedded;

 

player.scalingMode = MPMovieScalingModeAspectFill;   //充满屏幕

[self.view addSubview:player.view];

[player play];

(2).avplayer

 

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerItemDidReachEnd:)                                                       name:AVPlayerItemDidPlayToEndTimeNotification

object:plaitem];

}

}];

#pragma mark – Notification Callbacks

– (void)playerItemDidReachEnd:(NSNotification *)notification {
NSLog(@”是跳转*侦吗?  “);

[self.queuePlayer seekToTime:kCMTimeZero];

[self.queuePlayer play];

}

28.sina微博错误返回值格式

http://open.weibo.com/wiki/Error_code

29.ios 获得文件夹的大小

 

//计算文件夹下文件的总大小

-(long)fileSizeForDir:(NSString*)path

{

NSFileManager *fileManager = [[NSFileManager alloc] init];

long size = 0;

NSArray* array = [fileManager contentsOfDirectoryAtPath:path error:nil];

for(int i = 0; i<[array count]; i++)

{

NSString *fullPath = [path stringByAppendingPathComponent:[array objectAtIndex:i]];

 

BOOL isDir;

if ( !([fileManager fileExistsAtPath:fullPath isDirectory:&isDir] && isDir) )

{

NSDictionary *fileAttributeDic=[fileManager attributesOfItemAtPath:fullPath error:nil];

size+= fileAttributeDic.fileSize;

}        else        {

[self fileSizeForDir:fullPath];

}

}

[fileManager release];    return size;    }

30.    谓词过滤

//搜索用谓词过滤数组

NSArray * arrMy=@[@”张2荣三a”,@”李四b”,@”王五a”,@”李流j”,@”荣天321″,@”iOS基地”,@”iOS7″];

NSString  * strg=@”荣”;

NSPredicate * fiecate=[NSPredicate predicateWithFormat:@”SELF CONTAINS %@”,strg];

NSArray * arr3=[arrMy filteredArrayUsingPredicate:fiecate];

NSLog(@”这是我过滤的数组对吗?%@”,arr3);

31.多线程的多种创建

 

//    NSThread * th=[[NSThread alloc]initWithTarget:self selector:@selector(thAction) object:nil];

//    [th start];

 

//[NSThread detachNewThreadSelector:@selector(thAction) toTarget:self withObject:nil];

 

// [self performSelectorInBackground:@selector(thAction) withObject:self];

 

//    NSOperationQueue * operationQueue=[[NSOperationQueue alloc]init];

//    [operationQueue addOperationWithBlock:^{

//        for(int i=0; i<20;i++){

//            NSLog(@”This isThread: %d”,i);

//        }

//    }];

 

//    NSOperationQueue * operationQueue=[[NSOperationQueue alloc]init];

//    //设置线程池中的并发数

//    operationQueue.maxConcurrentOperationCount=1;

//

//    NSInvocationOperation * invocation1=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(threadOne) object:nil];

//    [invocation1 setQueuePriority:NSOperationQueuePriorityLow];

//

//    NSInvocationOperation * invocation2=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(threadTwo) object:nil];

//    [invocation2 setQueuePriority:NSOperationQueuePriorityHigh];

//    [operationQueue addOperation:invocation1];

 

//    [operationQueue addOperation:invocation2];

32.用多线程开启Nstimer提高精确度

//用多线程开启nstimer提高精确度

– (void)mutiThread

{

NSLog(@”Start NStimer”);

@autoreleasepool {

[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerAction:) userInfo:nil repeats:YES];

}

//获得当前的runloop,线程就停在这里

[[NSRunLoop currentRunLoop]run];

NSLog(@”after”);

}

– (void)timerAction:(NSTimer * )timer

{

i++;

NSLog(@”Print NSTimer”);

if (i==5) {

[timer invalidate];

}

}

33.判断此页面是push,还是模态过来的

if (self.presentingViewController) {

NSLog(@”这个是模态过来的!”);}

34。等比例放大缩小视图

UILabel * la=(UILabel * )[self.view viewWithTag:908];

[UIView animateWithDuration:.5 animations:^{

CGAffineTransform transform=la.transform;

transform=CGAffineTransformScale(la.transform, 1.5, 1.5);

la.transform=transform;

} completion:^(BOOL finished) {
CGAffineTransform transform=la.transform;

transform=CGAffineTransformScale(la.transform, 0.5, 0.5);

la.transform=transform;

}];

35.清掉编译文件

~/Library/Developer/Xcode/DerivedData

模拟器清空编译

~/Library/Application Support/iPhone Simulator/

36.改变状态栏的颜色状态

[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];

[[UIApplication sharedApplication] setStatusBarHidden:NO];

37.给自己的项目中添加特殊的标示符号

http://patorjk.com/software/taag/#p=moreopts&h=0&v=1&f=优雅&t=V

38 清空某个文件夹

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

NSString *outputURL = paths[0];

[NSFileManager.new removeItemAtPath:outputURL error:nil];

[NSFileManager.new createDirectoryAtPath:outputURL

withIntermediateDirectories:YES

attributes:nil

error:NULL];

39. 在document下创建文件

NSString *writePath=[NSString stringWithFormat:@”%@/%@.txt”,stre,@”aaa”];

NSData *data = [@”” dataUsingEncoding:NSUTF8StringEncoding];//新文件的初始数据,设为空

[[NSFileManager defaultManager] createFileAtPath:writePath contents:data attributes:nil];//创建文件的命令在这里

40.layoutSubviews在以下情况下会被调用:

1、init初始化不会触发layoutSubviews

2、addSubview会触发layoutSubviews
3、设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化
4、滚动一个UIScrollView会触发layoutSubviews
5、旋转Screen会触发父UIView上的layoutSubviews事件
6、改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件

41.苹果审核加急通道

https://developer.apple.com/appstore/contact/?topic=expedite

51 .美化配置git log

$ git config –global alias.lg “log –color –graph –pretty=format:’%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset’ –abbrev-commit –”
$ git lg
52.查看远程 git
git remote show origin
53.显示远程git仓库
git remote show
54.OC冒泡排序
//   NSMutableArray 自带排序方法

NSMutableArray *lastArrary = [NSMutableArray arrayWithArray:sinceArray];

[lastArrary sortedArrayUsingSelector:@selector(compare:)];

– (NSComparisonResult)compare:(NSNumber *)otherNumber

{

// 设置升 降序
return NSOrderedDescending;

}

// 冒泡排序
NSMutableArray *sinM_Array = [NSMutableArray arrayWithArray:sinceArray];

for (int x = 0; x < sinceArray.count -1; x ++) {

for (int y = x + 1; y < sinceArray.count – 1 -x; y ++) {

int leftNum = [[sinM_Array objectAtIndex:x] intValue];

int rightNum = [[sinM_Array objectAtIndex:y]intValue];

if (leftNum > rightNum) {

[sinM_Array replaceObjectAtIndex:x withObject:[NSNumber numberWithInt:leftNum]];

[sinM_Array replaceObjectAtIndex:y withObject:[NSNumber numberWithInt:rightNum]];

}

}

}
55.前后摄像头的切换

– (AVCaptureDevice *)cameraWithPosition:(AVCaptureDevicePosition)position

{

NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];

for ( AVCaptureDevice *device in devices )

if ( device.position == position )

return device;

return nil;

}

– (void)backCarme:(UIButton *)button

{

NSArray *inputs = self.session.inputs;

for ( AVCaptureDeviceInput *input in inputs ) {

AVCaptureDevice *device = input.device;

if ( [device hasMediaType:AVMediaTypeVideo] ) {

AVCaptureDevicePosition position = device.position;

AVCaptureDevice *newCamera = nil;

AVCaptureDeviceInput *newInput = nil;

if (position == AVCaptureDevicePositionFront)

newCamera = [self cameraWithPosition:AVCaptureDevicePositionBack];

else

newCamera = [self cameraWithPosition:AVCaptureDevicePositionFront];

newInput = [AVCaptureDeviceInput deviceInputWithDevice:newCamera error:nil];

[self.session beginConfiguration];

[self.session removeInput:input];

[self.session addInput:newInput];

[self.session commitConfiguration];

break;

}

}

}
56.#pragma mark –获得视频的尺寸
-(CGSize)getImage:(NSURL *)url

{
NSDictionary *opts = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO]forKey:AVURLAssetPreferPreciseDurationAndTimingKey];

AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:url options:opts];

CGSize size = [[[urlAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] naturalSize];

return size;

}

57.播放音频

// 导入框架 AudioToolbox.framework

NSString *path = [[NSBundle mainBundle] pathForResource:@”msgcome” ofType:@”wav”];

NSURL *url = [NSURL fileURLWithPath:path];

SystemSoundID soundId;

AudioServicesCreateSystemSoundID((CFURLRef)url, &soundId);

AudioServicesPlaySystemSound(soundId);

有用 kotlin 开发后端的吗?

目前只敢工具类用 kotlin,不知道 kotlin 和 spring 会不会有兼容上的坑,兼容 spring 各种注解么。 目前发现比较难受的是,数据类(DO, DTO)必须全部用可空,不然 fastjson 反序列化会有问题。 有生产环境用 kotlin 开发的老哥吗,目前有什么问题?

20 条回复  •  2021-03-31 13:00:48 +08:00     
1 rust   2 小时 13 分钟前 公司一个小项目用了 Ktor,开发确实爽,目前还没有发现什么问题.    
2 xuanbg   2 小时 10 分钟前 自从 get 了终*秘技 cv 大法,Java 语言啰嗦繁琐的弱点也就不存在了,反倒是隐隐成了优势。所以 kotlin 什么的也就没有吸引力了    
3 zoharSoul   2 小时 8 分钟前 有, json 序列化建议用 gson, 和 kt 配合的资料比较多    
4 yazinnnn   2 小时 7 分钟前 json 现在在用 moshi 用 kotlin 可以尝试一下其他东西,比如 quarkus vertx 啥的    
5 micean   2 小时 0 分钟前 兼容旧系统的话,带问号是必要的。 所有的 pojo 用 IDEA 自带的.java 转.kt 就行 kotlin 目前*主要的问题在于 debug 反编译依赖 source,异常打印 stack 的行号不那么准    
6 zerofancy   1 小时 55 分钟前
毕设项目都是 Kotlin,目前遇到过两个奇怪的问题。

1. 同时有 Java 和 Kotlin 的 RestController,Java 的找不到
2. 类型推断好像有点问题

有如下代码:

“`kt
val gridFsFile: GridFSFile? = gridFsTemplate.findOne(Query(Criteria.where(“_id”).`is`(id)))
“`

idea 提示我

“`
‘gridFsFile’ is always non-null type
“`

很明显 gridFsTemplate 是可空的,甚至在接口 GridFsOperations 中已经标注了  。
尝试加入判空逻辑:

“`
if (gridFsFile == null) {
// do something
}
“`

idea 提示:

“`
No method ‘equals(Any?): Boolean’ available
“`

猜想是不是 Kotlin 调用 java 都会有这样问题,结果未能在 demo 项目中复现。
目前用这样的方式判断,原理不明:

“`kt
if (gridFsFile === null) {
// do something
}
“`

7 anke1938   1 小时 55 分钟前 两年前小公司用的纯 kotlin 后端 开发的 web 后台 / 小程序后台 用起来还是很爽的 没啥特别的坑 或者没怎么遇到    
8 hantsy   1 小时 52 分钟前 你多少年没用 Spring 了?
Spring 5.0(2017 年) 开始, 除了 Reactive,Kotlin 就是*重要的特性之一,Spring 对 Kotlin 进行深度集成(远超过之差的 Groovy 语言支持)。
针对很多 Kotlin 特性很多优化,例如,不必声明 open, data class 可以用于 JPA Entity 等。

Kotlin DSL 声明 beans 定义,安全 (参考 Spring 中 BeanDefinitionDSL )等。

val beans = beans {
bean {
CommandLineRunner {
println(“start data initialization…”)
val posts = ref<PostRepository>()
posts.deleteAll()
.thenMany<Post>(
posts.saveAll(
arrayListOf(
Post(null, “my first post”, “content of my first post”),
Post(null, “my second post”, “content of my second post”)
)
)
)
.log()
.subscribe(
{ println(it) },
{ println(it) },
{ println(“data initialization done…”) }
)
}
}

https://github.com/hantsy/spring-kotlin-dsl-sample/blob/master/reactive/src/main/kotlin/com/example/demo/DemoApplication.kt

现在 Spring 还有一个 Spring Kofu 孵化项目(提供完全 Kotlin DSL )。

val app = reactiveWebApplication {
configurationProperties<SampleProperties>(prefix = “sample”)
enable(dataConfig)
enable(webConfig)

listener<ApplicationReadyEvent> {
println(“start data initialization…”)
ref<PostRepository>().init()
}
profile(“foo”) {
beans { bean<Bar>() }
}
}

https://github.com/hantsy/spring-kotlin-dsl-sample/blob/master/kofu-reactive-mongo/src/main/kotlin/com/example/demo/DemoApplication.kt

9 optional   1 小时 51 分钟前 via iPhone   1 你不觉得 fastJson 比较坑。。。    
10 wellsc   1 小时 50 分钟前 借楼问一个 kotlin 的 protobuf grpc 的库    
11 hantsy   1 小时 50 分钟前 @zerofancy Spring Data 一般中 Template, repository 都有写 Kotlin 扩展。估计那 GridFsTemplate 没有处理。    
12 hantsy   1 小时 48 分钟前 @optional 在 Spring 3 。x 就开始提供了内容协商机制,为什么要用 FastJSON 这种东西???实在不明白。    
13 ChangQin   1 小时 10 分钟前 via iPhone @rust ktor+1    
14 zoharSoul   1 小时 3 分钟前 @zerofancy gridFsTemplate.findOne 返回的是 nullable 的吗?    
15 loshine1992   1 小时 0 分钟前 用 moshi 或 kotlin-serialization    
16 xmumiffy   56 分钟前 via Android 建议换掉 fastjson 另外也可以混用 java 至少我这 data class 都是用 java 的,kotlin 的 data class 非常不好用    
17 Kasumi20   42 分钟前 没有发现 Kotlin 不支持 IoC 和 AOP,所以 Kotlin 和 Spring 百分百兼容。 至于什么反序列化的如果是先构造一个空对象,当然会有问题。    
18 boris93   34 分钟前 via iPhone 正在用 Kotlin+Spring Boot+Webflux json 序列化反序列化用的 jackson 目前没啥问题 话说干嘛要用 fastjson 呢?框架自己序列化反序列化用自带的 jackson 就行了啊,也就稍微配置一下的事 偶尔用 gson 也能搞定    
19 youngxhui   27 分钟前 via Android @wellsc grpc 官方有的    
20 wellsc   9 分钟前 via iPhone @youngxhui protobuf 我没找到好用的

关于学习Python的一点学习总结

关于学习Python的一点学习总结

27.创建和使用字典:字典由键及其相应的值组成,这种键值对称为项(item)
方法一:

>>> name={‘Hongkong’:’45’,’shanghai’:’67’,’guizhou’:’89’}
>>> name
{‘Hongkong’: ’45’, ‘shanghai’: ’67’, ‘guizhou’: ’89’}

方法二:

>>> item={(‘hongkong’,’45’),(‘guizhou’,’67’),(‘shanghai’,’89’)}
>>> name=dict(item)
>>> name
{‘hongkong’: ’45’, ‘shanghai’: ’89’, ‘guizhou’: ’67’}
>>> name[‘shanghai’]
’89’

方法三:

>>> name=dict(first=’one’,shanghai=’67’,guizhou=’89’)
>>> name
{‘first’: ‘one’, ‘shanghai’: ’67’, ‘guizhou’: ’89’}
>>> name[‘first’]
‘one’
>>> name[‘guizhou’]
’89’

关于字典的一些基本操作:
1. len(d)返回字典d包含的项(键值对)数。
2.d[k]返回与键k相关联的值。
3.d[k] = v将值v关联到键k。 
4.del d[k]删除键为k的项。
5.k in d检查字典d是否包含键为k的项。

>>> name=dict(first=’one’,shanghai=’67’,guizhou=’89’)
>>> len(name)

>>> name[‘shanghai’]=78
>>> name
{‘first’: ‘one’, ‘shanghai’: 78, ‘guizhou’: ’89’}
>>> del name[‘first’]
>>> name
{‘shanghai’: 78, ‘guizhou’: ’89’}
>>> ‘guizhou’ in name
True

注意:将一个字符赋值给列表是不可以的;而将一个字符赋值给字典是可以的。
例如:

` >>> item=[]
>>> item[2]=’guizhou’
Traceback (most recent call last):
File “<pyshell#43>”, line 1, in <module>
item[2]=’guizhou’
IndexError: list assignment index out of range
——————————————————-
>>> item={}
>>> item[2]=’guizhou’
>>> item[2]
‘guizhou’

遍历点击下拉树图标

遍历点击下拉树图标

发现有下级菜单的图标,都有一个特点,放到css里面了。

然后进行循环,点击一个展开后 需要重新定位这样不会有重复的。这里有个特殊的,是从0开始的,循环的时候要注意。

#循环点击左侧树状图 先遍历点下拉图标
ele_icon=driver.find_elements_by_css_selector(‘.aty-tree-node-hd .aty-tree-node-trigger’)
css=’.aty-tree-node-hd .aty-tree-node-trigger’
left_list=driver.find_elements_by_css_selector(css)
print(f”’我在外面{len(left_list)}”’)
for i in range(0,len(left_list)+1):
driver.find_elements_by_css_selector(css)[i].click()
left_list = driver.find_elements_by_css_selector(css)
print(f”’我在里面{len(left_list)}”’)
time.sleep(2)
print(i)
再附上一个  固定两个层级的代码–备用

import time
import self
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.support import expected_conditions as EC
from selenium import webdriver

# 判断元素是否存在的方法
def isElementExist(ele_icon):
flag=True
# browser=self.driver
try:
driver.find_element_by_xpath(ele_icon)
return flag
except:
flag=False
return flag

if __name__ == ‘__main__’:

driver = webdriver.Chrome()
driver.maximize_window()
driver.implicitly_wait(30)
first_url = ‘http://172.18.65.1111111136:8081/#/query/1’
driver.get(first_url)
#点击到编辑查询界面
driver.find_element_by_xpath(‘//*[@id=”app”]/div[1]/div[2]/div[2]/div/div[3]/div[1]/div/div[2]/span’).click()
driver.find_element_by_xpath(‘//*[@id=”app”]/div[2]/div/div[2]/div[1]/div[1]/button/span’).click()

#循环点击左侧树状图
left_table=driver.find_elements_by_css_selector(‘#jsTreeContain>.aty-tree-node’)
index=len(left_table)
for i in range(1,index+1):
try:
#*个层级 这里有可能会有多个层级,一般是一个 //*[@id=”jsTreeContain”]/li[1]/h3/span[2]
ele=driver.find_element_by_xpath(‘//*[@id=”jsTreeContain”]/li[‘+str(i)+’]/h3/span[2]’)
ele_icon=driver.find_element_by_xpath(‘//*[@id=”jsTreeContain”]/li[‘+str(i)+’]/h3/span[1]’)
flag=isElementExist(ele_icon)
ele_icon.click()
print(‘已展开下级菜单’.center(50,’-‘))
time.sleep(1)
# 第二个层级 #jsTreeContain .aty-tree-node-content >.aty-tree-node
ele2 = driver.find_elements_by_css_selector(‘#jsTreeContain .aty-tree-node-content >.aty-tree-node’)
num = len(ele2)
print(f”'{i}组:{ele.text}里有{num}个表”’)
for m in range(1, num + 1):
ele_inner = driver.find_element_by_xpath(‘//*[@id=”jsTreeContain”]/li[‘ + str(i) + ‘]/ul/li[‘ + str(m) + ‘]’)
ele_inner.click()
print(f”’第{m}个表为:{ele_inner.text}”’)
time.sleep(0.5)

except NoSuchElementException:
driver.find_element_by_xpath(‘//*[@id=”jsTreeContain”]/li[‘+str(i)+’]/h3/span’).click()

LeetCode——反转字符串中的元音字母

LeetCode——反转字符串中的元音字母

LeetCode——反转字符串中的元音字母
题目描述:
编写一个函数,以字符串作为输入,反转该字符串中的元音字母。

示例 1:

输入:“hello”
输出:“holle”
示例 2:

输入:“leetcode”
输出:“leotcede”

提示:

元音字母不包含字母 “y” 。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-vowels-of-a-string
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路:

双指针法:
首先我们将所有元音字母的小写和大写都存储在一个列表yy中,便于判断遇到的字符是否是元音字母。
然后定义两个指针,一个指向字符串首端(start),一个指向字符串末端(end)。
我们遍历整个字符串,循环条件是start < end,在循环中,我们首先判断start和end指向的是否是元音字母,如果不是则更新指针的位置,如果都是元音字母则交换两个字母的位置。
因为我使用的是python语言,所以需要注意字符串是无法修改的,我们需要将s转换为列表,再对列表进行操作,结束后再把该列表转换回字符串,*后返回字符串s。

双指针法python代码:

class Solution(object):
def reverseVowels(self, s):
“””
:type s: str
:rtype: str
“””
yy = [‘a’, ‘e’, ‘i’, ‘o’, ‘u’, ‘A’, ‘E’, ‘I’, ‘O’, ‘U’]
s_list = list(s)
start = 0
end = len(s) – 1
while start < end:
if s[start] not in yy:
start += 1
if s[end] not in yy:
end -= 1
if s[start] in yy and s[end] in yy:
s_list[start], s_list[end] = s_list[end], s_list[start]
start += 1
end -= 1
s = ”.join(s_list)
return s

4款开源云计算框架和工具简介

本文讲的是4款开源云计算框架和工具简介,【IT168 资讯】1、Enomalism (http://www.enomaly.com/) 云计算平台。Enomalism 是一个开放源代码项目,它提供了一个功能类似于 EC2 的云计算框架。Enomalism 基于 Linux,同时支持 Xen 和 Kernel Virtual Machine(KVM)。Enomalism 提供了一个基于 TurboGears Web 应用程序框架和 Python 的软件栈。
2、Euclyptus (http://eucalyptus.cs.ucsb.edu/) 项目(Elastic Utility Computing Architecture for Linking Your Programs To Useful Systems)是 Amazon EC2 的一个开源实现,它与商业服务接口兼容。和 EC2 一样,Eucalyptus 依赖于 Linux 和 Xen 进行操作系统虚拟化。Eucalyptus 是加利福尼亚大学(Santa Barbara)为进行云计算研究而开发的。您可以从该大学的网站上下载它,或者通过 Eucalyptus Public Cloud 体验它,不过后者有一些限制。
3、10Gen (http://www.10gen.com/) 它既是一个云平台,又是一个可下载的开放源代码包,可用于创建您自己的私有云。10gen 是类似于 App Engine 的一个软件栈,它提供与 App Engine 类似的功能 — 但有一些不同之处。通过 10gen,可以使用 Python 以及 JavaScript. 和 Ruby 编程语言开发应用程序。该平台还使用沙盒概念隔离应用程序,并且使用它们自己的应用服务器的许多计算机(当然,是在 Linux 上构建)提供一个可靠的环境。
4、NimBus (http://workspace.globus.org/) 呵呵,网格中间件Globus的作品,从*早的Virtual Workspace演化而来,提供与EC2类似的功能和接口。
另外我们还有一个补充,云计算怎么能没有BOINC呢~
5、BOINC(http://boinc.berkeley.edu/)   BOINC 的英语全称是 Berkeley Open Infrastructure for Network Computing,直接翻译成中文的意思是:伯克利开放式网络计算。
BOINC 是一个分布式计算平台,使得各种分布式计算项目能够使用一个平台软件来运行。不同于传统的分布式计算项目(比如SETI@homeClassic,Folding@home)都有独立的内核和分布式程序,通过BOINC,协调不同的项目所能分配到的系统资源,都将变得非常方便。
BOINC 是由美国加利福尼亚大学伯克利分校(University of California -Berkeley)于2003年开发,通过多年时间、多个项目的测试,目前该平台已经较为成熟。伯克利方面之前曾成功运行 SETI@home项目6年多,取得巨大成功,吸引了五百多万用户的参加,完成了两百万CPU小时的计算量。BOINC平台的开发,很重要的一个原因是为了吸引更多用户加入更多的其他由实际意义的分布式计算项目,比如气候变化,药物开发等。
BOINC 的前景非常客观,有可能发展成一种业界标准,有了 BOINC 平台,分布式计算的开发和推广工作变得更加容易简便。而统一的界面,统一的方式将会大大方便新加入分布式计算的用户,而不必研究每个不同项目的参与方法、积分算法等。  BOINC 中文主页是http://boinc.equn.com/
补充知识:云计算的几大形式
1.SAAS(软件即服务)
这种类型的云计算通过浏览器把程序传给成千上万的用户。在用户眼中看来,这样会省去在服务器和软件授权上的开支;从供应商角度来看,这样只需要维持一个程序就够了,这样能够减少成本。Salesforce.com是迄今为止这类服务*为出名的公司。SAAS在人力资源管理程序和ERP中比较常用。
Google Apps和Zoho Office也是类似的服务
2.实用计算(Utility Computing)
这个主意很早就有了,但是直到*近才在Amazon.com、Sun、IBM和其它提供存储服务和虚拟服务器的公司中新生。这种云计算是为IT行业创造虚拟的数据中心使得其能够把内存、I/O设备、存储和计算能力集中起来成为一个虚拟的资源池来为整个网络提供服务。
3.网络服务
同SAAS关系密切,网络服务提供者们能够提供API让开发者能够开发更多基于互联网的应用,而不是提供单机程序。
4.平台即服务
另一种SAAS,这种形式的云计算把开发环境作为一种服务来提供。你可以使用中间商的设备来开发自己的程序并通过互联网和其服务器传到用户手中。
5.MSP(管理服务提供商)
*古老的云计算运用之一。这种应用更多的是面向IT行业而不是终端用户,常用于邮件病毒扫描、程序监控等等。
6.商业服务平台
SAAS和MSP的混合应用,该类云计算为用户和提供商之间的互动提供了一个平台。比如用户个人开支管理系统,能够根据用户的设置来管理其开支并协调其订购的各种服务。
7.互联网整合
将互联网上提供类似服务的公司整合起来,以便用户能够更方便的比较和选择自己的服务供应商。

用 Vulkan 渲染写一个 Android GPUImage

说的 GPUImage 相信大家都不陌生,GPUImage 是做滤镜、渲染、特效*主流的框架之一,被广泛应用在短视频应用中。

GPUImage 目前还是采用 OpenGL 进行渲染的,可随着技术的发展进步,iOS 系统都开始抛弃 OpenGL 拥抱 Metal 了,Android 也推出了 Vulkan 渲染机制。

关于 Vulkan,大家可能会有点陌生,它和 OpenGL 一样也是跨平台的渲染接口,就是学习成本高了一点,调用流程麻烦了一点,但还是可以掌握的~~~

而且一旦掌握了 Vulkan, 再去看 Metal,或者 Windows 平台下的 Direct3D,就会发现它们有很多共通之处的,很多概念都是可以互相借鉴的,就好比编程语言一样,掌握了 Kotlin 再去看 Swift 感觉就傻傻分不清楚了。

这次要介绍的就是用 Vulkan 实现一个 Android GPUImage 了。

我已经实现了大部分的代码,组建了基本的渲染链机制,复刻了一些特效,具体可以看代码详情:

代码地址如下,欢迎 Star !!!

https://github.com/glumes/Vulkan-GPUImage

想要后续添加特效也是非常方便的,以曝光特效为例:

static const char *shader =
        "#version 400\n"
        "#extension GL_ARB_separate_shader_objects : enable\n"
        "#extension GL_ARB_shading_language_420pack : enable\n"
        "layout (binding = 0) uniform sampler2D tex;\n"
        "layout (location = 0) in vec2 texcoord;\n"
        "layout (location = 0) out vec4 uFragColor;\n"
        "layout (push_constant) uniform exposure {\n"
        " float exposure;\n"
        "} pushVals;\n"
        "void main() {\n"
        "    vec4 textureColor = texture(tex,  texcoord); \n"
        "   uFragColor = vec4(textureColor.rgb * pow(2.0,pushVals.exposure),textureColor.w);\n"
        "}";

class ExposureFilter : public VulkanFilter {

public:
    ExposureFilter() : VulkanFilter() {
        pFragShader = shader;
        pushConstant.resize(1);
        pushConstant[0] = exposure;
    }

    virtual void setProcess(uint32_t process);

protected:

private:
    float exposure = 1.0f;
};

首先实现对应的 Shader,然后对应特效类继承自 VulkanFilter,如果特效没有需要更新的参数,可以不用 pushConstant 。

如果有的话把 pushConstant 的长度修改为参数的个数,每个参数对应 shader 中推送常数的值即可。

然后在 setProcess 里面修改对应的 pushConstant 值:

void ExposureFilter::setProcess(uint32_t process) {
    pushConstant[0] = FilterUtil::getProcess(process,-10.0f,10.0f);
}

在应用中拖动 SeekBar,就可以更改对应的常量值了,从而修改 Shader 效果,对于简单的特效,基本上不用五分钟就可以添加一个新的效果了,很多封装工作都放在 VulkanFilter 里面了。

在实现上采用的是多 RenderPass 的方式,其实也可以用多 Subpass 的方式,但是不好做效果切换,干脆就多 RenderPass 了,其实也可以两者混合。

代码写的不是特别优雅,后面持续优化了,各位走过路过不要错过,目前全网还搜不到 Vulkan 做 GPUImage 相关的实现呢,算是开张了,觉得有帮助就点个 Star 呀~~~

12 条回复  •  2021-03-09 22:56:23 +08:00

1 visionsmile   21 天前 老哥牛皮,已 star

2 glumess   21 天前 @visionsmile 感谢老铁~~

3 codehz   21 天前 via Android Vulkan 在移动平台 /linux 桌面海星,windows 上驱动还是问题很大。。。

4 neoblackcap   21 天前 @codehz windows 平台就老实用 DX 啦,用 vulkan 找不自在么?

5 MCVector   21 天前 @codehz @neoblackcap Vulkan 在 Windows 下的驱动似乎还行呀。我用的 GTX 1070 基本上 Vulkan 1.2 的 feature 都能用,Ray tracing pipeline 的大部分 extensions 都支持

6 MCVector   21 天前 如果用 subpass 的话像 Gaussian blur 这种需要读周围 pixel 的 pass 应该就用不了了吧?这样直接用 renderpass 可能会更灵活一些

7 neoblackcap   21 天前 @MCVector 可能看是哪一家吧,不过 Vulkan 是二等公民,肯定不如 DX 好使。

8 MCVector   21 天前   1 @neoblackcap 我不认为 DX12 在 Windows 下能做的 Vulkan 做不了。据我所知基本上支持 DX12 的显卡在 Windows 下都支持 Vulkan 。所以我认为 Vulkan 是二等公民的说法是不成立的。

9 TSai2019   21 天前 via Android filter-> filter 没有? two input 也没有,离完整 GPUImage 还差不少

10 glumess   21 天前 @TSai2019 filter -> fitler 应该有了啊,采用两个 renderpass 的方式实现的,two input 还在想怎么搞更好…

11 glumess   21 天前 @MCVector 高斯模糊的 shader 应该可以吧,就是 shader 里面的操作呀

12 MCVector   20 天前 @glumess 哈哈我之前也是这么想的。 如果用 subpass 的话在当前的 fragment shader 里只能读前一个 subpass 输出的同一个 fragment (subpassLoad()), 而不是像传统的 renderpass 一样可以用 uv 读。高斯模糊需要周围像素的信息所以在这种情况下会有限制。 Subpass 存在的原因是告诉 GPU 不需要等到整张图片都处理完了再开始下一个 pass 的处理,而是当前 fragment 处理完了下一个 pass 就可以操作这个 fragment 了。这样可以减少一些 overhead,同时也限制了只能操作当前 fragment 。

服务器性能配置要点总结

一般来说,服务器性能主要由三部分决定:

1.服务器的硬件配置

2.服务器操作系统

3.应用程序

服务器硬件配置主要有:

(1).CPU

一般来说CPU的数量越多,主频越高,那么服务器的性能也就会越好。在实际测试过程中,如果在大压力下持续观察CPU的使用率很低,那么CPU的资源基本上是可以满足服务器要求的。这样的情况其实是有点浪费CPU资源的,比较理想的情况是压力不大的时候CPU利用率比较低,压力上来之后CPU利用率保持在60%-70%。大部分的CPU在同一时间内只能运行一个线程,但是超线程的处理器可以在同一个时间运行多个线程,我们可以利用处理前超线程特性提高系统性能。虽然采用超线程技术能同时执行两个线程,但它并不象两个真正的CPU那样,每个CPU都具有独立的资源。当两个线程都同时需要某一个资源时,其中一个要暂时停止,并让出资源,直到这些资源闲置后才能继续。因此超线程的性能并不等于两颗CPU的性能。

(2).RAM

内存的大小也是影响服务器性能的一个重要因素。内存太小,系统进程要被阻塞,应用程序会变得缓慢,甚至是失去响应;如果太大的话,也是造成一种浪费。Linux系统中采用物理内存和虚拟内存两种方式,使用虚拟内存可以缓解物理内存的不足,但是如果占用过多的虚拟内存的话,应用程序的性能会明显的下降。

(3).网络宽带

网络带宽的大小限制了客户端与服务器交互的流量,相对其他硬件资源,网络带宽在价格上更贵。这需要我们合理预估服务器的可服务器能力,需要占用的带宽资源。

(4).硬盘

以前硬盘多是机械方式运作的,主要体现在硬盘读写前寻找磁道的过程。硬盘自带的读写缓存大小,对于硬盘读写速度至关重要。读写速度快的硬盘,通常都带有较大的读写缓存。硬盘的寻道过程是机械方式,决定了其随机读写速度将明显低于顺序读写。在我们做系统设计和实现时,需要考虑到硬盘的这一特性。

操作系统:

(1).操作系统

当前主流的服务器操作系统则主要分为:Windows server、UNIX、Linux、NetWare这四大阵容。不同的系统有不同的特点,要根据情况来判断
Windows server是用户群体*大的服务器系统,不得不多做介绍。旗下又分为:Winnt4.0、Win2000、Win2003、Win2008、Win2012。

Win2000则是Winnt原有完整的内核上进行开发的,对多任务的处理能力有了大幅的提升,管理以及其他功能更加全面,但是系统的稳定性和安全性被削弱了。微软也停止了对win2000的销售和升级服务;win2003在操作的易用性上进行了升级,安全性是目前所有的windows server系统中*高的,线程处理能力、硬件的支持、管理能力都有了大幅的提升,是目前服务器操作系统中主流的操作系统之一。不过由于更多功能的加入,使得win2003的处理能力有所下降。win2008添加了一些特性和策略,以及多了server 2008 r2b版本,运行速度有所加强,但是稳定性有所欠佳。也是主流系统之一。*后就是win2012,目前微服务器操作系统中*高的版本,同时也有r2版本,全面的升级,对应win8内核优化而来,但是,对一些老牌软件应用的兼容性,以及稳定性还是欠佳的。如果说            Windows server是为单用户设计的,那么UNIX则是为多用户而生的。支持大型文件系统和数据库,系统的安全性、稳定性、以及引用软件有着Windows server无法比拟的优势。但是操作界面欠人性化,相关操作管理技未得到推广,使得雇佣维护人员的成本非常高。
Linux是基于UNIX系统开发修补而来,免费、开源、使得其稳定性、安全性、兼容性非常高,对于商业服务器是首选。但是仅凭开发的源代码,使得很多服务器管理人员对其喜爱有加。
NetWare对服务器硬件的要求*低,而且对于网络的组件也有着先天的优势,能够支持无盘工作站,也能支持非常之多游戏软件的开发环境搭建,还能节省很多成本,常用户网络教学、游戏大厅、金融系统等。但是同样是需要手工敲入命令来实现操作指令的。而且系统多年来也没有更深层次的更新,使得部分软件的支持与其他新型应用的兼容性有所欠佳。

(2).操作系统选型原则

一般来说,个人用户或者实验用户,选用windows操作系统比较普遍,人性化的界面设计使得操作简单,而且网上能找到大量的资料来参考。商业或者对服务器性能要求较高场合一般使用Linux或者UNIX.

应用程序本身:
对于应用程序本身的设计来说,只要选用合适的数据结构和内存操作方式,那么至少在性能上差距不是很大,避免对常用内存数据的多次创建和释放。也可增加服务器的性能。

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速