RAC


RAC中類的繼承關(guān)系

1.RACDynamicSignal:RACSignal:RACStream
2.RACSequence:RACStream
3.RACCompoundDisposable : RACDisposable
4.RACSubscriptionScheduler : RACScheduler
5.RACQueueScheduler : RACScheduler


RAC優(yōu)勢(提高開發(fā)效率)

1.把target-Action/代理/通知/KVO統(tǒng)一封裝成信號(hào),即信號(hào)就可以實(shí)現(xiàn)這些功能。
2.監(jiān)聽屬性的代碼少
3.代碼直觀,代碼復(fù)雜度減小m3u8
4.通過block降低代碼間的耦合


訂閱和訂閱者

  • subscribeNext:訂閱
    subscribeNext:^(id x) { }
  • subscriber:訂閱者,例如訂閱者調(diào)用sendNext方法。
    [subscriber sendNext:responseObject];

25個(gè)事例+1個(gè)小項(xiàng)目幫助你解開RAC的面紗


1.監(jiān)聽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)聽UITextField內(nèi)容的輸入信號(hào)

}
-(void)Username{

    /*  1+2可以寫成一行代碼
     [self.usernameField.rac_textSignal subscribeNext:^(id x) {/
     NSLog(@"%@",x);
     }];
     */
    
    // 文本信號(hào):監(jiān)聽UITextField內(nèi)容的輸入
    RACSignal *textSignal = self.usernameField.rac_textSignal;// 1
   // 訂閱者block
    [textSignal subscribeNext:^(id x) {// 2
        NSLog(@"%@",x);
        
    }];
    
}

@end

截圖

101.1.gif

