沙盒模型
特點(diǎn)
- 安全
- 隱私
- 整潔
sandbox
- Bundle Container
- yixin.app
[[NSBundle mainBundle] pathForResource:@"name" ofType:@"type"]
- Data Container
NSHomeDirectory()
- Documents
[NSSearchPathForDirectoriesInDomains(NSDocumentDictionary, NSUserDomainMask, YES) firstObject]
- Library
- Temp
NSTemporaryDirectory()
資源管理器
- 發(fā)現(xiàn)資源 : 遍歷目錄
- 修改資源 : 創(chuàng)建目錄, 創(chuàng)建文件, 修改目錄, 修改文件, 讀寫目錄, 讀寫文件
NSFileManager *manager = [[NSFileManager alloc] init];
NSFileManager *defaultManager = [NSFileManager defaultManager];
多線程
- 線程生而不平等 : 主線程 & 后臺線程; 線程有優(yōu)先級的關(guān)系
- 線程是一個(gè)被模擬出來的概念 : CPU 通過分配時(shí)間片模擬出多線程同時(shí)工作的狀態(tài)
NSThread
// 初始化
- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument;
// 啟動
- (void)start;
// 類方法, 會自動啟動
+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;
// 使用繼承, 需要使用 start 方法啟動, 使用 delegate 將線程執(zhí)行的結(jié)果傳出
@interface MyThread : NSThread
@end
@implementation
- (void)main {
// 在這里重寫線程實(shí)現(xiàn)的方法
NSLog(@"thread start");
}
@end
- (void)viewDidLoad {
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(downloadImage:) object:nil];
[thread start];
}
- (void)downloadImage:(id)arg {
NSURL *url = [NSURL urlWithString:@"http://xxx.com/image.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
[self performSelectorOnMainThread:@selector(onImageDone:) withObject:image waitUntilDone:NO];
}
- (void)onImageDone:(id)arg {
if ([arg isKindOfClass:[UIImage class]]) {
self.imageView.image = (UIImage *)arg;
}
}
- 使用 cancel 將線程狀態(tài)標(biāo)記成取消狀態(tài)
+ (BOOL)isMainThread;
+ (NSThread *)mainThread;
+ (NSThread *)currentThread;
// 暫停線程
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
unsigned int sleep(unsigned int);
// 線程通信
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
- (void)performSelectorOnBackground:(SEL)aSelector withObject:(nullable id)argA;
多線程優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn)
- 提高 APP 實(shí)時(shí)響應(yīng)性
- 充分利用計(jì)算資源
- 缺點(diǎn)
- 額外的系統(tǒng)開銷
- 線程同步問題
- 程序復(fù)雜度上升
多線程同時(shí)訪問資源
- 使用 NSLock
@property (nonatomic, strong) NSLock *lock;
_lock = [[NSLock alloc] init];
[_lock lock]; // 加鎖
// 這里執(zhí)行的代碼會把使用的成員變量鎖住
[_lock unlock]; // 解鎖
// 過程猜測: 使用 [_lock lock] 的時(shí)候, 如果 _lock 在鎖住狀態(tài), 則這個(gè)操作會一直等待,
// 等到操作執(zhí)行完之后, _lock 被解鎖, 才能執(zhí)行下次加鎖操作
- 使用 @synchronized
- 簡單
- 不需要自己 unlock, 不容易產(chǎn)生死鎖
@synchronized (self) {
// 執(zhí)行操作, 這里的操作會被加鎖, 執(zhí)行完后退出 synchronized 則會被解鎖
}
死鎖狀態(tài)
GCD (Grand Central Dispatch)
// 隊(duì)列
dispatch_quequ_t
// 創(chuàng)建
dispatch_queue_t
dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);
// 使用
void
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
void
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
單例
+ (instancetype)sharedObject {
static SingletonObject *instance = nil;
// 下面的兩行代碼只會被之行一次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[SingletonObject alloc] init];
});
return instance;
}
dispatch_semaphore (信號量)
dispatch_semaphore_t
// 創(chuàng)建
dispatch_semaphore_t
dispatch_semaphore_create(long value);
// 觸發(fā)信號量
long
dispatch_semaphore_signal(dispatch_semaphore_t dsema);
// 等待信號量
long
dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);
NSOperation
創(chuàng)建 NSOperationQueue :
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
-
創(chuàng)建 NSOperation 子類對象 : 重寫 NSOperation 任務(wù)執(zhí)行函數(shù)
@interface MyOperation : NSOperation @end @implementation MyOperation - (void)main { // 任務(wù)執(zhí)行函數(shù) }
將 NSOperation 的子類對象加入 NSOperationQueue :
[queue addOperation:operation];
-
設(shè)置子類對象的
completionBlock
, 在 block 中進(jìn)行剩余的 UI 操作NSOperationQueue *queue = [[NSOperationQueue alloc] init]; MyOperation *op = [[MyOperation alloc] init]; __weak typeof(op) weakOp = op; op.completionBlock = ^(){ // 執(zhí)行完畢之后需要進(jìn)行的操作 // 在此的操作也是在子線程進(jìn)行的, 所以如果涉及到 UI 的操作需要手動放到主線程中 }
NSBlockOperation
+ (instancetype)blockOperationWithBlock:(void (^)(void))block;
NSInvocationOperation
+ (nullable instancetype)initWithTarget:(id)target selector:(SEL)sel object:(nullable id)arg;
Serial vs Concurrent
@property NSInteger maxConcurrentOperationCount;
// maxConcurrentOperationCount = 1 Serial Queue
// maxConcurrentOperationCount > 1 Concurrent Queue
// [NSOperationQueue mainQueue] dispatch_get_main_queue()
@property (readonly) NSUinteger operationCount;
GCD vs NSOperation
- NSOperation 支持取消
- 標(biāo)記成取消狀態(tài), 當(dāng)執(zhí)行到這個(gè)任務(wù)的時(shí)候, 任務(wù)不會被執(zhí)行但是 completetionBlock 仍然會被執(zhí)行
- 封裝, 能適應(yīng)更復(fù)雜的操作和提供更精細(xì)化的操控
NSOperation 等待
- 創(chuàng)建兩個(gè) OperationQueue : uploadQueue, finalQueue
- 在 uploadQueue 中添加所有的操作
- 在 finalQueue 中添加后續(xù)的操作 finalOperation, 中間加入代碼
[uploadQueue waitUntilAllOperationsAreFinished];
- finalOperation 會等待到所有的 uploadQueue 中任務(wù)執(zhí)行完然后執(zhí)行
使用 dependency 等待任務(wù)
@interface NSOperation : NSObject
- (void)addDependency:(NSOperation *)op; // 添加依賴任務(wù)
- (void)removeDependency:(NSOperation *)op; // 移除依賴任務(wù)
@property (readonly, copy) NSArray<NSOperation *> *dependencies;
- 循環(huán)依賴
- 顯式循環(huán)依賴
- 隱式循環(huán)依賴 : 串行隊(duì)列中, 前面的任務(wù)依賴于后面的任務(wù), 導(dǎo)致任務(wù)循環(huán)依賴
優(yōu)先級
@interface NSOperation : NSObject
@property NSOperationQueuePriority queuePriority;
typedef NS_ENUM(NSInteger, NSOperationQueuePriority) {
NSOperationQueuePriorityVeryLow = -8L;
NSOperationQueuePriorityLow = -4L;
NSOperationQueuePriorityNormal = 0;
NSOperationQueuePriorityHigh = 4;
NSOperationQueuePriorityVeryHigh = 8;
}
RunLoop 常駐的主線程
- 和線程一一對應(yīng), 每個(gè)線程有且只有一個(gè) RunLoop
- 線程創(chuàng)建的時(shí)候并未有 RunLoop, 需要手動創(chuàng)建, 主線程除外
- RunLoop 的創(chuàng)建發(fā)生在第一次獲取它的時(shí)候(單例)
- 只能在線程內(nèi)部獲取對應(yīng)的 RunLoop (主線程 RunLoop 除外)
@interface NSRunLoop : NSObject
+ (NSRunLoop *)currentRunLoop;
+ (NSRunLoop *)mainRunLoop;
- (void)run;
- (void)runUntilDate:(NSDate *)limitDate;
@end
常駐的后臺線程
- 將有繁重的操作的回調(diào)指定到固定的線程中執(zhí)行
- perform selector 指定到固定的線程執(zhí)行
RunLoop Mode
- NSDefaultRunLoopMode
- NSRunLoopCommonModes
- default mode
- modal mode
- tracking mode UITrackingRunLoopMode
@interface NSRunLoop : NSObject
- (void)addTimer:(NSTimer *)timer forMode:(NSString *);
@end
iOS 網(wǎng)絡(luò)基礎(chǔ)
NSURLRequest
/********** 創(chuàng)建請求 **********/
@interface NSURLRequest : NSObject
// 各種屬性都不可設(shè)置
+ (instancetype)requestWithURL:(NSURL *)URL;
- (instancetype)initWithURL:(NSURL *)URL;
@property (nullable, readonly, copy) NSURL *URL;
@property (nullable, readonly, copy) NSString *HTTPMethod;
@property (nullable, readonly, copy) NSDictionary<NSString *, NSString *> *allHTTPHeaderFields;
- (nullable NSString *)valueForHTTPHeaderField:(NSString *)field;
@property (nullable, readonly, copy) NSData *HTTPBody;
@end
@interface : NSMutableURLRequest : NSURLRequest
// ... 各種屬性都是可以設(shè)置的
@interface NSURL : NSObject
- (nullable instancetype)initWithString:(NSString *)URLString;
+ (nullable instancetype)URLWithString:(NSString *)URLString;
@property (readonly, copy) NSString *absoluteString;
@end
/********** 發(fā)送請求 **********/
@interface NSURLConnection : NSObject // 逐步被廢棄, 推薦使用 NSURLSession
- (nullable instancetype)initWithRequest:(NSURLRequest *)request delegate:(nullable id)delegate startImmediately:(BOOL)startImmediately;
- (void)start;
@end
/********** 接收響應(yīng) **********/
@protocol NSURLConnectionDataDelegate <NSURLConnectionDelegate>
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
@end
@protocol NSURLConnectionDelegate <NSObject>
@optional
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
@end
@interface NSHTTPURLResponse : NSURLResponse
@property (readonly) NSInteger statusCode;
@property (readonly, copy) NSDictionary *allHeaderFields;
@end
@interface NSURLResponse : NSObject <NSSecureCoding, NSCopying>
@property (nullable, readonly, copy) NSURL *URL;
@end
/********** 獲取數(shù)據(jù) : 解析 JSON/XML 數(shù)據(jù) **********/
// JSON <==> NSData
@interface NSJSONSeriallization : NSObject
+ (BOOL)isValidJSONObject:(id)obj;
+ (nullable NSData *)dataWithJSONObject:(id)obj options:(NSJSONWritingOptions)opt error:(NSError **)error;
+ (nullable id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error;
流程 Demo
// 創(chuàng)建一個(gè)請求
NSURL *url = [NSURL URLWithString:@"http://xxx.com"];
NSMutableURLRequest *request = [NSMutableRequest requestWithURL:url];
request.HTTPMethod = @"POST";
[request setValue:@"NEDemoAgent" forHTTPHeaderField:@"User-Agent"];
[request setValue:@"Application/JSON" forHTTPHeaderField:@"Content-Type"];
// 發(fā)送請求
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
[connection start];
// 接收響應(yīng)
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
self.response = response;
self.responseData = [NSMutableData data];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// handle error.
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// handle when request finished.
NSStringEncoding stringEncoding = NSUTF8StringEncoding;
// 直接獲取返回的字符串
self.responseString = [[NSString alloc] initWithData:self.responseData
encoding:stringEncoding];
// self.responseInfo 是 id 類型, 在這里獲取的是格式化之后的 JSON 數(shù)據(jù), 可能是 NSArray 或者 NSDictionary
self.responseInfo = [NSJSONSerialization JSONObjectWithData:self.responseData
options:0
error:nil];
}
使用 NSURLSession 代替 NSURLConnection
NSURLSession | NSURLConnection |
---|---|
NSURLConnection |
NSURLSession & NSURLSessionTask & NSURLSessionConfiguration |
NSURLConnectionDelegate && NSURLConnectionDatDelegate |
NSURLSessionDelegate |
@interface NSURLSession : NSObject
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration;
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue;
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request;
- (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url;
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL;
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(NSData *)bodyData;
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request;
- (NSURLSessionDownloadTask *)downloadTaskWithURL:(NSURL *)url;