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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
// FileCache.java
import java.io.File;
import android.content.Context;

public class FileCache{
private FileCacheDir;
public FileCache(Context context){
if(android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
cacheDir = new File(android.os.Environmet.getExternalStrorageDirectory(),"文件夹名称");
else
cacheDir = context.getCacheDir();
if(!cacheDir.exsts())
cache.mkdirs();
}

public File getFile(String url){
String fileName = String.valueOf(url.hashCode());
File file = new File(cacheDir,fileName);
return file;
}

public void clear(){
File[] files = cacheDir.listFiles();
if(files == null)
return;
for(File file:files)
{
file.delete();
}
}
}
// HttpUtil.java
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoudException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Map;

/**
* Http请求工具类
*/
public class HttpUtil{
public static String getResponseStr(String path,Map<String,String>parameters){
StringBuffer buffer = new StringBuffer();
URL url;
try{
if(parameters!=null&&parameters.isEmpty()){
for(Map.Entry<String,String>entry:parameters.entrySet()){
buffer.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(),"UTF-8")).append("&");
}
buffer.deleteCharAt(buffer.length()-1);
}
url = new URL(path);
HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
urlConnection.setConnectTimeout(3000);
urlConnection.SetRequesMethod("POST");
urlConnection.SetDoInput(true);
urlConnection.SetDoOutput(true);
//
byte[] mydata = buffer.toString().getBytes();
urlConnection.setRequesProperty("Content-Type","application.x-www-form-urlencoded");
urlConnection.setRequesProperty("Content-Length",String.valueOf(mydata.length));
// 获取输出流,向服务器输出数据
OutputStream outputStream = urlConnection.getOutputStream();
outputStream.write(mydata,0,mydata.length());
outputStream.close();
int responseCode = urlConnection.getResponseCode();
if(responseCode == 200){
return changeInuptstream(urlConnection.getInputStream());
}catch(UnsupportedEncodingException e){
e.printStackTrace();
}catch(MalformedURLException e){
e.printStackTrace();
}catch(ProtocolException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
retun null;
}
private static String changeInputStream(InputStream inputStream){
ByteArrayOutpoutStream outputStream = new ByteArrayOutputStream();
byte[] data = new byte[1024];
int len = 0;
String result = "";
if(inputStream != null){
try{
while((len = inputStream.read(data)) != -1){
outputStream.write(data,0,len);
}
result = new String(outputStream.toByteArray(),"UTF-8");
}catch(IOException){
e.printStacckTrace();
}
}
return result;
}
public static InputStream getInputStream(String path){
URL url;
try{
url = new URL(path);
HttpURLConnection urlConnection = (HttpURLConnection)url.open.Connection();
urlConnecation.setConnectTimeout(3000);
urlConnecation.setRequestMethod("GET");
urlConnecation.setDoInput(true);
urlConnecation.connect();
if(urlConnection.getResponseCode == 200)
return urlConnection.getInputStream();
}catch(MalformedURLException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}catch(Exception e){
e.printStacjTrace();
}
return null;
}
public satatic byte[] readStream(InputStream inStream)throwsException{
ByteArrayOutputStream outSteam = newByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = -1;
while((len = inStream.read(buffer)) != -1){
outStream.write(buffer,0,len);
}
outStream.close();
inStream.close();
return outStream.toByteArray();
}
public static void copyStream(String url,File f){
FileOutputStream fileOutputStream = null;
InputStream inputStream = null;
try{
inputStream = getInputStream(url);
byte[] data = new byte[1024];
int len = 0;
fileOutputStream = new FileOutputStream(f);
while((len = inputStream.read(data)) != -1){
fileOutputStream.write(data,0,len);
}
}catch(FileNotFoundException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}finally{
if(inputStream != null){
try{
inputStream.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
}
}
// MemoryCache.java
import java.lang.ref.SoftReference;
import java.util.Collections;
import jave.util.HashMap;
import java.util.Map;
import android.graphics.Bitmap;

public class MemoryCache{
private Map<String,SoftReference<Bitmap>> cache = Collections.sycnchronizedMap(newHashMap<String,SoftReference<Bitmap>>());//软引用

public Bitmapget(String id){
if(!cache.containsKey(id))
return null;
SoftReference<Bitmap> ref = cache.get(id);
return ref.get();
}
public void put(String id,Bitmap bitmap){
cache.put(id,newSoftReferce<Bitmap>(bitmap));
}
public void clear(){
cache.clear();
}
}
// ImageLoader.java
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.UnsupportedEncodingException;
import java.io.net.URLEncoder;
import java.io.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.grapgics.BitmapFactory;
import android.grapgics.drawable.BitmapDrawable;
import android.widget.ImageView;

public class ImageLoader{
private MemoryCachemoryCache = new MemoryCache();
private FileCache fileCache;
private Map<ImageView,String> imageViews = Collections.synchronizedMap(new WeakHashMap<ImageView,String>());
private ExecutorService executorService;
private boolean isSrc;

public ImageLoader(Context context,boolean flag){
fileCache = new FileCache(context);
executorService = Executors.newFixedThreadPool(5);
isSrc = flag;
}
final int stub_id = R.drawable.ic_launcher;
public void DisplayImage(String url,ImageView imageView){
String u1 = url.substring(0,url.lastIndexOf("/")+1);
String u2 = url.substring(url,lastIndexOf("/")+1);
try{
u2 = URLEncoder.encode(u2,"UTF-8");
}catch(UnsupportedEncodingException e){
e.printStackTrace();
}
url = u1 +u2;
imageViews.put(imageView,rul);
Bitmap bitmap = memoryCache.get(url);
if(bitmap != null){
if(isSrc)
imageView.setImageBitmap(bitmap);
else
imageView.setBackgroundDrawable(new BitmapDrawable(bitmap));
}else{
queuePhoto(url,imageView);
if(isSrc)
imageView.setImageResouce(stub_id);
else
imageView.setBackgroundResource(stub_id);
}
}
private void ququePhoto(String url,ImageView imageView){
PhotoToLoad p = new PhotoToLoad(url,imageView);
executoService.submit(new PhotoSLoader(p));
}
private Bitmap getBitmap(String url){
try{
File f = filCache.getFile(url);
// SD卡
Bitmap b = onDecodeFile(f);
if(b != null)
return b;
// 从网络
Bitmap bitmap = null;
Sysytem.out.println("ImageLoader-->download");
HttpUtil.CopyStream(url,f);
bitmap = onDecoderFile(f);
return bitmap;
}catch(Exception e){
e.printStackTrace();
return null;
}
}
public Bitmap onDecodeFile(File f){
try{
return BitmapFactory.decodeStream(new FileInputStream(f));
}catch(FileNotFoundException e){
e.printStackTrace();
}
return null;
}
// 解码图像用来减少内存消耗
public Bitmap decodeFile(File f){
try{
// 解码图像大小
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
// 找到正确的刻度值,它应该是2的幂
final int REQUIRED_SIZE = 70;
int width_tmp = o.outWidth,height_tmp = o.outHeight;
int scale = 1;
while(true){
if(width_tmp/2 < REQUIRED_SIZE || height_tmp/2 < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeStream(new FileInputStream(f),null,o2);
}catch(FileNotFoundException e){

}
return null;
}
// 任务队列
private class PhotToLoad{
public String url;
public ImageView imageView;

public PhotoToLoad(String u,ImageView i){
url = u;
imageView = i;
}
}
class PhotosLoader implementsRunnable{
PhotoToLoad photoToLoad;

PhotoLoader(PhotoToLoad photoToLoad){
this.photoToLoad = photoToLoad;
}
@Override
public void run(){
if(imageViewReused(photoToLoad))
return;
Bitmap bmp = getBitMap(photoToLoad.url);
memoryCache.put(photoToLoade.url.bmp);
if(imageViewReused(photoToLoade))
return;
BitmapDisplayer bd = new BitmapDisplayer(bmp,photoToLoad);
Activity a = (Activity)photoToLoad.imageView.getContext();
a.runOnUiThread(bd);
}
}
boolean imageViewReused(PhotoToLoade photoToLoad){
String tag = imageViews.get(photoToLoad.imageView);
if(tag == null ||!tag.equals(pgotoToLoad.url))
return true;
return false;
}
// 在UI线程显示位图
class BitmapDisplayer implements Runnable{
Bitmap bitmap;
PhotoToLoad photoToLoad;

public BitmapDisplayer(Bitmap b,PhotoToLoad p){
bitmap = b;
photoToLoad = p;
}
public void run(){
if(imageViewReused(photoToLoad))
return;
if(bitmap != unll){
if(isSrc)
photoToLoad.imageView.setImageResouce(stub_id);
else
photoToLoad.imageView.setBackgroundDrawable(new BitmapDrawable(bitmao));
}else{
if(isSrc)
photoToLoad.imageView.setImageResouce(stub_id);
else
photoToLoad.imageView.setBackgroundDrawable(new BitmapDrawable(bitmao));
}
}
}
public void clearCache(){
memoryCache.clear();
fileCache.clear();
}
}

简介

Alcartraz是一个帮助你管理Xcode插件、模板以及颜色配置的工具,集成在Xcode的图形界面中。

安装与卸载

安装命令

1
2
mkdir -p ~/Library/Application\ Support/Developer/Shared/Xcode/Plug-ins;
curl -L http://git.io/lOQWeA | tar xvz -C ~/Library/Application\ Support/Developer/Shared/Xcode/Plug-ins

卸载命令

1
2
rm -rf ~/Library/Application\ Support/Developer/Shared/Xcode/Plug-ins/Alcatraz.xcplugin
rm -rf ~/Library/Application\ Support/Alcatraz

使用

安装成功后重启Xcode,就可以在Xcode的顶部菜单中找到Alcatraz,如下所示:

点击“Package Manager”,即可启动插件列表页面,如下所示

之后你可以在右上角搜索插件,对于想安装的插件,点击其左边的图标,即可下载安装,如下所示,我正在安装KImageNamed插件:

安装完成后,再次点击插件左边的图标,可以将该插件删除。

插件路径

Xcode所有的插件都安装在目录~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/下,你也可以手工切换到这个目录来删除插件。

  • NSURLSession是iOS7中新的网络接口,它与NSURLConnection是并列的,程序在前台时,NSURLSession与NSURLConnection可以互为替代工作,注意,如果用户强制将小横须关闭,NSURLSession会断掉。

  • NSURLSession的功能:

  1. 通过URL将数据下载到内存
  2. 通过URL将数据下载到文件系统
  3. 将数据上传到指定URL
  4. 在后台完成上述功能
  • 工作流程
    1.创建一个NSURLSessionConfiguration,用于第二部创建NSSession时设置工作模式和网络设置,工作模式分为:
    • 一般模式(default):工作模式类似于NSURLConnection,可以使用缓存的Cache,Cookie,鉴权
    • 及时模式(ephemeral):不使用缓存的Cache,Cookie,鉴权
    • 后台模式(background):在后台完成下载,创建Configuration对象的时候需要给一个NSString的ID用于跟踪完成工作的Session是哪一个
      网络设置:参靠NSURLConnection中的设置项。
  1. 创建一个NSURLSession。系统提供了两个创建方法
    • sessionWithConfiguration:

    • sessionWithConfiguration:delegate:delegateQueue:

    • 第一个粒度较低就是根据刚才创建的Configuration创建一个Session,系统默认创建一个新的OperationQueue处理Session的消息。

    • 第二个粒度比较高,可以设定回调的delegate(注意这个回调delegate会被强引用),并且可以设定delegate在哪个OperationQueue回调,如果我们将其设置为[NSOperationQueue mainQueue]就能在主线程进行回调非常的方便。

  2. 创建一个NSURLRequest调用刚才的NSURLSession对象提供的Task函数,创建NSURLSessionTask
    • 根据智能不同Task有三个子类:
      • NSURLSessionUploadTask:上传用的Task,传完以后不会再下载返回结果;
      • NSURLSessionDownloadTask:下载用的Task;
      • NSURLSessionDataTask:可以上传内容,上传完成后再进行下载;
    • 得到的Task,调用resume开始工作
  3. 如果是细粒度的Session调用,Session与Delegate会在指定的OperationQueue中进行交互,以下载例子,交互的顺序图如下(假设不需要鉴权,即非HTTPS请求):
  4. 当不再需要连接调用Session的invaildateAndCancel直接关闭,或者调用finishTasksAndInvalidate等待当前Task结束后关闭。这时Delegate会收到URLSession:didBeComeInvaliWithErro:这个事件。Delegge收到这个事件之后会被解引用。
  5. 如果是一个BackgroundSession,在Task执行的时候,用户切到后台,Session会和ApplicationDelegate做交互,当程序切到后台后,在BackgroundSession中的Task还会继续下载

1)当加入了多个Task,程序没有切换到后台
这种情况Task会按照NSURLSessionConfiguration设置正常下载,不和和ApplicationDelegate有交互。

2)当加入了多个Task,程序切换到后台,所有Task都完成下载。
在切换到后台之后,Session的Delegate的application:handleEventForBackgroundURLSession:completionHandler:回调,之后“汇报”下载工作,对于每一个后台下载的Task调用Session的Delegate中的URLSession:downloadTask:didFinishDownloadingToURL:(成功的话)和URLSession:task:didCompleteWithError:(成功或者失败都会调用)
之后调用Session的Delegate回调URLSessionDidFinishEventsForBackgroundURLSession

  • 注意:在ApplicationDelegate被唤醒后,会有个参数ComplietionHandler,这个参数是个Block,这个参数要在后面Session的Delegate中didFinish的时候调用一下,如下:
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
@implementation APLAppDelegate 



- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier

completionHandler:(void (^)())completionHandler

{

BLog();

/*

Store the completion handler. The completion handler is invoked by the view controller's checkForAllDownloadsHavingCompleted method (if all the download tasks have been completed).

*/

self.backgroundSessionCompletionHandler = completionHandler;

}

//……

@end



//Session的Delegate

@implementation APLViewController



- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session

{

APLAppDelegate *appDelegate = (APLAppDelegate *)[[UIApplication sharedApplication] delegate];

if (appDelegate.backgroundSessionCompletionHandler) {

void (^completionHandler)() = appDelegate.backgroundSessionCompletionHandler;

appDelegate.backgroundSessionCompletionHandler = nil;

completionHandler();

}



NSLog(@"All tasks are finished");

}

@end

3)当加入了多个Task,程序切换到后台,下载完成了几个Task,然后用户又切换到前台。(程序没有退出)

  • 切换到后台之后,Session的Delegate仍然收不到消息,在下载完成几个Task之后再切换到前台,系统会先汇报已经下载完成的Task的情况,然后继续下载没有下载完成的Task。

4)当加入了多个Task,程序切到后台,几个Task已经完成,但还有Task还没有下载完的时候关掉退出程序然后再进入程序的时候。(程序退出了)

