iOS 開発の結構
畫面
UI
UIWebview
[[UIApplication sharedApplication] openURL:]
調用谷歌地圖(Google Maps)
NSString *searchQuery = @"1 Infinite Loop, Cupertino, CA 95014";
searchQuery = [addressText stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
NSString *urlString=[NSString stringWithFormat:@"http://maps.google.com/maps?q=%@", searchQuery];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlText]];
調用郵件客戶端(Apple Mail)
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"mailto://admin@eyecm.com"]];
撥號(Phone Number)
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"tel://10086"]];
調用短信(SMS)
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"sms:10086"]];
調用瀏覽器(Safari Browser)
NSURL *url= [NSURL URLWithString:@"http://eyecm.com"];
[[UIApplication sharedApplication] openURL:url];
調用應用商店(AppStore)
NSURL *appStoreUrl= [NSURL URLWithString:@"http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=291586600&mt=8"];
[[UIApplication sharedApplication] openURL:appStoreUrl];
調用appstore中程序的評論
NSString *str = [NSString stringWithFormat:
@"itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=%d",
m_appleID ];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:str]];
// 啟動系統風火輪
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
// 隱藏系統風火輪
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
畫面の切り替え
UINavgationController
UIBarButtonItem* next =?[[[UIBarButtonItem alloc] initWithTitle:@"閉じる"
style:UIBarButtonItemStyleBordered
target:modalViewController
action:@selector(touchedCloseModalViewControler)] autorelease];
modalViewController.navigationItem.leftBarButtonItem = next;
UINavigationController *navigationController =?[[[UINavigationController alloc] initWithRootViewController:modalViewController] autorelease];
[self presentViewController:navigationController animated:YES completion:nil];
[self.navigationController pushViewController:detail animated:YES];
[self.navigationController popViewControllerAnimated:YES];
[self presentViewController:navigationController animated:YES completion:nil];
Network
NSURLSession
配置
image.xcassets
Prefix.pch
#ifdef __OBJC__
#endif
Info.plist
//獲取當前版本號
NSDictionary*infoDic = [[NSBundlemainBundle]infoDictionary];
NSLog(@"%@",infoDic);
NSString?*currentAppVersion = infoDic[@"CFBundleShortVersionString"];
// contentView.plist読み込み準備
NSString *path = [[NSBundle mainBundle] pathForResource:@"contentView" ofType:@"plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
NSString?*executableFile?=?[[[NSBundle?mainBundle]?infoDictionary]?objectForKey:(NSString?*)kCFBundleExecutableKey];
//獲取項目名稱
NSString?*version?=?[[[NSBundle?mainBundle]?infoDictionary]?objectForKey:(NSString?*)kCFBundleVersionKey];
//獲取項目版本號 NSDictionary?*infoDictionary?=?[[NSBundle?mainBundle]?infoDictionary]; ?CFShow(infoDictionary); //?app名稱
NSString?*app_Name?=?[infoDictionary?objectForKey:@"CFBundleDisplayName"];
//?app版本
NSString?*app_Version?=?[infoDictionary?objectForKey:@"CFBundleShortVersionString"];
//?app?build版本
NSString?*app_build?=?[infoDictionary?objectForKey:@"CFBundleVersion"];
performSelectorOnMainThread的一些細節
#pragma mark 加載圖片
-(void)loadImage{
//請求數據
NSData *data= [self requestData];
/*將數據顯示到UI控件,注意只能在主線程中更新UI,
另外performSelectorOnMainThread方法是NSObject的分類方法,每個NSObject對象都有此方法,
它調用的selector方法是當前調用控件的方法,例如使用UIImageView調用的時候selector就是UIImageView的方法
Object:代表調用方法的參數,不過只能傳遞一個參數(如果有多個參數請使用對象進行封裝)
waitUntilDone:是否線程任務完成執行
*/
[self performSelectorOnMainThread:@selector(updateImage:) withObject:data waitUntilDone:YES];
}
NSThread->1.0創建線程
第一種:通過NSThread的對象方法(alloc / init - start)
//線程一啟動,就會在線程thread中執行self的run方法
NSThread*thread = [[NSThreadalloc]initWithTarget:<#(nonnull id)#>
selector:<#(nonnull SEL)#>
object:<#(nullable id)#> ];
//開啟線程,通過start方法,就會將我們創建出來的當前線程加入到`可調度線程池`,供CPU調度
//[thread start];執行后,會在另外一個線程執行longOperation:方法
[thread start];
第二種:通過NSThread的類方法(detachNewThreadSelector)
// detachNewThreadSelector類方法不需要啟動,會自動創建線程并執行@selector方法
//它會自動給我們做兩件事:? 1.創建線程對象2.添加到`可調度線程池`
//通過NSThread的類和NSObject的分類方法直接加入到可調度線程池里面去,等待CPU調度
[NSThreaddetachNewThreadSelector:<#(nonnullSEL)#>
toTarget:<#(nonnullid)#>
withObject:<#(nullableid)#> ];
第三種:通過NSObject的方法
//此方法在后臺線程中執行(即是:在子線程中執行)
// performSelectorInBackground是NSObject的分類方法,會自動在后臺線程執行@selector方法
//沒有thread字眼,隱式創建并啟動線程
//所有NSObject都可以使用此方法,在其他線程執行方法
//通過NSThread的類和NSObject的分類方法直接加入到可調度線程池里面去,等待CPU調度
// PerformSelectorInBackground可以讓方便地在后臺線程執行任意NSObject對象的方法
[selfperformSelectorInBackground:<#(nonnull SEL) #>
withObject:<#(nullable id) #> per];
方式2和方式3的優缺點 :
優點:簡單快捷
缺點:無法對線程進行更詳細的設置
NSThread->2.0線程屬性
線程相關方法:
+ (NSThread*)mainThread;//獲得主線程
- (BOOL)isMainThread;//是否為主線程
+ (BOOL)isMainThread;//是否為主線程
NSThread*main = [NSThreadmainThread];// + (NSThread *)mainThread;獲得主線程
[NSThreadisMainThread];//? + (BOOL)isMainThread;類方法判斷,該方法是否為主線程
[main isMainThread];//? - (BOOL)isMainThread;對象方法判斷,該對象是否為主線程
NSThread*current = [NSThreadcurrentThread];//獲得當前線程
//返回當前方法所在線程的優先級
+ (double)threadPriority;
舉例:[NSThreadthreadPriority];
//設置線程的優先級
+ (BOOL)setThreadPriority:(double)p;
舉例:self.thread1.threadPriority=1.0;
- (double)threadPriority;//返回當前方法所在線程的優先級
- (BOOL)setThreadPriority:(double)p;//設置線程的優先級
- (void)setName:(NSString*)n;//set方法
- (NSString*)name;//get方法
舉例:
thread.name=@"線程A";
NSThread->5.0線程間通訊和常用方法
線程間通信常用方法:
//在主線程執行操作(從子線程回到主線程)(推薦)
- (void)performSelectorOnMainThread:(SEL)aSelector
withObject:(id)arg
waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector
onThread:(NSThread*)thr
withObject:(id)arg
waitUntilDone:(BOOL)wait;
GCD->1.0 GCD簡介和使用
GCD 的優勢:
GCD是蘋果公司為多核的并行運算提出的解決方案
GCD會自動利用更多的CPU內核(比如雙核、四核)
GCD會自動管理線程的生命周期(創建線程、調度任務、銷毀線程)
程序員只需要告訴GCD想要執行什么任務,不需要編寫任何線程管理代碼
任務的執行:同步
//queue:隊列block:任務
dispatch_sync(dispatch_queue_tqueue,dispatch_block_tblock);
任務的執行:異步
//queue:隊列block:任務
dispatch_async(dispatch_queue_tqueue,dispatch_block_tblock);
//在前面的任務執行結束后它才執行,而且它后面的任務等它執行完成之后才會執行
dispatch_barrier_async(dispatch_queue_tqueue,dispatch_block_tblock);
【區別】同步 & 異步:同步和異步決定了要不要開啟新的線程
-同步:只能在當前線程中執行任務,不具備開啟新線程的能力
-異步:可以在新的線程中執行任務,具備開啟新線程的能力
【區別】并發 & 串行:并發和串行決定了任務的執行方式
-并發:允許多個任務并發(同時)執行
-串行:一個任務執行完畢后,再執行下一個任務
GCD的使用 - 隊列
并發隊列
-可以讓多個任務并發(同時)執行(自動開啟多個線程同時執行任務)
-并發功能只有在異步(dispatch_async)函數下才有效
串行隊列
-讓任務一個接著一個地執行(一個任務執行完畢后,再執行下一個任務)
release
-凡是函數名種帶有create\copy\new\retain等字眼,都應該在不需要使用這個數據的時候進行release
- GCD的數據類型在ARC環境下不需要再做release
dispatch_release(queue);//非ARC需要釋放手動創建的隊列
- CF(Core Foundation)的數據類型在ARC環境下還是需要再做release
創建隊列 - 并發隊列
方式1 - 手動創建并發隊列
dispatch_queue_create(
constchar *label,//隊列名稱
dispatch_queue_attr_tattr//隊列的類型
);
// 1.創建并發隊列DISPATCH_QUEUE_CONCURRENT (并發)
dispatch_queue_t queue = dispatch_queue_create(“TD", DISPATCH_QUEUE_CONCURRENT);
// 2.非ARC需要釋放手動創建的隊列
dispatch_release(queue);
方式2 - 獲取全局并發隊列:(GCD默認已經提供了全局的并發隊列,供整個應用使用,可以無需手動創建
#define DISPATCH_QUEUE_PRIORITY_HIGH2//高
#define DISPATCH_QUEUE_PRIORITY_DEFAULT0//默認(中)
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)//低
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN//后臺
dispatch_get_global_queue(
longidentifier,//隊列的優先級
unsignedlong flags//此參數暫時無用,用0即可
);
//獲取全局并發隊列
dispatch_queue_tqueue= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
#pragma mark -同步函數+并發隊列:不會開啟新的線程,在當前線程執行任務(主線程),順序執行,并發隊列失去了并發的功能
- (void)syncConcurrent {
NSLog(@"同步并發----- begin");
// 1.獲得全局的并發隊列
dispatch_queue_tqueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
// 2.將任務加入隊列
dispatch_sync(queue, ^{
NSLog(@"1-----%@", [NSThreadcurrentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2-----%@", [NSThreadcurrentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3-----%@", [NSThreadcurrentThread]);
});
NSLog(@"同步并發----- end");
}
#pragma mark -寫法2
- (void)concurrentSync {
// 1.創建并發隊列
dispatch_queue_tconCurrentQueue =
dispatch_queue_create("TD", DISPATCH_QUEUE_CONCURRENT);
// 2.創建任務
void(^task1)() = ^() {
NSLog(@"---task1---%@", [NSThreadcurrentThread]);
};
void(^task2)() = ^() {
NSLog(@"---task2---%@", [NSThreadcurrentThread]);
};
void(^task3)() = ^() {
NSLog(@"---task3---%@", [NSThreadcurrentThread]);
};
// 3.將同步任務添加到并發隊列中
dispatch_sync(conCurrentQueue, task1);
dispatch_sync(conCurrentQueue, task2);
dispatch_sync(conCurrentQueue, task3);
}
#pragma mark -異步函數+并發隊列:可以同時開啟多條線程,在當前線程執行任務(主線程),無序執行(按照任務添加到隊列中的順序被調度),線程條數具體由`可調度線程池/底層線程池`來決定
- (void)asyncConcurrent {
NSLog(@"異步并發----- begin");
// 1.獲得全局的并發隊列
dispatch_queue_tqueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
// 2.將任務加入隊列
dispatch_sync(queue, ^{
NSLog(@"1-----%@", [NSThreadcurrentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2-----%@", [NSThreadcurrentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3-----%@", [NSThreadcurrentThread]);
});
NSLog(@"異步并發----- begin");
}
#pragma mark -寫法2
- (void)concurrentAsync {
// 1.創建并發隊列
dispatch_queue_tconCurrentQueue =
dispatch_queue_create("TD", DISPATCH_QUEUE_CONCURRENT);
// 2.創建任務
void(^task1)() = ^() {
NSLog(@"---task1---%@", [NSThreadcurrentThread]);
};
void(^task2)() = ^() {
NSLog(@"---task2---%@", [NSThreadcurrentThread]);
};
void(^task3)() = ^() {
NSLog(@"---task3---%@", [NSThreadcurrentThread]);
};
// 3.將異步任務添加到并發隊列中
dispatch_async(conCurrentQueue, task1);
dispatch_async(conCurrentQueue, task2);
dispatch_async(conCurrentQueue, task3);
}
創建隊列-隊列
//1.創建串行隊列
//方式1:DISPATCH_QUEUE_SERIAL (串行)
dispatch_queue_t queue = dispatch_queue_create(“TD", DISPATCH_QUEUE_SERIAL);
//方式2:傳NULL
dispatch_queue_t queue = dispatch_queue_create(“TD",NULL);
// 2.非ARC需要釋放手動創建的隊列
dispatch_release(queue);
串行隊列,異步任務,在多線程中,是斯坦福大學最推薦的一種多線程方式
優點:將任務放在其他線程中工作,每個任務順序執行,便于調試
缺點:并發能力不強,最多只能使用一條線程!
同步函數 + 并發隊列:不會開啟新的線程,在當前線程執行任務(主線程),順序執行,并發隊列失去了并發的功能
#異步函數 + 并發隊列:可以同時開啟多條線程,在當前線程執行任務(主線程),無序執行(按照任務添加到隊列中的順序被調度),線程條數具體由可調度線程池/底層線程池來決定
(1)如果異步任務前面有同步任務:就會先執行同步任務同步任務是按順序執行的任務等他執行完了才會執行并行中的異步任務(可以做到阻塞 控制任務的執行順序)
(2)如果異步任務后面有同步任務:兩個任務會并行(同時)執行
同步函數 + 串行隊列:不會開啟新的線程,在當前線程執行任務(主線程),任務是串行的(順序執行)
異步函數 + 串行隊列:會開啟新的線程,在子線程執行任務,任務是串行的(順序執行),只開一條線程
串行隊列中的任務都是按順序執行:
異步函數 + 主隊列:不會開啟新的線程,在當前線程執行任務(主線程),任務是串行的(順序執行),只開一條線程(適合處理 UI 或者是 UI事件)
同步函數 + 主隊列:不會開啟新的線程,會出現"死等",可能導致主線程卡死
【區別】同步 & 異步:同步和異步決定了要不要開啟新的線程
-同步:只能在當前線程中執行任務,不具備開啟新線程的能力
-異步:可以在新的線程中執行任務,具備開啟新線程的能力
【區別】并發 & 串行:并發和串行決定了任務的執行方式
-并發:允許多個任務并發(同時)執行
-串行:一個任務執行完畢后,再執行下一個任務
同步函數:無論是什么隊列都不會開啟線程
(1)并發隊列:不會開線程
(2)串行隊列:不會開線程
異步函數:具備開啟線程的能力(但不一定會開線程 ),開啟幾條線程由隊列決定
(1)并發隊列:能開啟N條線程
(2)串行隊列:開啟1條線程
Touch ID定制Demo
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
NSString *myLocalizedReasonString = <#String explaining why app needs authentication#>;
if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:myLocalizedReasonString
reply:^(BOOL success, NSError *error) {
if (success) {
// User authenticated successfully, take appropriate action
dispatch_async(dispatch_get_main_queue(), ^{
// write all your code here
});
} else {
// User did not authenticate successfully, look at error and take appropriate action
switch (error.code) {
case LAErrorAuthenticationFailed:
NSLog(@"Authentication Failed");
break;
case LAErrorUserCancel:
NSLog(@"User pressed Cancel button");
break;
case LAErrorUserFallback:
NSLog(@"User pressed \"Enter Password\"");
break;
default:
NSLog(@"Touch ID is not configured");
break;
}
NSLog(@"Authentication Fails");
}
}];
} else {
// Could not evaluate policy; look at authError and present an appropriate message to user
}
iOS ---沙盒
Documents目錄
保存應用程序運行時生成的需要持久化的數據,Itunes會自動備份該目錄
Library目錄
存儲程序的默認設置和其他狀態信息,Itunes會自動備份該目錄
tmp目錄
保存應用運行時所需要的臨時數據,使用完畢后在將相應的文件從該目錄刪除。
獲取沙盒路徑
NSString *path = NSHomeDirectory();
獲取沙盒下文件目錄的路徑
有三種獲取方法:
1.拼接字符串:
NSString *Documents = [path stringByAppendingString:@"/Documents"];
2.拼接路徑
NSString *Documents2 = [path stringByAppendingPathComponent:@"Documents"];
3.系統提供的獲取沙盒下目錄路徑的方法
NSString *Documents3 = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, NO) firstObject];
//NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, NO) 方法返回值為只有一個元素的數組,所以去第一個元素
對于其他兩個文件路徑的獲取方式都一樣,系統提供的方法有些區別
NSString *library3 = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) firstObject];
//對于Library文件獲取路徑方法,只是參數有些不一樣
//獲取library下的caches
NSString *cachesStr = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
獲取tmp文件夾路徑(系統提供的方法)
NSString *tmpStr = NSTemporaryDirectory();
獲取程序包路徑
NSString *appPath = [NSBundle mainBundle].resourcePath;
獲取程序包內種的一個圖片資源(apple.png)路徑
NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"apple" ofType:@"png"];
簡單對象的讀寫(I/O)操作
簡單對象:字符串,數組,字典,data
字符串存儲
//獲取存儲的目錄
NSString *str = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
//在沙盒文件夾下的Documents內創建.txt文件
NSString *newPath = [str stringByAppendingPathComponent:@"text.txt"];
//存入內容
NSString *name = @"藍歐科技, nihao";
[name writeToFile:newPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
字符串讀取
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *newPath = [path stringByAppendingString:@"/text.txt"];
NSString *string = [NSString stringWithContentsOfFile:newPath encoding:NSUTF8StringEncoding error:nil];
NSLog(@"%@", string);
數組存儲
[nameArr writeToFile:newPath atomically:YES];
數組讀取
NSArray *array = [NSArray arrayWithContentsOfFile:newPath];
字典存儲
[dict writeToFile:newPath atomically:YES];
字典讀取
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:newPath];
NSData類型存儲
NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
//寫入文件
[data writeToFile:dataPath atomically:YES];
NSData讀取
//獲取路徑
NSData *data = [NSData dataWithContentsOfFile:dataPath];
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
圖片存儲//將圖片轉成NSData類型在存儲
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
//在沙盒問價下面創建一個文件
NSString *newPath = [path stringByAppendingPathComponent:@"image.png"];
//需要存儲的圖片
NSData *imageData = UIImageJPEGRepresentation([UIImage imageNamed:@"tu.jpg"], 1.0);
//創建文件并存儲
[imageData writeToFile:newPath atomically:YES];
圖片讀取
//獲取沙盒地址
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
//獲取圖片data地址
NSString *newPath = [path stringByAppendingPathComponent:@"image.png"];
//獲取data
NSData *data = [NSData dataWithContentsOfFile:newPath];
//獲取圖片
UIImage *image = [UIImage imageWithData:data];
//添加imageView
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(100, 200, 150, 150)];
imageView.image = image;
[self.view addSubview:imageView];
通過文件管理器來操作對象
創建對象
NSString *string = @"hello nihao";
//根據字符串創建data
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
創建文件管理器
NSFileManager *fileManager = [[NSFileManager alloc] init];
存儲對象//向目標文件寫入信息
BOOL save = [fileManager createFileAtPath:[[self documentPath] stringByAppendingPathComponent:@"studenttt.plist"] contents:data attributes:nil];
//注:[self documentPath]是獲取Documents路徑
//獲取Documents路徑
- (NSString *)documentPath {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
}
讀取對象
NSData *mData = [fileManager contentsAtPath:[[self documentPath] stringByAppendingPathComponent:@"studenttt.plist"]];
NSString *mStr = [[NSString alloc] initWithData:mData encoding:NSUTF8StringEncoding];
復雜對象的讀寫---歸檔和反歸檔
1.首先,復雜對象所屬的類要遵循協議
//Person.h
@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *gender;
@property (nonatomic, assign) NSInteger age;
@end
2.其次,實現協議中的兩個方法
-(void)encodeWithCoder:(NSCoder *)aCoder;
-(instancetype)initWithCoder:(NSCoder *)aDecoder
//Person.m
@implementation Person
//當對象進行歸檔操作的時候,會自動調用這個方法
- (void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeObject:self.gender forKey:@"gender"];
[aCoder encodeInteger:self.age forKey:@"age"];
}
//當對象進行反歸檔的時候會調用
- (instancetype)initWithCoder:(NSCoder *)aDecoder{
if (self = [super init]) {
self.name = [aDecoder decodeObjectForKey:@"name"];
self.age = [aDecoder decodeIntegerForKey:@"age"];
self.gender = [aDecoder decodeObjectForKey:@"gender"];
}
return self;
}
@end
歸檔 ——NSKeyedArchiver
Person *person = [[Person alloc] init];
person.name = @"小明";
person.age = 23;
person.gender = @"男";
//進行歸檔操作
//1.創建一個NSmutableData,用來存儲歸檔后的數據
NSMutableData *mData = [[NSMutableData alloc] init];
//2.創建歸檔器
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:mData];
//進行歸檔
[archiver encodeObject:person forKey:@"person"];
//歸檔結束
[archiver finishEncoding];
//存到沙盒的文件夾中
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *newPath = [path stringByAppendingPathComponent:@"guidang.plist"];
//存儲data
[mData writeToFile:newPath atomically:YES];
反歸檔 ——NSKeyedUnarchiver
//獲取路徑
NSString * newPath = [[self documentPath] stringByAppendingPathComponent:@"guidang.plist"];
//取出數據
NSData *data = [NSData dataWithContentsOfFile:newPath];
//創建反歸檔器
NSKeyedUnarchiver *unArchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
Person *person = [unArchiver decodeObjectForKey:@"person"];
//反歸檔結束
[unArchiver finishDecoding];
NSLog(@"name : %@ age : %ld gender : %@", person.name, person.age, person.gender);
iOS語言本地化/國際化
應用名稱本地化/國際化
InfoPlist.strings
CFBundleDisplayName = "國際化App名稱";
代碼中字符串的本地化
Localizable.stirings
// NSLocalizedString(key, comment) 本質
// NSlocalizeString 第一個參數是內容,根據第一個參數去對應語言的文件中取對應的字符串,第二個參數將會轉化為字符串文件里的注釋,可以傳nil,也可以傳空字符串@""。
#define NSLocalizedString(key, comment) [[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:nil]
Targets:
Build Settings
Search Paths
Header Search Paths
NSNotification
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(notifyUrlScheme:) name:kNotifyUrlScheme object:nil];
NSNotification *notice = [NSNotification notificationWithName:kNotifyUrlScheme ?object:self userInfo:dic];
[[NSNotificationCenter defaultCenter] postNotification:notice];
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center removeObserver:self name:kNotifyUrlScheme object:nil];
Notification
Local Notification
remote notifications
- (void)application:(UIApplication *)application?didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userinfo {
}
atomic和nonatomic用來決定編譯器生成的getter和setter是否為原子操作。
assign
對基礎數據類型 (NSInteger,CGFloat)和C數據類型(int, float, double, char)等等。
此標記說明設置器直接進行賦值,這也是默認值。
retain
對其他NSObject和其子類對參數進行release舊值,再retain新值
copy
對NSString 它指出,在賦值時使用傳入值的一份拷貝。
也就是說,retain 是指針拷貝,copy 是內容拷貝
weak 和 strong 屬性只有在你打開ARC時才會被要求使用,這時你是不能使用retain release autorelease 操作的,因為ARC會自動為你做好這些操作,但是你需要在對象屬性上使用weak 和strong,其中strong就相當于retain屬性,而weak相當于assign。
ARC的重點:
它是Compile-time的技術,并不是在runtime用thread去處理
開發者不能再直接使用retain,release,autorelease,改由compiler幫你寫這些代碼。
所有的property不再使用retain,assign而改用strong,weak取代。
NSAutoreleasePool也要改用特有的@autoreleasepool{}來取代
ARC的工作原理:
在你編譯程序時,將內存操作的代碼(retain,release或autorelease)自動添加到需要的位置。即底層上使用和Manual Reference Counting(手工引用計數)一樣的內存管理機制,但由于是自動幫你在編譯時添加內存操作的代碼,從而簡化了編程的工作。
第31條 在dealloc方法中只釋放引用并解除監聽
要點
? 在dealloc方法里,應該做的事情就是釋放指向其他對象的引用,并取消原來訂閱的“鍵值觀測”(KVO)或NSNotificationCenter等通知,不要做其他事情。
? 如果對象持有文件描述符等系統資源,那么應該專門寫一個方法來釋放此種資源。這樣的類要和其使用者約定:用完資源后必須調用close方法。
? 執行異步任務的方法不應該在dealloc里調用;只能在正常狀態下執行的那些方法也不應在dealloc里調用,因為此時對象已處于正在回收的狀態了。
第36條 不要使用retainCount
要點
? 對象的保留計數看似有用,實則不然,因為任何給定時間點上的“絕對保留計數”(absolute retain count對象生命期的全貌。
引入ARC之后,retainCount方法就正式廢止了,在ARC‰o調用該方法會導致編譯器報錯。
Other Framework
1.ZXingObjC---二次元コード
- (IBAction)updatePressed:(id)sender {
[self.textView resignFirstResponder];
NSString *data = self.textView.text;
if (data == 0) return;
ZXMultiFormatWriter *writer = [[ZXMultiFormatWriter alloc] init];
ZXBitMatrix *result = [writer encode:data
format:kBarcodeFormatQRCode
width:self.imageView.frame.size.width
height:self.imageView.frame.size.width
error:nil];
if (result) {
ZXImage *image = [ZXImage imageWithMatrix:result];
self.imageView.image = [UIImage imageWithCGImage:image.cgimage];
} else {
self.imageView.image = nil;
}
}
Object-C
使用synchronized方法實現:
staticidobj = nil;
+(instancetype)shareInstance
{
@synchronized(self) {
if(!obj) {
obj = [[SingletonObj alloc] init];
}
}
returnobj;
}
使用dispatch_once方法實現:
static id obj = nil;
+(instancetype)shareInstance
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
obj = [[SingletonObj alloc] init];
});
return obj;
}
數據類型
ObjC支持的數據類型包括:基本類型、構造類型和指針類型。其中,基本類型包括:整型、字符型、浮點型和枚舉型;構造類型包括:數組類型、結構體類型和共用體類型;而指針類型是ObjC中最重要的類型。
整型
short int,int,long int,long long,unsigned
int 與 NSInteger, bool 與 BOOL, float 與 CGFloat
NSValue
另外NSNumber支持和NSString一樣的@符號簡寫
NSArray
字符型
char,
NSString
http://blogios.stack3.net/archives/309
検索
NSString#rangeOfStringメソッドを使います。戻り値はNSRange構造體です。
NSRange#location 見つかった位置のインデックス。見つからなかった時はNSNotFound
NSRange#length 見つかった文字列の長さ
NSRange range;
range = [@"string" rangeOfString:@"ring"];
// --> range.location = 2; range.length = 4;
range = [@"string" rangeOfString:@"abc"];
// --> range.location = NSNotFound; range.length = 0;
大文字小文字區別なし。
range = [@"string" rangeOfString:@"NG" options:NSCaseInsensitiveSearch];
// --> range.location = 4; range.length = 2;
後ろから検索。
range = [@"abcabcabc" rangeOfString:@"abc" options:NSBackwardsSearch];
// --> range.location = 6; range.length = 3;
複數のオプションをORで指定することもできます。以下は、大文字小文字區別なし、かつ、後ろから検索。
range = [@"abcabcabc" rangeOfString:@"ABC" options:NSCaseInsensitiveSearch|NSBackwardsSearch];
// --> range.location = 6; range.length = 3;
optionsに0を指定すると條件指定なし。単なるrangeOfStringと同じです。
range = [@"abcabcabc" rangeOfString:@"ABC" options:0];
// --> range.location = NSNotFound; range.length = 0;
正規表現による検索。
range = [@"? abc" rangeOfString:@"\w+" options:NSRegularExpressionSearch];
// --> range.location = 2; range.length = 3;
範囲を指定して検索。
range = [@"abcabc" rangeOfString:@"abc" options:0 range:NSMakeRange(3, 3)];
// --> range.location = 3; range.length = 3;
range = [@"abcabc" rangeOfString:@"ABC" options:NSCaseInsensitiveSearch range:NSMakeRange(3, 3)];
// --> range.location = 3; range.length = 3;
置換
置換はメソッド名が長いです???
string = [@"string" stringByReplacingOccurrencesOfString:@"ring" withString:@"and"];
// --> @"stand"
また、見つかった文字は全部置換されることに注意が必要です。
string = [@"stringring" stringByReplacingOccurrencesOfString:@"ring" withString:@"and"];
// --> @"standand"
最初に見つかった文字だけ置換したい場合。
string = @"stringring";
NSRange range = [string rangeOfString:@"ring"];
if (range.location != NSNotFound) {
string = [string stringByReplacingCharactersInRange:range withString:@"and"];
// --> @"standring"
}
文字列の連結
NSString *string = @"abc";
string = [string stringByAppendingString:@"def"];
// string --> @"abcdef"
もちろん変數に代入にしなくても直接呼び出せます。
string = [@"abc" stringByAppendingString:@"def"];
STAssertEqualObjects(string, @"abcdef", nil);
NSMutableStringを使う場合
NSMutableString *mutableString = [NSMutableString stringWithString:@"abc"];
// こういう書き方もできる
// mutableString = [@"abc" mutableCopy];
[mutableString appendString:@"def"];
// string --> @"abcdef"
數値などを文字列に埋めたい時は、フォーマットを使う。
string = @"abc";
string = [string stringByAppendingFormat:@"%d", 100];
// string --> @"abc100"
mutableString = [NSMutableString stringWithString:@"abc"];
[mutableString appendFormat:@"%d", 100];
// string --> @"abc100"
あまり使わないと思いますが、こういうのもあります。
string = @"abc";
string = [string stringByPaddingToLength:6 withString:@"x" startingAtIndex:0];
// string --> @"abcxxx"
文字列は第1引數Lengthの長さになります。
文字列がLengthより短い場合は末尾を第2引數のStringで埋めます。
文字列が第2引數の文字列のどの位置から連結するかを第3引數で決定します。
第3引數がわかりづらいとおもうのですが、たとえばこういうことです。
string = @"abc";
string = [string stringByPaddingToLength:9 withString:@"efg" startingAtIndex:2];
// string -> @"abcgefgef"
文字列の長さを9文字にして、@”efg”のindex:2つまり@”g”から連結をはじめ、次は@”ef”と連結するのを繰りかえすことになります。
文字列の分解
カンマ區切りの文字列を分解。
NSString *string = @"Apple,Orange,Grape";
NSArray *array = [string componentsSeparatedByString:@","];
// array --> @[@"Apple", @"Orange", @"Grape"];
カンマ+スペース區切りの文字列を分解
string = @"Apple, Orange, Grape";
array = [string componentsSeparatedByString:@", "];
// array --> @[@"Apple", @"Orange", @"Grape"]
空白(半角スペース、全角スペース)で區切られているものを分解。こういう場面ではNSCharacterSetを使うと良い。
string = @"Apple Orange Grape";
array = [string componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
// array --> @[@"Apple", @"Orange", @"Grape"]
指定インデックスから切り取る。
string = [@"abcdef" substringFromIndex:3];
// string --> @"def"
指定インデックスより前までを切り取る。指定インデックスは含まない。
string = [@"abcdef" substringToIndex:3];
// string --> @"abc"
指定範囲を切り取る。
string = [@"abcdef" substringWithRange:NSMakeRange(2, 2)];
// string --> @"cd"
NSMutableString好比一個字符串鏈表,
- \- (void)appendString:(NSString *)aString;
+ 拼接aString到最后面
- \- (void)appendFormat:(NSString *)format, ...;
+ 拼接一段格式化字符串到最后面
- (void)deleteCharactersInRange:(NSRange)range;
刪除range范圍內的字符串
- (void)insertString:(NSString *)aString atIndex:(NSUInteger)loc;
在loc這個位置中插入aString
NSUserDefault用法
方法很簡單,一行代碼就可以搞定
//保存
- (void)saveValue:(NSString *)value forKey:(NSString *)key
{
[[NSUserDefaults standardUserDefaults] setObject:value forKey:key];
}
//讀取
- (void)readValueforKey:(NSString *)key
{
[[NSUserDefaults standardUserDefaults] objectForKey:key];
}
[[NSUserDefaults standardUserDefaults] setValue:version forKey:@"newfeatures"];
[[NSUserDefaults standardUserDefaults] synchronize];
NSString *newUserAgent = [NSString stringWithFormat:@"KuronekoyamatoOfficialApp/%@ %@", aplversion, userAgent];
NSDictionary *dic = [[NSDictionary alloc] initWithObjectsAndKeys:newUserAgent, @"UserAgent", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:dic];
(lldb) po dic
{
UserAgent = "KuronekoyamatoOfficialApp/2.26.0 Mozilla/5.0 (iPhone; CPU iPhone OS 9_3 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Mobile/13E230”;
}
注意
NSUserDefault只能保存特定類型的對象:NSData, NSString, NSNumber, NSDate, NSArray, NSDictionary。如果想要存儲其它類型,需要將打包成NSData類型。
當應用第一次設置某項用戶偏好設置的值時,相應的值會通過指定的鍵加入應用域。當通過NSUserDefaults獲取某項用戶偏好設置的值時,NSUserDefaults會先在應用域中查找,如果找到了值,NSUserDefaults就會返回這個值。如果沒有找到,NSUserDefaults就會在注冊域中查找并返回默認值。
NSUserDefaults從上到下透過域的層級尋找正確的值,不同的域有不同的功能,有些域是可持久的,有些域則不行。
應用域(application domain)是最重要的域,它存儲著你app通過NSUserDefaults set...forKey添加的設置。
注冊域(registration domain)僅有較低的優先權,只有在應用域沒有找到值時才從注冊域去尋找。
全局域(global domain)則存儲著系統的設置
語言域(language-specific domains)則包括地區、日期等
參數域( argument domain)有最高優先權
Protocol協議
@protocol?ProtocolDelegate?//?必須實現的方法
@required
-?(void)error;
//?可選實現的方法
@optional
-?(void)other;
-?(void)other2;
-?(void)other3;
@end
#import
@interface ASStudent : NSObject
{
NSString* name;//ios當中 對象都是在堆上分配的,所以都是指針
@public
unsigned int age;
@private
NSString* sid;//
}
+(void)print; // + 代表方法為 類方法; void為返回值類型, print為簽名
-(void)setName:(NSString*)aName;// - 代表方法為 實例方法; void為返回值類型,setName: 為 簽名 :也屬于簽名部分; NSString* 為形參類型, aName為形參
-(NSString*)name;
//-(void)name;//error 實例方法簽名不能相同 這個和上面都是 name
-(void)name:(int)aname;// 簽名部分為 name: 包含冒號部分所以不算相同
+(void)name; //true 類方法和 實例方法簽名可以相同方法簽名不能一樣,不支持重載
//在同一個類內方法不能重載,即方法的簽名不能完全一樣;但是類方法和實例方法簽名可以相同
//方法的簽名 和 參數類型、參數名稱無關
//方法簽名和方法的返回值類型無關;
@end
實現:
#import "ASStudent.h"
@implementation ASStudent
-(NSString*)name{
return name;
}
-(void)setName:(NSString *)aName{
name = aName;
}
+(void)print{
NSLog(@"類方法");
}
//實例方法可以直接引用類的實例變量和其他實例方法
//類的方法都是public的,沒有protected 和 private方法 ,但是如果一個方法 只是出現在類的方法里面,沒有出現在類的聲明里,name這個方法可以認為是私有的!
@end
.h文件中@interface指令用來標識文件的接口代碼的起始位置,而@end指令標示該段的結束位置。在.m文件中,@implementation指令用來標識實現的起始位置,@end標識結束位置
@interface用于定義類的公共接口,通常,接口被稱為API(application programming interface)而真正使對象能夠運行的代碼,位于@implementation中。
當我們要給一個Car類聲明一個發動機屬性的時候,如果對外公開,則代碼為
文/xuyafei86(簡書作者)
原文鏈接:http://www.lxweimin.com/p/4f7dda4a5192
著作權歸作者所有,轉載請聯系作者獲得授權,并標注“簡書作者”。如果不對外公開,則在.m里的代碼為
關于Objective-C Runtime看我就夠了
http://www.lxweimin.com/p/f73ea068efd2
目通常采用工程文件設計結構的例子
1.主目錄結構
-ProjectDemo
--Features//模塊。包含各個模塊的Model,View,Controller,Manager
--categories//類目。包含各種類的分類
--Frameworks//系統框架。包含導入的系統的框架
--Helpers//幫助類。包含網絡,數據庫,歸檔,定位等操作類的封裝和實現
--Utilites//工具類,一些非對象的,而是類方法調用的類
--Vendors//第三方庫。部分需要修改或者不支持cocoapod的第三方的框架引入
--Config//配置。包含宏定義文件,全局配置文件,全局常量文件,顏色配置文件
--Resources//資源。包含plist,image,html,bundle,Localizable.strings等
--AppEntry//程序入口。包含AppDelegate,main.c,info.plist
-PAHealthTests
-PAHealthUITests
-Products// 系統自動生成的.app所在文件夾
-Pods// 采用 CocoaPods 管理的第三方庫。
2.模塊目錄結構
-- Features
---Base//MVC的基類或者通用類
----Models//數據模型
----Views//視圖
----Controllers//控制器
----Manager//store層的數據管理類
---Home
----Models
----Views
----Controllers
----Manager
---UserCenter
----Models
----Views
----Controllers
----Manager
---UserEntry
----Models
----Views
----Controllers
----Manager
---Payment
----Models
----Views
----Controllers
----Manager
…