RAC中類的繼承關(guān)系
1.RACDynamicSignal:RACSignal:RACStream
2.RACSequence:RACStream
3.RACCompoundDisposable : RACDisposable
4.RACSubscriptionScheduler : RACScheduler
5.RACQueueScheduler : RACScheduler
RAC優(yōu)勢(shì)(提高開(kāi)發(fā)效率)
1.把target-Action/代理/通知/KVO統(tǒng)一封裝成信號(hào),即信號(hào)就可以實(shí)現(xiàn)這些功能。
2.監(jiān)聽(tīng)屬性的代碼少
3.代碼直觀,代碼復(fù)雜度減小m3u8
4.通過(guò)block降低代碼間的耦合
訂閱和訂閱者
- subscribeNext:訂閱
subscribeNext:^(id x) { } - subscriber:訂閱者,例如訂閱者調(diào)用sendNext方法谒出。
[subscriber sendNext:responseObject];
25個(gè)事例+1個(gè)小項(xiàng)目幫助你解開(kāi)RAC的面紗
1.監(jiān)聽(tīng)UITextField內(nèi)容的輸入信號(hào)
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UITextField *usernameField;
@end
@implementation ViewController
// rac給每一個(gè)UI控件都增加了分類颤芬,在分類里面給UI控件擴(kuò)充了新的方法卫枝。利用rac編程時(shí)用到的就是這個(gè)方法
- (void)viewDidLoad {
[super viewDidLoad];
[self Username];// 監(jiān)聽(tīng)UITextField內(nèi)容的輸入信號(hào)
}
-(void)Username{
/* 1+2可以寫(xiě)成一行代碼
[self.usernameField.rac_textSignal subscribeNext:^(id x) {/
NSLog(@"%@",x);
}];
*/
// 文本信號(hào):監(jiān)聽(tīng)UITextField內(nèi)容的輸入
RACSignal *textSignal = self.usernameField.rac_textSignal;// 1
// 訂閱者block
[textSignal subscribeNext:^(id x) {// 2
NSLog(@"%@",x);
}];
}
@end
截圖
2.監(jiān)聽(tīng)按鈕的點(diǎn)擊信號(hào)(信號(hào)理解為事件)
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIButton *login;
@end
@implementation ViewController
// rac給每一個(gè)UI控件都增加了分類鱼辙,在分類里面給UI控件擴(kuò)充了新的方法。利用rac編程時(shí)用到的就是這個(gè)方法
- (void)viewDidLoad {
[super viewDidLoad];
[self Login];// 監(jiān)聽(tīng)按鈕的點(diǎn)擊信號(hào)(信號(hào)理解為事件)
}
-(void)Login{
/* 1+2可以寫(xiě)成一行代碼
[[self.login rac_signalForControlEvents:UIControlEventTouchUpInside]subscribeNext:
^(id x) {
NSLog(@"%@",x);
}];
*/
RACSignal *clickSignal = [self.login rac_signalForControlEvents:UIControlEventTouchUpInside];// 1
// 訂閱者block
[clickSignal subscribeNext:^(id x) { // 2
NSLog(@"%@",x);
}];
}
@end
截圖
3.取消按鈕的點(diǎn)擊信號(hào)
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIButton *login;
@property(nonatomic,strong)RACDisposable *btnDisposable;
@end
@implementation ViewController
// rac給每一個(gè)UI控件都增加了分類药磺,在分類里面給UI控件擴(kuò)充了新的方法。利用rac編程時(shí)用到的就是這個(gè)方法
- (void)viewDidLoad {
[super viewDidLoad];
[self Dispose];// 取消按鈕的點(diǎn)擊信號(hào)煤伟。先點(diǎn)擊屏幕癌佩,然后再點(diǎn)擊按鈕,發(fā)現(xiàn)沒(méi)有打印便锨。因?yàn)辄c(diǎn)擊信號(hào)已經(jīng)取消了围辙,點(diǎn)擊多少次都不會(huì)打印。
}
-(void)Dispose{
self.btnDisposable = [[self.login rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self.btnDisposable dispose];
}
@end
截圖
4.信號(hào)的map方法
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UITextField *usernameField;
@end
@implementation ViewController
// rac給每一個(gè)UI控件都增加了分類放案,在分類里面給UI控件擴(kuò)充了新的方法姚建。利用rac編程時(shí)用到的就是這個(gè)方法
- (void)viewDidLoad {
[super viewDidLoad];
[self Map];// 信號(hào)的map方法
}
-(void)Map{
// 文本信號(hào):監(jiān)聽(tīng)UITextField內(nèi)容的輸入
RACSignal *textSignal = self.usernameField.rac_textSignal;
// 調(diào)用map方法:更改訂閱者block輸出的參數(shù)的類型
textSignal = [textSignal map:^id(id value){
return [NSString stringWithFormat:@"username = %@",value];
}];
// 訂閱者block
[textSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
}
@end
截圖
5.信號(hào)的filter方法
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UITextField *usernameField;
@end
@implementation ViewController
// rac給每一個(gè)UI控件都增加了分類,在分類里面給UI控件擴(kuò)充了新的方法吱殉。利用rac編程時(shí)用到的就是這個(gè)方法
- (void)viewDidLoad {
[super viewDidLoad];
[self filterText];// 信號(hào)的filter方法
}
-(void)filterText{
// 文本信號(hào):監(jiān)聽(tīng)UITextField內(nèi)容的輸入
RACSignal *textSignal = self.usernameField.rac_textSignal;
textSignal = [textSignal filter:^BOOL(NSString *value) {// 將(id value)改為(NSString *value),因?yàn)槲覀円呀?jīng)確定了輸入的內(nèi)容是字符串(即使輸入的是數(shù)字也行)
NSLog(@"filter %@",value);
// 當(dāng)輸入的內(nèi)容大于5時(shí)掸冤。才會(huì)調(diào)用訂閱者block
return value.length > 5;
}];
// 訂閱者block
[textSignal subscribeNext:^(id x) {
NSLog(@"輸出%@",x);// 只有當(dāng)輸入的個(gè)數(shù)大于5時(shí)才打印這行內(nèi)容
}];
}
@end
截圖
6.組合信號(hào)combineLatest:reduce:
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UITextField *usernameField;
@property (weak, nonatomic) IBOutlet UIButton *login;
@property (weak, nonatomic) IBOutlet UITextField *pwd;
@property(nonatomic,strong)RACDisposable *btnDisposable;
@end
@implementation ViewController
// rac給每一個(gè)UI控件都增加了分類,在分類里面給UI控件擴(kuò)充了新的方法友雳。利用rac編程時(shí)用到的就是這個(gè)方法
- (void)viewDidLoad {
[super viewDidLoad];
[self combine]; // 組合信號(hào)combineLatest:reduce:
}
-(void)combine{
NSArray *signals = @[self.usernameField.rac_textSignal,self.pwd.rac_textSignal];
// 組合信號(hào)
RACSignal *combineSignal = [RACSignal combineLatest:signals reduce:^id(NSString *username,NSString *password){
// 無(wú)論用戶名和密碼有沒(méi)有值稿湿,都會(huì)執(zhí)行訂閱block,只是返回的值有0和1押赊,讓登錄按鈕變?yōu)辄c(diǎn)擊狀態(tài)的話,x必須為1.
return @(username.length > 0 && password.length >0);
}];
// 訂閱者block
[combineSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
// x為1時(shí),登錄按鈕才可以點(diǎn)擊
self.login.enabled = [x boolValue];
}];
}
@end
截圖
7.創(chuàng)建一個(gè)用于封裝自定義的網(wǎng)絡(luò)請(qǐng)求的信號(hào)
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface ViewController ()
@end
@implementation ViewController
// rac給每一個(gè)UI控件都增加了分類饺藤,在分類里面給UI控件擴(kuò)充了新的方法。利用rac編程時(shí)用到的就是這個(gè)方法
- (void)viewDidLoad {
[super viewDidLoad];
[self net];// 創(chuàng)建信號(hào)流礁,用于封裝自定義的網(wǎng)絡(luò)請(qǐng)求
}
-(void)net{
// 創(chuàng)建信號(hào),用于封裝自定義的網(wǎng)絡(luò)請(qǐng)求涕俗。即:把網(wǎng)絡(luò)請(qǐng)求的代碼封裝在createSignal的代碼塊中
RACSignal *ipSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 1.創(chuàng)建請(qǐng)求對(duì)象
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://pv.sohu.com/cityjson"]];
// 2.創(chuàng)建下載任務(wù)
NSURLSessionDataTask *dataTask = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// data不是UTF-8編碼,而是GBK編碼
if (error == nil) {// 沒(méi)錯(cuò)誤就執(zhí)行
//將data對(duì)象轉(zhuǎn)換成字符串
NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
NSString *responseStr = [[NSString alloc] initWithData:data encoding:enc];
// 調(diào)用sendNext,底層就會(huì)調(diào)用subscribeNext.只有調(diào)用了subscribeNext,才會(huì)調(diào)用訂閱者block,才會(huì)執(zhí)行block中的內(nèi)容,從而打印responseStr中的內(nèi)容崇棠,然后接著會(huì)打印x中的內(nèi)容咽袜。沒(méi)有這句代碼,什么也不會(huì)打印
[subscriber sendNext:responseStr];//A:調(diào)用subscribeNext的block
[subscriber sendNext:@"CoderZb"];// B:調(diào)用subscribeNext的block
// 注意:調(diào)用sendCompleted或者sendError,程序會(huì)終止向下執(zhí)行枕稀,所以當(dāng)C出現(xiàn)询刹,D不執(zhí)行谜嫉。反之亦然。
[subscriber sendCompleted];// C:調(diào)用sendCompleted的block
// 模擬錯(cuò)誤信息
NSError *ErrorInfo = [NSError errorWithDomain:@"服務(wù)未啟動(dòng)" code:2016 userInfo:nil]; [subscriber sendError:ErrorInfo];//D:調(diào)用error的block
}else{
NSLog(@"+++++%@",error);
}
}];
// 3.執(zhí)行下載任務(wù)
[dataTask resume];
return nil;
}];
// 訂閱者block
[ipSignal subscribeNext:^(id x) {// sendNext:調(diào)用的凹联。
NSLog(@"網(wǎng)絡(luò)請(qǐng)求成功,內(nèi)容為%@",x);// 打印responseStr中的內(nèi)容沐兰。驗(yàn)證:將responseStr替換為@"CoderZb"
} error:^(NSError *errorInfo){
NSLog(@"%@",errorInfo);
}
completed:^{// sendCompleted調(diào)用的。
NSLog(@"終止了訂閱");
}];
}
@end
截圖
8.信號(hào)嵌套
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIButton *ipAddressBtn;
@property (weak, nonatomic) IBOutlet UILabel *ipLabel;
@end
@implementation ViewController
// rac給每一個(gè)UI控件都增加了分類蔽挠,在分類里面給UI控件擴(kuò)充了新的方法住闯。利用rac編程時(shí)用到的就是這個(gè)方法
- (void)viewDidLoad {
[super viewDidLoad];
[self flatterMap];//信號(hào)嵌套
}
-(void)flatterMap{
// 按鈕信號(hào)
RACSignal *btnSignal = [self.ipAddressBtn rac_signalForControlEvents:UIControlEventTouchUpInside];
[[btnSignal flattenMap:^RACStream *(id value) {
return [self ipSignal];// 又嵌套了一個(gè)封裝網(wǎng)絡(luò)請(qǐng)求的信號(hào)
}] subscribeNext:^(id x) {
NSLog(@"%@",x);
self.ipLabel.text = x;
}];
}
-(RACSignal *)ipSignal{
// 創(chuàng)建信號(hào),用于封裝自定義的網(wǎng)絡(luò)請(qǐng)求。即:把網(wǎng)絡(luò)請(qǐng)求的代碼封裝在createSignal的代碼塊中
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 1.創(chuàng)建請(qǐng)求對(duì)象
NSURLRequest * request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://pv.sohu.com/cityjson"]];
// 2.創(chuàng)建下載任務(wù)
NSURLSessionDataTask *dataTask = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// NSLog(@"---%@",[NSThread currentThread]); // 通過(guò)打印可知,block代碼塊所在的線程為子線程澳淑,所以應(yīng)將x比原,y處的代碼寫(xiě)在主線程中,否則ipLabel上顯示不出來(lái)內(nèi)容.因?yàn)轱@示UI要在主線程(主隊(duì)列)執(zhí)行
// data不是UTF-8編碼,而是GBK編碼
if (error == nil) {// 沒(méi)錯(cuò)誤就執(zhí)行
//將data對(duì)象轉(zhuǎn)換成字符串
NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
NSString *responseStr = [[NSString alloc] initWithData:data encoding:enc];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{// 主隊(duì)列即主線程杠巡。驗(yàn)證:打印下面的注釋
// NSLog(@"+++%@",[NSThread currentThread]);
[subscriber sendNext:responseStr];//x:調(diào)用subscribeNext的block
}];
}else{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"+++++%@",error);// y
}];
}
}];
// 3.執(zhí)行下載任務(wù)
[dataTask resume];
return [RACDisposable disposableWithBlock:^{
// 取消網(wǎng)絡(luò)請(qǐng)求
[dataTask cancel];
}];
}];
}
@end
截圖
9.信號(hào)注入
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIButton *ipAddressBtn;
@property (weak, nonatomic) IBOutlet UILabel *ipLabel;
// 可視化創(chuàng)建UIActivityIndicatorView控件并勾選面板右側(cè)的Hides When Stopped量窘,即靜態(tài)(停止)的時(shí)候隱藏該控件。
@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *Indicator;
@end
@implementation ViewController
// rac給每一個(gè)UI控件都增加了分類氢拥,在分類里面給UI控件擴(kuò)充了新的方法蚌铜。利用rac編程時(shí)用到的就是這個(gè)方法
- (void)viewDidLoad {
[super viewDidLoad];
[self doNext];// 信號(hào)注入:doNext在網(wǎng)絡(luò)請(qǐng)求之前可以提前做一些操作,例如提前開(kāi)始Indicator的動(dòng)畫(huà)
}
-(void)doNext{
RACSignal *btnSignal = [self.ipAddressBtn rac_signalForControlEvents:UIControlEventTouchUpInside ];
[btnSignal doNext:^(id x) {
// 開(kāi)始Indicator的動(dòng)畫(huà),此時(shí)Indicator會(huì)顯示,因?yàn)樵诳梢暬姘逵覀?cè)勾選了Hides When Stopped
[self.Indicator startAnimating];
}];
[[btnSignal flattenMap:^RACStream *(id value) {
// 開(kāi)始Indicator的動(dòng)畫(huà),此時(shí)Indicator會(huì)顯示,因?yàn)樵诳梢暬姘逵覀?cè)勾選了Hides When Stopped
[self.Indicator startAnimating];
// 執(zhí)行網(wǎng)絡(luò)請(qǐng)求的信號(hào)
return [self ipSignal];// 當(dāng)有ruturn操作時(shí)嫩海,后面的內(nèi)容不能再用btnSignal對(duì)象調(diào)用,否則最終的結(jié)果不是自己想要的冬殃。
}] subscribeNext:^(id x) {
self.ipLabel.text = x;
// 停止Indicator的動(dòng)畫(huà).此時(shí)Indicator會(huì)隱藏,因?yàn)樵诳梢暬姘逵覀?cè)勾選了Hides When Stopped
[self.Indicator stopAnimating];
}];
}
-(void)flatterMap{
RACSignal *btnSignal = [self.ipAddressBtn rac_signalForControlEvents:UIControlEventTouchUpInside];
[[btnSignal flattenMap:^RACStream *(id value) {
return [self ipSignal];
}] subscribeNext:^(id x) {
NSLog(@"%@",x);
self.ipLabel.text = x;
}];
}
-(RACSignal *)ipSignal{
// 創(chuàng)建信號(hào),用于封裝自定義的網(wǎng)絡(luò)請(qǐng)求。即:把網(wǎng)絡(luò)請(qǐng)求的代碼封裝在createSignal的代碼塊中
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 1.創(chuàng)建請(qǐng)求對(duì)象
NSURLRequest * request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://pv.sohu.com/cityjson"]];
// 2.創(chuàng)建下載任務(wù)
NSURLSessionDataTask *dataTask = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// NSLog(@"---%@",[NSThread currentThread]); // 通過(guò)打印可知,block代碼塊所在的線程為子線程叁怪,所以應(yīng)將x审葬,y處的代碼寫(xiě)在主線程中,否則ipLabel上顯示不出來(lái)內(nèi)容.因?yàn)轱@示UI要在主線程(主隊(duì)列)執(zhí)行
// data不是UTF-8編碼,而是GBK編碼
if (error == nil) {// 沒(méi)錯(cuò)誤就執(zhí)行
//將data對(duì)象轉(zhuǎn)換成字符串
NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
NSString *responseStr = [[NSString alloc] initWithData:data encoding:enc];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{// 主隊(duì)列即主線程骂束。驗(yàn)證:打印下面的注釋
// NSLog(@"+++%@",[NSThread currentThread]);
[subscriber sendNext:responseStr];//x:調(diào)用subscribeNext的block
}];
}else{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"+++++%@",error);// y
}];
}
}];
// 3.執(zhí)行下載任務(wù)
[dataTask resume];
return [RACDisposable disposableWithBlock:^{
// 取消網(wǎng)絡(luò)請(qǐng)求
[dataTask cancel];
}];
}];
}
@end
截圖
10.信號(hào)延遲
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIButton *ipAddressBtn;
@end
@implementation ViewController
// rac給每一個(gè)UI控件都增加了分類耳璧,在分類里面給UI控件擴(kuò)充了新的方法。利用rac編程時(shí)用到的就是這個(gè)方法
- (void)viewDidLoad {
[super viewDidLoad];
[self throttle];// 信號(hào)延遲:訂閱block中的內(nèi)容延時(shí)輸出
}
-(void)throttle{
RACSignal *btnSignal = [self.ipAddressBtn rac_signalForControlEvents:UIControlEventTouchUpInside ];
// 延遲5秒輸出block中的內(nèi)容
[[btnSignal throttle:5] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
}
@end
截圖
11.信號(hào)串聯(lián)
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface ViewController ()
@end
@implementation ViewController
// rac給每一個(gè)UI控件都增加了分類展箱,在分類里面給UI控件擴(kuò)充了新的方法旨枯。利用rac編程時(shí)用到的就是這個(gè)方法
- (void)viewDidLoad {
[super viewDidLoad];
[self concat];// 信號(hào)串聯(lián)(一條線程),任務(wù)依次執(zhí)行.需要執(zhí)行sendCompleted操作
}
-(void)concat{
//調(diào)用sendCompleted,表示信號(hào)的完成。只有信號(hào)完成了混驰,才能執(zhí)行串聯(lián)操作攀隔。就比如串行隊(duì)列,只有前一個(gè)任務(wù)執(zhí)行完成了栖榨,后面的任務(wù)才能執(zhí)行昆汹。如何判斷任務(wù)完成了,類比Rac中的sendCompleted操作婴栽。
// 起床信號(hào)
RACSignal *getup =[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"正在穿衣服"];
[subscriber sendNext:@"起床"];
[subscriber sendCompleted];// 信號(hào)串聯(lián)满粗,必須在兩個(gè)信號(hào)之間執(zhí)行sendCompleted操作
return nil;
}];
// 吃飯信號(hào)
RACSignal *eat =[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"正在吃飯"];
[subscriber sendNext:@"吃完飯了"];
return nil;
}];
// 信號(hào)串聯(lián)
[[getup concat:eat] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
}
@end
截圖
12.信號(hào)并聯(lián)
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface ViewController ()
@end
@implementation ViewController
// rac給每一個(gè)UI控件都增加了分類,在分類里面給UI控件擴(kuò)充了新的方法愚争。利用rac編程時(shí)用到的就是這個(gè)方法
- (void)viewDidLoad {
[super viewDidLoad];
[self merge];// 信號(hào)并聯(lián)(多條線程),任務(wù)同時(shí)執(zhí)行.不用執(zhí)行sendCompleted操作
}
-(void)merge{
// 起床信號(hào)
RACSignal *getup =[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"正在穿衣服"];
[subscriber sendNext:@"起床"];
return nil;
}];
// 吃飯信號(hào)
RACSignal *eat =[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"正在吃飯"];
[subscriber sendNext:@"吃完飯了"];
return nil;
}];
// 信號(hào)并聯(lián)
[[getup merge:eat] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
}
@end
截圖
13.信號(hào)忽略
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface ViewController ()
@end
@implementation ViewController
// rac給每一個(gè)UI控件都增加了分類映皆,在分類里面給UI控件擴(kuò)充了新的方法挤聘。利用rac編程時(shí)用到的就是這個(gè)方法
- (void)viewDidLoad {
[super viewDidLoad];
[self then];// 信號(hào)忽略(一條線程),任務(wù)依次執(zhí)行.忽略的是then:前面的信號(hào),執(zhí)行then后面的信號(hào),所以then前面的信號(hào)不執(zhí)行捅彻,then后面的信號(hào)依次執(zhí)行.需要執(zhí)行sendCompleted操作
}
-(void)then{
// 起床信號(hào)
RACSignal *getup =[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"正在穿衣服"];
[subscriber sendNext:@"起床"];
[subscriber sendCompleted];
return nil;
}];
// 吃飯信號(hào)
RACSignal *eat =[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"正在吃飯"];
[subscriber sendNext:@"吃完飯了"];
return nil;
}];
// 信號(hào)忽略.忽略了getup信號(hào)
[[getup then:^RACSignal *{
return eat;
}] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
}
@end
截圖
14.信號(hào)延遲
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIButton *ipAddressBtn;
@end
@implementation ViewController
// rac給每一個(gè)UI控件都增加了分類组去,在分類里面給UI控件擴(kuò)充了新的方法。利用rac編程時(shí)用到的就是這個(gè)方法
- (void)viewDidLoad {
[super viewDidLoad];
[self delay];// 信號(hào)延遲:等同throttle
}
-(void)delay{
RACSignal *btnSignal = [self.ipAddressBtn rac_signalForControlEvents:UIControlEventTouchUpInside ];
// 點(diǎn)擊按鈕步淹,延遲5秒執(zhí)行
[[btnSignal delay:5] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
}
@end
截圖
15.信號(hào)超時(shí)
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface ViewController ()
@end
@implementation ViewController
// rac給每一個(gè)UI控件都增加了分類从隆,在分類里面給UI控件擴(kuò)充了新的方法。利用rac編程時(shí)用到的就是這個(gè)方法
- (void)viewDidLoad {
[super viewDidLoad];
[self timeout];//信號(hào)超時(shí).用于網(wǎng)絡(luò)請(qǐng)求的信號(hào)
}
-(void)timeout{
// 過(guò)了7秒就超時(shí)缭裆,就不再執(zhí)行訂閱者block.因?yàn)镾ignal方法中線程休眠了5秒键闺,5秒<7秒,所以沒(méi)有超過(guò)超時(shí)的時(shí)間,所以會(huì)執(zhí)行訂閱者block.如果線程休眠10秒,那么就不會(huì)執(zhí)行訂閱者block
[[[self Signal] timeout:7 onScheduler:[RACScheduler mainThreadScheduler]] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
}
-(RACSignal *)Signal{
// 創(chuàng)建信號(hào),用于封裝自定義的網(wǎng)絡(luò)請(qǐng)求澈驼。即:把網(wǎng)絡(luò)請(qǐng)求的代碼封裝在createSignal的代碼塊中
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 1.創(chuàng)建請(qǐng)求對(duì)象
NSURLRequest * request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://pv.sohu.com/cityjson"]];
// 2.創(chuàng)建下載任務(wù)
NSURLSessionDataTask *dataTask = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// NSLog(@"---%@",[NSThread currentThread]); // 通過(guò)打印可知,block代碼塊所在的線程為子線程艾杏,所以應(yīng)將x,y處的代碼寫(xiě)在主線程中盅藻,否則ipLabel上顯示不出來(lái)內(nèi)容.因?yàn)轱@示UI要在主線程(主隊(duì)列)執(zhí)行
// data不是UTF-8編碼,而是GBK編碼
if (error == nil) {// 沒(méi)錯(cuò)誤就執(zhí)行
//將data對(duì)象轉(zhuǎn)換成字符串
NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
NSString *responseStr = [[NSString alloc] initWithData:data encoding:enc];
#warning 線程休眠5秒
[NSThread sleepForTimeInterval:10];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{// 主隊(duì)列即主線程。驗(yàn)證:打印下面的注釋
// NSLog(@"+++%@",[NSThread currentThread]);
[subscriber sendNext:responseStr];//x:調(diào)用subscribeNext的block
}];
}else{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"+++++%@",error);// y
}];
}
}];
// 3.執(zhí)行下載任務(wù)
[dataTask resume];
return [RACDisposable disposableWithBlock:^{
// 取消網(wǎng)絡(luò)請(qǐng)求
[dataTask cancel];
}];
}];
}
@end
截圖
16.監(jiān)聽(tīng)選中的圖片,監(jiān)聽(tīng)選中圖片的手勢(shì)
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property(nonatomic,strong)RACDisposable *btnDisposable;
@end
@implementation ViewController
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
static dispatch_once_t onceToken;
// 一次性代碼畅铭,保證只執(zhí)行一次.這樣第二次點(diǎn)擊屏幕時(shí)候不會(huì)執(zhí)行這段代碼氏淑,但是3處的代碼會(huì)執(zhí)行
dispatch_once(&onceToken,^{ // 功能1:監(jiān)聽(tīng)選中的圖片
UIImagePickerController *pickVC = [[UIImagePickerController alloc] init];
pickVC.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
// 通過(guò)信號(hào)獲取用戶選中的圖片
[pickVC.rac_imageSelectedSignal subscribeNext:^(NSDictionary *Info) {
// NSLog(@"%@",x);
// key根據(jù)上面的打印內(nèi)容粘貼
UIImage *selectImage = Info[@"UIImagePickerControllerOriginalImage"];
self.imageView.image = selectImage;
// 選中完圖片,直接到返回之前的控制器
[self dismissViewControllerAnimated:YES completion:nil];
}];
[self presentViewController:pickVC animated:YES completion:nil];
});
// 功能2:監(jiān)聽(tīng)點(diǎn)擊圖片的手勢(shì)
self.imageView.userInteractionEnabled = YES;
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]init];
[self.imageView addGestureRecognizer:tap];
[tap.rac_gestureSignal subscribeNext:^(id x) {
NSLog(@"圖片被點(diǎn)擊");
}];
}
@end
截圖
17.監(jiān)聽(tīng)鍵盤的彈出
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UITextField *usernameField;
@end
@implementation ViewController
// rac給每一個(gè)UI控件都增加了分類硕噩,在分類里面給UI控件擴(kuò)充了新的方法假残。利用rac編程時(shí)用到的就是這個(gè)方法
- (void)viewDidLoad {
[super viewDidLoad];
// 功能3:監(jiān)聽(tīng)鍵盤的彈出
NSNotificationCenter *notification = [NSNotificationCenter defaultCenter];
[[notification rac_addObserverForName:UIKeyboardDidShowNotification object:nil] subscribeNext:^(id x) {
NSLog(@"鍵盤彈出,鍵盤信息如下----%@",x);
}];
}
@end
截圖
18.監(jiān)聽(tīng)屬性值的改變
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
#import "Person.h"
@interface ViewController ()
@property(nonatomic,strong)Person *person;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self kvo];// kvo監(jiān)聽(tīng)屬性的改變
}
-(void)kvo{
self.person = [[Person alloc] init];
// kvo監(jiān)聽(tīng)屬性的改變,一旦屬性發(fā)生改變就會(huì)調(diào)用訂閱block.所以點(diǎn)擊一下屏幕炉擅,就會(huì)調(diào)用訂閱block一次辉懒。
[RACObserve(self.person, name) subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
self.person.name = @"CoderZb";// 修改name屬性
}
@end
截圖
19.綁定屬性
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UILabel *ipLabel;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self Bundle];// 綁定屬性.將修改的內(nèi)容顯示到屬性上
}
-(void)Bundle{
// 綁定ipLabel對(duì)象的text屬性,將[self ipSignal]返回的結(jié)果賦值給text屬性谍失。相當(dāng)于給系統(tǒng)的屬性賦值眶俩。
RAC(self.ipLabel,text) = [self ipSignal];
}
-(RACSignal *)ipSignal{
// 創(chuàng)建信號(hào),用于封裝自定義的網(wǎng)絡(luò)請(qǐng)求。即:把網(wǎng)絡(luò)請(qǐng)求的代碼封裝在createSignal的代碼塊中
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 1.創(chuàng)建請(qǐng)求對(duì)象
NSURLRequest * request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://pv.sohu.com/cityjson"]];
// 2.創(chuàng)建下載任務(wù)
NSURLSessionDataTask *dataTask = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// NSLog(@"---%@",[NSThread currentThread]); // 通過(guò)打印可知,block代碼塊所在的線程為子線程快鱼,所以應(yīng)將x颠印,y處的代碼寫(xiě)在主線程中,否則ipLabel上顯示不出來(lái)內(nèi)容.因?yàn)轱@示UI要在主線程(主隊(duì)列)執(zhí)行
// data不是UTF-8編碼,而是GBK編碼
if (error == nil) {// 沒(méi)錯(cuò)誤就執(zhí)行
//將data對(duì)象轉(zhuǎn)換成字符串
NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
NSString *responseStr = [[NSString alloc] initWithData:data encoding:enc];
#warning 線程休眠5秒
[NSThread sleepForTimeInterval:5];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{// 主隊(duì)列即主線程抹竹。驗(yàn)證:打印下面的注釋
// NSLog(@"+++%@",[NSThread currentThread]);
[subscriber sendNext:responseStr];//x:調(diào)用subscribeNext的block
}];
}else{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"+++++%@",error);// y
}];
}
}];
// 3.執(zhí)行下載任務(wù)
[dataTask resume];
return [RACDisposable disposableWithBlock:^{
// 取消網(wǎng)絡(luò)請(qǐng)求
[dataTask cancel];
}];
}];
}
@end
截圖
20.監(jiān)聽(tīng)UITextField文本信號(hào)的改變
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UITextField *usernameField;
@property (weak, nonatomic) IBOutlet UILabel *ipLabel;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self Change]; // 監(jiān)聽(tīng)UITextField文本信號(hào)的改變线罕,只要文本發(fā)生改變,就會(huì)將改變的內(nèi)容顯示在UILabel上
}
-(void)Change{
// 監(jiān)聽(tīng)UITextField文本信號(hào)的改變窃判,只要文本發(fā)生改變钞楼,就會(huì)將改變的內(nèi)容添加到UILabel上
RAC(self.ipLabel,text) = self.usernameField.rac_textSignal;
}
@end
截圖
21.RAC中,解決block造成的循環(huán)引用的兩種做法
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
#import "Person.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UITextField *usernameField;
@property (weak, nonatomic) IBOutlet UIButton *login;
@property (weak, nonatomic) IBOutlet UITextField *pwd;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 解決block造成的循環(huán)引用的兩種做法
// 做法1:
/*
__weak typeof(self) weakSelf = self;
[[RACSignal combineLatest:@[self.usernameField.rac_textSignal,self.pwd.rac_textSignal] reduce:^id(NSString *username,NSString *pwd){
return @(username.length > 0 && pwd.length > 0);
}] subscribeNext:^(id x) {
weakSelf.login.enabled = [x boolValue];
}];
*/
// 做法2:
@weakify(self)
[[RACSignal combineLatest:@[self.usernameField.rac_textSignal,self.pwd.rac_textSignal] reduce:^id(NSString *username,NSString *pwd){
return @(username.length > 0 && pwd.length > 0);
}] subscribeNext:^(id x) {
@strongify(self)
self.login.enabled = [x boolValue];
}];
}
-(void)dealloc{
NSLog(@"%s",__func__);
}
@end
截圖
101.21.gif
22.(一)rac_command
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIButton *ipAddressBtn;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self btnClick];//rac_command
}
-(void)btnClick{
// RACCommand:點(diǎn)擊按鈕,執(zhí)行訂閱者block
self.ipAddressBtn.rac_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
return [self ipSignal];
}];
}
-(RACSignal *)ipSignal{
// 創(chuàng)建信號(hào),用于封裝自定義的網(wǎng)絡(luò)請(qǐng)求。即:把網(wǎng)絡(luò)請(qǐng)求的代碼封裝在createSignal的代碼塊中
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 1.創(chuàng)建請(qǐng)求對(duì)象
NSURLRequest * request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://pv.sohu.com/cityjson"]];
// 2.創(chuàng)建下載任務(wù)
NSURLSessionDataTask *dataTask = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error == nil) {// 沒(méi)錯(cuò)誤就執(zhí)行
//將data對(duì)象轉(zhuǎn)換成字符串
NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
NSString *responseStr = [[NSString alloc] initWithData:data encoding:enc];
NSLog(@"%@",responseStr);
}else{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"+++++%@",error);// y
}];
}
}];
// 3.執(zhí)行下載任務(wù)
[dataTask resume];
return nil;
}];
}
@end
截圖
23.(二)rac_command
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UITextField *usernameField;
@property (weak, nonatomic) IBOutlet UITextField *pwd;
@property (weak, nonatomic) IBOutlet UIButton *ipAddressBtn;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self EnabledSingle];// rac_command
}
-(void)EnabledSingle{
// 按鈕的可用信號(hào)
RACSignal *btnEnabledSingle = [RACSignal combineLatest:@[self.usernameField.rac_textSignal,self.pwd.rac_textSignal] reduce:^id(NSString *username,NSString *pwd){
// 只有用戶名和密碼不為空時(shí)袄琳,ipAddressBtn按鈕才會(huì)變?yōu)榭梢渣c(diǎn)擊的狀態(tài)询件。
return @(username.length > 0 && pwd.length > 0);
}];
// 按鈕點(diǎn)擊后觸發(fā)信號(hào)燃乍,從而會(huì)打印出ip地址。如果按鈕不可點(diǎn)擊,是無(wú)法觸發(fā)信號(hào)的雳殊。
self.ipAddressBtn.rac_command = [[RACCommand alloc]initWithEnabled:btnEnabledSingle signalBlock:^RACSignal *(id input) {
return [self ipSignal];
}];
}
-(RACSignal *)ipSignal{
// 創(chuàng)建信號(hào),用于封裝自定義的網(wǎng)絡(luò)請(qǐng)求橘沥。即:把網(wǎng)絡(luò)請(qǐng)求的代碼封裝在createSignal的代碼塊中
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 1.創(chuàng)建請(qǐng)求對(duì)象
NSURLRequest * request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://pv.sohu.com/cityjson"]];
// 2.創(chuàng)建下載任務(wù)
NSURLSessionDataTask *dataTask = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// NSLog(@"---%@",[NSThread currentThread]); // 通過(guò)打印可知,block代碼塊所在的線程為子線程,所以應(yīng)將x夯秃,y處的代碼寫(xiě)在主線程中座咆,否則ipLabel上顯示不出來(lái)內(nèi)容.因?yàn)轱@示UI要在主線程(主隊(duì)列)執(zhí)行
// data不是UTF-8編碼,而是GBK編碼
if (error == nil) {// 沒(méi)錯(cuò)誤就執(zhí)行
//將data對(duì)象轉(zhuǎn)換成字符串
NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
NSString *responseStr = [[NSString alloc] initWithData:data encoding:enc];
NSLog(@"%@",responseStr);
}else{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"+++++%@",error);// y
}];
}
}];
// 3.執(zhí)行下載任務(wù)
[dataTask resume];
return nil;
}];
}
@end
截圖
24.RACSequence
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self racSequence];// RACSequence:主要用于遍歷
}
-(void)racSequence{
NSArray *names = @[@"Tom",@"Mary",@"Jack"];
// 獲取RACSequence里面的信號(hào)進(jìn)行遍歷
[names.rac_sequence.signal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
}
@end
截圖
25.RACSequence和filter結(jié)合使用
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self racSequenceAndfilter];// RACSequence和filter結(jié)合使用
}
-(void)racSequenceAndfilter{
// RACSequence與filter(過(guò)濾)的結(jié)合使用
NSString *text = @"19293842456647";
[[text.rac_sequence.signal filter:^BOOL(id value) {
return [value intValue] >5;// 只打印大于5的數(shù)字
}] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
}
@end
截圖
登錄小項(xiàng)目
- 查看隱藏的Apache的安裝目錄:/etc/apache2/
- 做法1:dock下右鍵Finder,選擇"前往文件夾"仓洼,輸入"/etc"
- 做法2:finder下->前往->前往文件夾->輸入/etc
- 做法3:Terminal 輸入 "open /etc"
apache相關(guān)指令:
開(kāi)啟apache服務(wù) sudo apachectl start
停止apache服務(wù) sudo apachectl stop
重啟服務(wù) sudo apachectl restart
查看版本 httpd -v
注意點(diǎn):
Apache+Mysql+PHP的集成環(huán)境的配置(一介陶、二、三)
(一)Apache服務(wù)器的開(kāi)啟和配置色建、php的配置
httpd.conf配置錯(cuò)誤的話,重新下載未修改的httpd.conf文件 密碼
具體步驟推薦這個(gè)參考鏈接
- 1.在自己的用戶目錄(zhangbin)里新建一個(gè)Sites文件夾
- 2.進(jìn)到cd /etc/apache2/users/目錄下哺呜,sudo vim zhangbin.conf,增加內(nèi)容為:
<Directory "/Users/zhangbin/Sites/">
AllowOverride All
Options Indexes MultiViews FollowSymLinks
Require all granted
</Directory>
- 3.修改zhangbin.conf這個(gè)文件的權(quán)限
sudo chmod 644 zhangbin.conf
- 4.cd到/etc/apache2/目錄箕戳,sudo vim httpd.conf 將下面五句話的注釋去掉
LoadModule authz_core_module libexec/apache2/mod_authz_core.so
LoadModule authz_host_module libexec/apache2/mod_authz_host.so
LoadModule userdir_module libexec/apache2/mod_userdir.so
Include /private/etc/apache2/extra/httpd-userdir.conf
LoadModule php5_module libexec/apache2/libphp5.so
- 5.進(jìn)到/etc/apache2/extra/目錄某残,sudo vim httpd-userdir.conf ,將這句話的注釋去掉
Include /private/etc/apache2/users/*.conf
- 6.sudo apachectl restart 重啟服務(wù)器
- 7.將php后臺(tái)代碼放到Sites文件夾下
- 8.瀏覽器輸入: loacal/~zhangbin/
拓展知識(shí)點(diǎn)修改apache默認(rèn)頁(yè)面的內(nèi)容
cd /Library/WebServer/Documents/
sudo vim index.html.en
(二)開(kāi)啟MySQL服務(wù)器(必不可少),安裝Navicat數(shù)據(jù)庫(kù)管理工具
-
1.只安裝MySQL.prefPane陵吸,用于開(kāi)啟MySQL服務(wù)器
102.1gif.gif 2.終端輸入(必須)
mysqladmin -u root password "123456"-
3.安裝Navicat數(shù)據(jù)庫(kù)管理工具. 目的:創(chuàng)建表玻墅,創(chuàng)建數(shù)據(jù)庫(kù)等等。
102.2.gif 4.創(chuàng)建數(shù)據(jù)庫(kù)壮虫,創(chuàng)建表
(三)效果展示
注冊(cè)
登錄
發(fā)表日志
細(xì)節(jié)問(wèn)題
-
1.開(kāi)啟和關(guān)閉MySQL的影響
101.29.gif
-
2.1.Apache系統(tǒng)級(jí)的根目錄及對(duì)應(yīng)網(wǎng)址是:
/Library/WebServer/Documents/http://localhost
-
2.2.用戶級(jí)的根目錄及對(duì)應(yīng)網(wǎng)址是:
~/Siteshttp://localhost/~zhangbin/
由2.1和2.2可知關(guān)閉和開(kāi)啟apache服務(wù)器對(duì)訪問(wèn)網(wǎng)址的影響如下截圖
[軟件+項(xiàng)目LS](https://pan.baidu.com/s/1gffo8IB 密碼 43kp )