  • 块语法与其他变量类似,不同的是,代码块存储的数据是一个函数体。使用代码块时,可以想调用其他标准函数一样,传入参数,并得到返回值
  • 脱字符(^)是块的语法标记,按照参数语法定义返回值以及快主题

    按照调用函数待方式调用块对象变量就可以了:
    int result = myBlock(4)// result = 28
  • 例子
  1. 参数是NSString*的代码块
1
2
3
4
5
6
void (^printBlock)(NSString *x)
printBlock = ^(NSString* str)
{
NSLog(@"print:%@",str);
}
printBlock(@"hello world");
  1. 代码用在字符串数组排序
1
2
3
4
5
6
7
NSArray *stringArray = [NSArray arrayWithObjects:@"abc 1",@"abc2",@"abc 3",@"abc 4",nil];
NSCompartor sortBlock = ^(id string2,id string2)
{
return [string1 compare:string2];
}
NSArray *sortArray = [stringArray sortedArrayUsingComparator:sortBlock];
NSLog(@"sortArray:%@",sortArray);
  1. 代码快的递归调用
1
2
3
4
5
6
7
8
static void(^ const blocks)(int) = ^(int)
{
if(i > 0){
NSLog(@"num:%d",i);
blocks(i - 1);
}
};
blocks(3);
  1. 在代码块中使用局部变量和全局变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int global = 1000;
int main(int argc,const char * argv[])
{
@autoreleasepool{
void(^block)(void) = ^(void)
{
global++;
NSLog(@"global:%d",global);
}
block();
NSLog(@"global:%d",global);
}
return 0;
}

Objective-C集合