2.監(jiān)聽按鈕的點(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)聽按鈕的點(diǎn)擊信號(hào)(信號(hào)理解為事件)
}

 -(void)Login{
    /* 1+2可以寫成一行代碼
    [[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

截圖

101.2.gif

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)沒有打印。因?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

截圖

101.3.gif

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)聽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

截圖

101.4.gif

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)聽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

截圖

101.5.gif

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){
        // 無論用戶名和密碼有沒有值,都會(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

截圖

101.6.gif

7.創(chuàng)建一個(gè)用于封裝自定義的網(wǎng)絡(luò)請求的信號(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ò)請求
    
}

-(void)net{
    // 創(chuàng)建信號(hào),用于封裝自定義的網(wǎng)絡(luò)請求。即:把網(wǎng)絡(luò)請求的代碼封裝在createSignal的代碼塊中
    RACSignal *ipSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        // 1.創(chuàng)建請求對象
        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) {// 沒錯(cuò)誤就執(zhí)行
                //將data對象轉(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)容。沒有這句代碼,什么也不會(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ò)請求成功,內(nèi)容為%@",x);// 打印responseStr中的內(nèi)容。驗(yàn)證:將responseStr替換為@"CoderZb"
        } error:^(NSError *errorInfo){
            NSLog(@"%@",errorInfo);
        }
        completed:^{// sendCompleted調(diào)用的。
            NSLog(@"終止了訂閱");
        }];
}

@end

截圖

101.7.gif

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ò)請求的信號(hào)
    }] subscribeNext:^(id x) {
          NSLog(@"%@",x);
        self.ipLabel.text = x;
    }];
}

-(RACSignal *)ipSignal{
    // 創(chuàng)建信號(hào),用于封裝自定義的網(wǎng)絡(luò)請求。即:把網(wǎng)絡(luò)請求的代碼封裝在createSignal的代碼塊中
   return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        // 1.創(chuàng)建請求對象
        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]); // 通過打印可知,block代碼塊所在的線程為子線程,所以應(yīng)將x,y處的代碼寫在主線程中,否則ipLabel上顯示不出來內(nèi)容.因?yàn)轱@示UI要在主線程(主隊(duì)列)執(zhí)行
            // data不是UTF-8編碼,而是GBK編碼
            if (error == nil) {// 沒錯(cuò)誤就執(zhí)行
                //將data對象轉(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ò)請求
           [dataTask cancel];
       }];
    }];
}
@end

截圖

101.8.gif

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ò)請求之前可以提前做一些操作,例如提前開始Indicator的動(dòng)畫
}

-(void)doNext{

    RACSignal *btnSignal = [self.ipAddressBtn rac_signalForControlEvents:UIControlEventTouchUpInside ];
    [btnSignal doNext:^(id x) {
        // 開始Indicator的動(dòng)畫,此時(shí)Indicator會(huì)顯示,因?yàn)樵诳梢暬姘逵覀?cè)勾選了Hides When Stopped
                [self.Indicator startAnimating];
    }];
    [[btnSignal flattenMap:^RACStream *(id value) {
        // 開始Indicator的動(dòng)畫,此時(shí)Indicator會(huì)顯示,因?yàn)樵诳梢暬姘逵覀?cè)勾選了Hides When Stopped
                [self.Indicator startAnimating];
                // 執(zhí)行網(wǎng)絡(luò)請求的信號(hào)
                return [self ipSignal];// 當(dāng)有ruturn操作時(shí),后面的內(nèi)容不能再用btnSignal對象調(diào)用,否則最終的結(jié)果不是自己想要的。
    }] subscribeNext:^(id x) {
        self.ipLabel.text = x;
                // 停止Indicator的動(dòng)畫.此時(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ò)請求。即:把網(wǎng)絡(luò)請求的代碼封裝在createSignal的代碼塊中
   return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        // 1.創(chuàng)建請求對象
        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]); // 通過打印可知,block代碼塊所在的線程為子線程,所以應(yīng)將x,y處的代碼寫在主線程中,否則ipLabel上顯示不出來內(nèi)容.因?yàn)轱@示UI要在主線程(主隊(duì)列)執(zhí)行
            // data不是UTF-8編碼,而是GBK編碼
            if (error == nil) {// 沒錯(cuò)誤就執(zhí)行
                //將data對象轉(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ò)請求
           [dataTask cancel];
       }];
    }];
}

@end

截圖

101.9.gif

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

截圖

101.10.gif

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

截圖

101.11.gif

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

截圖

101.12.gif

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

截圖

101.13.gif

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

截圖

101.14.gif

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ò)請求的信號(hào)

}

-(void)timeout{
    // 過了7秒就超時(shí),就不再執(zhí)行訂閱者block.因?yàn)镾ignal方法中線程休眠了5秒,5秒<7秒,所以沒有超過超時(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ò)請求。即:把網(wǎng)絡(luò)請求的代碼封裝在createSignal的代碼塊中
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        // 1.創(chuàng)建請求對象
        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]); // 通過打印可知,block代碼塊所在的線程為子線程,所以應(yīng)將x,y處的代碼寫在主線程中,否則ipLabel上顯示不出來內(nèi)容.因?yàn)轱@示UI要在主線程(主隊(duì)列)執(zhí)行
            // data不是UTF-8編碼,而是GBK編碼
            if (error == nil) {// 沒錯(cuò)誤就執(zhí)行
                //將data對象轉(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ò)請求
            [dataTask cancel];
        }];
    }];
}
@end

截圖

101.15.gif

16.監(jiān)聽選中的圖片,監(jiān)聽選中圖片的手勢


#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)聽選中的圖片
        UIImagePickerController *pickVC = [[UIImagePickerController alloc] init];
        pickVC.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
        // 通過信號(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)聽點(diǎn)擊圖片的手勢
    self.imageView.userInteractionEnabled = YES;
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]init];
    [self.imageView addGestureRecognizer:tap];
    [tap.rac_gestureSignal subscribeNext:^(id x) {
        NSLog(@"圖片被點(diǎn)擊");
    }];
}
@end

截圖

101.16.gif

17.監(jiān)聽鍵盤的彈出

#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)聽鍵盤的彈出
    NSNotificationCenter *notification = [NSNotificationCenter defaultCenter];
    [[notification rac_addObserverForName:UIKeyboardDidShowNotification object:nil] subscribeNext:^(id x) {
        NSLog(@"鍵盤彈出,鍵盤信息如下----%@",x);
    }];

}

@end

截圖

101.17.gif

18.監(jiān)聽屬性值的改變

#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)聽屬性的改變
    
   }

-(void)kvo{
    self.person = [[Person alloc] init];
    // kvo監(jiān)聽屬性的改變,一旦屬性發(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

截圖

101.18.gif

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對象的text屬性,將[self ipSignal]返回的結(jié)果賦值給text屬性。相當(dāng)于給系統(tǒng)的屬性賦值。
    RAC(self.ipLabel,text) = [self ipSignal];
}
-(RACSignal *)ipSignal{
    // 創(chuàng)建信號(hào),用于封裝自定義的網(wǎng)絡(luò)請求。即:把網(wǎng)絡(luò)請求的代碼封裝在createSignal的代碼塊中
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        // 1.創(chuàng)建請求對象
        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]); // 通過打印可知,block代碼塊所在的線程為子線程,所以應(yīng)將x,y處的代碼寫在主線程中,否則ipLabel上顯示不出來內(nèi)容.因?yàn)轱@示UI要在主線程(主隊(duì)列)執(zhí)行
            // data不是UTF-8編碼,而是GBK編碼
            if (error == nil) {// 沒錯(cuò)誤就執(zhí)行
                //將data對象轉(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ò)請求
            [dataTask cancel];
        }];
    }];
}

@end

截圖

101.19.gif

20.監(jiān)聽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)聽UITextField文本信號(hào)的改變,只要文本發(fā)生改變,就會(huì)將改變的內(nèi)容顯示在UILabel上
    
}

-(void)Change{
    // 監(jiān)聽UITextField文本信號(hào)的改變,只要文本發(fā)生改變,就會(huì)將改變的內(nèi)容添加到UILabel上
    RAC(self.ipLabel,text) = self.usernameField.rac_textSignal;
}
@end

截圖

101.20.gif

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ò)請求。即:把網(wǎng)絡(luò)請求的代碼封裝在createSignal的代碼塊中
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        // 1.創(chuàng)建請求對象
        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) {// 沒錯(cuò)誤就執(zhí)行
                //將data對象轉(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

截圖

101.22.gif

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)擊,是無法觸發(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ò)請求。即:把網(wǎng)絡(luò)請求的代碼封裝在createSignal的代碼塊中
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        // 1.創(chuàng)建請求對象
        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]); // 通過打印可知,block代碼塊所在的線程為子線程,所以應(yīng)將x,y處的代碼寫在主線程中,否則ipLabel上顯示不出來內(nèi)容.因?yàn)轱@示UI要在主線程(主隊(duì)列)執(zhí)行
            // data不是UTF-8編碼,而是GBK編碼
            if (error == nil) {// 沒錯(cuò)誤就執(zhí)行
                //將data對象轉(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

截圖

101.23.gif

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

截圖

101.24.gif

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(過濾)的結(jié)合使用
    NSString *text = @"19293842456647";
    [[text.rac_sequence.signal filter:^BOOL(id value) {
        return [value intValue] >5;// 只打印大于5的數(shù)字
    }] subscribeNext:^(id x) {
        NSLog(@"%@",x);
    }];

}
@end

截圖

101.25.gif

登錄小項(xiàng)目


  • 查看隱藏的Apache的安裝目錄:/etc/apache2/
  • 做法1:dock下右鍵Finder,選擇"前往文件夾",輸入"/etc"
  • 做法2:finder下->前往->前往文件夾->輸入/etc
  • 做法3:Terminal 輸入 "open /etc"

  • apache相關(guān)指令:

  • 開啟apache服務(wù) sudo apachectl start

  • 停止apache服務(wù) sudo apachectl stop

  • 重啟服務(wù) sudo apachectl restart

  • 查看版本 httpd -v

  • 注意點(diǎn):

端口沖突的問題.png

Apache+Mysql+PHP的集成環(huán)境的配置(一、二、三)


(一)Apache服務(wù)器的開啟和配置、php的配置

httpd.conf配置錯(cuò)誤的話,重新下載未修改的httpd.conf文件 密碼


具體步驟推薦這個(gè)參考鏈接

參考鏈接1
參考鏈接2
參考鏈接3
參考鏈接4

  • 1.在自己的用戶目錄(zhangbin)里新建一個(gè)Sites文件夾
111.1.png

  • 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>
111.2.gif

  • 3.修改zhangbin.conf這個(gè)文件的權(quán)限
sudo chmod 644 zhangbin.conf

111.3.gif

  • 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文件夾下
111.7.png

  • 8.瀏覽器輸入: loacal/~zhangbin/
111.8.png

拓展知識(shí)點(diǎn)修改apache默認(rèn)頁面的內(nèi)容

cd /Library/WebServer/Documents/
sudo vim index.html.en

(二)開啟MySQL服務(wù)器(必不可少),安裝Navicat數(shù)據(jù)庫管理工具


  • 1.只安裝MySQL.prefPane,用于開啟MySQL服務(wù)器


    102.1gif.gif
  • 2.終端輸入(必須)
    mysqladmin -u root password "123456"

  • 3.安裝Navicat數(shù)據(jù)庫管理工具. 目的:創(chuàng)建表,創(chuàng)建數(shù)據(jù)庫等等。


    102.2.gif
  • 4.創(chuàng)建數(shù)據(jù)庫,創(chuàng)建表

102.3.gif

(三)效果展示


注冊
101.26.gif
登錄
101.27.gif
發(fā)表日志
101.28.gif

細(xì)節(jié)問題
  • 1.開啟和關(guān)閉MySQL的影響


    101.29.gif
  • 2.1.Apache系統(tǒng)級(jí)的根目錄及對應(yīng)網(wǎng)址是:
    /Library/WebServer/Documents/

         http://localhost
    
  • 2.2.用戶級(jí)的根目錄及對應(yīng)網(wǎng)址是:
    ~/Sites

        http://localhost/~zhangbin/
    

由2.1和2.2可知關(guān)閉和開啟apache服務(wù)器對訪問網(wǎng)址的影響如下截圖


101.30.gif

[軟件+項(xiàng)目LS](https://pan.baidu.com/s/1gffo8IB 密碼 43kp )

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容