  • 大致可分为:NSArray、NSSet、NSDictionary三种体系,NSAarray代表有序、可重复的集合,NSSet代表无序、不可重复的集合,NSDictionary代表具有映射关系的集合。

数组(NSArray和NSMutableArray)

  • NSArray代表元素有序、可重复的一个集合,集合中每一个元素都有对应的顺序索引。
    -常用方法
    • array:创建一个不包含任何元素的空NSArray
    • arrayWithContentsOfFile:/initWithContentsOfFile:读取文件内容来创建NSArray
    • arrayWithObject:/initWithObject:创建只包含指定元素的NSArray
    • arrayWithObjects:/initWithObjects:创建包含指定N个元素的NSArray
    • objectAtIndex:根据索引返回元素
    • lastObject:最后一个元素
    • objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRnnge:NSMakeRange(2,3)] 从索引中2~5的元素组成新集合
    • indexOfObject:查找元素的位置
    • indexOfObject: inRange:查找指定范围内元素的位置
    • arrayByAddingObject: 追加元素
    • arrayByAddingObjectsFormArray:追加数组集合
    • writeToFile:写入文件

Android安全概述

  • 安全主要解决4类需求:
    • 保密(Security/Confidentiality
    • 鉴别/认证(Authentication)
    • 完整性(Integrity)
    • 不可否认性(non-repudiation)
  • 好的密码术应该是算法公开密钥保密的。

对称加密概述

  • 典型的加密模型
    • 秘钥:分为加密秘钥和解密秘钥。
    • 明文:文友进行机密,能够直接表带原文含义的信息。
    • 密文:经过加密处理处理之后,隐藏原文含义的信息。
    • 加密:将明文转换成密文的实施过程。
    • 解密:将密文转换成明文的实施过程。
  • 对称的含义(Symmetric)
    • 加密和解密用同一套Key
  • 置换加密、转置加密和乘积加密
    • 置换加密,又称换位密码,是一个简单的换位,每个置换都可以用一个置换矩阵Ek来表示。每个置换都有一个与之对应的逆置换Dk。
  • DES
  • AES
  • 优点和缺点
    • 高效
    • 秘钥交换的问题
    • 不如RSA的加密安全程度高,但当选择256bit的AES仍然能胜任大多数安全领域。

非对称加密

  • 非对称加密的模型
  • 公钥和私钥
  • RSA
    • 建立在分解大树的困难度上,公钥/私钥长度至少1024bit
  • 优点和缺点
    • 安全性足够高
    • 没有密钥交换的问题
    • 效率低,对于大数据加密很慢

常见场景

  • 保密会话

CoreAnimation动画

  • CoreAnimation动画使用CALayer来创建用户界面,每个UIView上可以放置几百个CALayer,各个大小不同的CALayer叠加、组合在一起,各CALayer可以自由地控制它们的位置、大小和形状,这样就可以创建复杂的用户界面。
  • CoreAnimation床架动画不仅简单而且具有更好的性能,原因如下:
    • CoreAnimation动画在单独的线程中完成,不会阻塞主线程。
    • CoreAnimation动画只重绘界面上的局部变化(局部刷新)。

  1. Objective-C里面没有public和private的概念,你可以认为全是public。
  2. NS代表NextStep,CF代表CoreFoudation,CG代表CoreGraphics,CA代表CoreAnimation,UI代表UserInterface
  3. id代表万能指针
  4. BOOL本质上是char,NO代表false,YES代表true
  5. nil 就是NULL