代理模式是一種消息傳遞方式,一個(gè)完整的代理模式包括:委托對(duì)象、代理對(duì)象和協(xié)議。
創(chuàng)新互聯(lián)建站2013年至今,先為南江等服務(wù)建站,南江等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為南江企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。
協(xié)議:用來指定代理雙方可以做什么,必須做什么。
委托對(duì)象:根據(jù)指定的協(xié)議,指定代理去完成什么功能。
代理對(duì)象:根據(jù)指定的協(xié)議,完成委托方需要實(shí)現(xiàn)的功能。
從上圖中可以看到三方之間的關(guān)系,在實(shí)際應(yīng)用中通過協(xié)議來規(guī)定代理雙方的行為,協(xié)議中的內(nèi)容一般都是方法列表,當(dāng)然也可以定義屬性。
協(xié)議是公共的定義,如果只是某個(gè)類使用,我們常做的就是寫在某個(gè)類中。如果是多個(gè)類都是用同一個(gè)協(xié)議,建議創(chuàng)建一個(gè)Protocol文件,在這個(gè)文件中定義協(xié)議。遵循的協(xié)議可以被繼承,例如我們常用的 UITableView ,由于繼承自 UIScrollView 的緣故,所以也將 UIScrollViewDelegate 繼承了過來,我們可以通過代理方法獲取 UITableView 偏移量等狀態(tài)參數(shù)。
協(xié)議只能定義公用的一套接口,類似于一個(gè)約束代理雙方的作用。但不能提供具體的實(shí)現(xiàn)方法,實(shí)現(xiàn)方法需要代理對(duì)象去實(shí)現(xiàn)。協(xié)議可以繼承其他協(xié)議,并且可以繼承多個(gè)協(xié)議,在iOS中對(duì)象是不支持多繼承的,而協(xié)議可以多繼承。
協(xié)議有兩個(gè)修飾符 @optional 和 @required ,創(chuàng)建一個(gè)協(xié)議如果沒有聲明,默認(rèn)是 @required 狀態(tài)的。這兩個(gè)修飾符只是約定代理是否強(qiáng)制需要遵守協(xié)議,如果 @required 狀態(tài)的方法代理沒有遵守,會(huì)報(bào)一個(gè)黃色的警告,只是起一個(gè)約束的作用,沒有其他功能。
無論是 @optional 還是 @required ,在委托方調(diào)用代理方法時(shí)都需要做一個(gè)判斷,判斷代理是否實(shí)現(xiàn)當(dāng)前方法,否則會(huì)導(dǎo)致崩潰。
在iOS中代理的本質(zhì)就是代理對(duì)象內(nèi)存的傳遞和操作,我們?cè)谖蓄愒O(shè)置代理對(duì)象后,實(shí)際上只是用一個(gè)id類型的指針將代理對(duì)象進(jìn)行了一個(gè)弱引用。委托方讓代理方執(zhí)行操作,實(shí)際上是在委托類中向這個(gè)id類型指針指向的對(duì)象發(fā)送消息,而這個(gè)id類型指針指向的對(duì)象,就是代理對(duì)象。
通過上面這張圖我們發(fā)現(xiàn),其實(shí)委托方的代理屬性本質(zhì)上就是代理對(duì)象自身,設(shè)置委托代理就是代理屬性指針指向代理對(duì)象,相當(dāng)于代理對(duì)象只是在委托方中調(diào)用自己的方法,如果方法沒有實(shí)現(xiàn)就會(huì)導(dǎo)致崩潰。從崩潰的信息上來看,就可以看出來是代理方?jīng)]有實(shí)現(xiàn)協(xié)議中的方法導(dǎo)致的崩潰。
而協(xié)議只是一種語法,是聲明委托方中的代理屬性可以調(diào)用協(xié)議中聲明的方法,而協(xié)議中方法的實(shí)現(xiàn)還是有代理方完成,而協(xié)議方和委托方都不知道代理方有沒有完成,也不需要知道怎么完成。
由于代理對(duì)象使用強(qiáng)引用指針,引用創(chuàng)建的委托方對(duì)象,并且成為委托對(duì)象的代理。這就會(huì)導(dǎo)致委托對(duì)象的delegate屬性強(qiáng)引用代理對(duì)象,導(dǎo)致循環(huán)引用的問題,最終兩個(gè)對(duì)象都無法正常釋放。
我們將委托對(duì)象的delegate屬性,設(shè)置為弱引用屬性。
weak 和 assign 是一種“非擁有關(guān)系”的指針,通過這兩種修飾符修飾的指針變量,都不會(huì)改變被引用對(duì)象的引用計(jì)數(shù)。但是在一個(gè)對(duì)象被釋放后, weak 會(huì)自動(dòng)將指針指向 nil ,而 assign 則不會(huì)。在iOS中,向 nil 發(fā)送消息時(shí)不會(huì)導(dǎo)致崩潰的,所以 assign 就會(huì)導(dǎo)致野指針的錯(cuò)誤 unrecognized selector sent to instance 。
所以我們?nèi)绻揎棿韺傩?,還是用 weak 修飾,比較安全。
協(xié)議(Protocol)類似Java中的接口,它是一個(gè)功能方法的集合。協(xié)議本身不是一個(gè)類,不能自己實(shí)現(xiàn)協(xié)議里的方法,而是委托其他類去實(shí)現(xiàn)。通常用來實(shí)現(xiàn)委托代理設(shè)計(jì)模式,實(shí)現(xiàn)不同類對(duì)象之間的時(shí)間消息通信。協(xié)議中的方法默認(rèn)都是@required,即使用該協(xié)議的類必須實(shí)現(xiàn)協(xié)議里的這些方法。開發(fā)者也可以使用@optional來選擇性地實(shí)現(xiàn)某個(gè)方法。
代理(Delegate)是一種設(shè)計(jì)模式,在Objective-C中通過協(xié)議(Protocol)來實(shí)現(xiàn)??梢允挂粋€(gè)對(duì)象在特定時(shí)刻通知其他類的對(duì)象去實(shí)現(xiàn)任務(wù),不需要獲取那些對(duì)象的指針,實(shí)現(xiàn)不同對(duì)象之間的通行。
在項(xiàng)目功能中有一個(gè)定位CLLocation的需求,遇到了一些知識(shí)難點(diǎn),經(jīng)過各位大俠的幫助,問題解決,特此分享供大家學(xué)習(xí),希望大家共同學(xué)習(xí)進(jìn)步。
一、簡(jiǎn)單說明
1.CLLocationManager
CLLocationManager的常用操作和屬性
開始用戶定位- (void)startUpdatingLocation;
停止用戶定位- (void) stopUpdatingLocation;
說明:當(dāng)調(diào)用了startUpdatingLocation方法后,就開始不斷地定位用戶的'位置,中途會(huì)頻繁地調(diào)用代理的下面方法
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations;
每隔多少米定位一次
@property(assign, nonatomic) CLLocationDistance distanceFilter;
定位精確度(越精確就越耗電)
@property(assign, nonatomic) CLLocationAccuracy desiredAccuracy;
使用定位功能,首先要導(dǎo)入框架,遵守CLLocationManagerDelegate協(xié)議,再創(chuàng)建位置管理器CLLocationManager
在iOS8.0后,定位功能需要在info.plist中加入NSLocationWhenInUseUsageDescription和NSLocationAlwaysUsageDescription這兩個(gè)NSString類型字段,才能夠使用定位功能
代碼貼出來與大家共勉,各位看官自行研究
{ self.locationManager = [[CLLocationManager alloc] init]; _locationManager.delegate = self; if([CLLocationManager locationServicesEnabled] == NO) { // NSLog(@"沒有GPS服務(wù)"); } //地理位置精確度 _locationManager.desiredAccuracy=kCLLocationAccuracyNearestTenMeters; //設(shè)置距離篩選器,double類型,只要距離變化多少,就調(diào)用委托代理 self.locationManager.distanceFilter = kCLDistanceFilterNone; // meters [_locationManager requestWhenInUseAuthorization];// 前臺(tái)定位 [_locationManager startUpdatingLocation];}- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{ NSLog(@"longitude = %f", ((CLLocation *)[locations lastObject]).coordinate.longitude); NSLog(@"latitude = %f", ((CLLocation *)[locations lastObject]).coordinate.latitude); CGFloat longTI=((CLLocation *)[locations lastObject]).coordinate.longitude; CGFloat latTI=((CLLocation *)[locations lastObject]).coordinate.latitude; //將經(jīng)度顯示到label上 _longitudeLabel.text = [NSString stringWithFormat:@"%f",longTI]; //將緯度現(xiàn)實(shí)到label上 _latitudeLabel.text = [NSString stringWithFormat:@"%f",latTI]; // 獲取當(dāng)前所在的城市名 CLGeocoder *geocoder = [[CLGeocoder alloc] init]; //根據(jù)經(jīng)緯度反向地理編譯出地址信息 [geocoder reverseGeocodeLocation:locations.lastObject completionHandler:^(NSArray *array, NSError *error) { if (array.count 0) { CLPlacemark *placemark = [array objectAtIndex:0];// //將獲得的所有信息顯示到label上// self.location.text = placemark.name; //獲取城市 NSString *city = placemark.locality; if (!city) { //四大直轄市的城市信息無法通過locality獲得,只能通過獲取省份的方法來獲得(如果city為空,則可知為直轄市) city = placemark.administrativeArea; } // NSLog(@"city = %@", city); _cityName=city; } else if (error == nil [array count] == 0) { // NSLog(@"No results were returned."); } else if (error != nil) { // NSLog(@"An error occurred = %@", error); } }]; //系統(tǒng)會(huì)一直更新數(shù)據(jù),直到選擇停止更新,因?yàn)槲覀冎恍枰@得一次經(jīng)緯度即可,所以獲取之后就停止更新 [manager stopUpdatingLocation];}
以上是關(guān)于我給大家整理的IOS開發(fā)之詳解定位CLLocation,后續(xù)還會(huì)持續(xù)更新,希望大家能夠喜歡。
由于對(duì)某款app的租房信息的篩選條件不滿意,所以爬取了它的api以便能夠根據(jù)自己的需求進(jìn)行篩選。根據(jù)自己的初級(jí)爬蟲經(jīng)驗(yàn),為了防止app封禁我的ip,所以準(zhǔn)備通過代理服務(wù)器去訪問。
過程是相當(dāng)糾結(jié)啊,嘗試的太多,這里就只放結(jié)論了。
筆者使用的 URLSession ,初始化前配置 URLSessionConfiguration 對(duì)象的 connectionProxyDictionary 即可。
特別提醒: host 類型為 String , 而 port 類型為 Int .
ps:使用http時(shí),需要添加ATS白名單
注: 兩種代理方式貌似不能同時(shí)使用。不確定是因?yàn)槲覝y(cè)試時(shí)上一秒代理還好好的,下一秒就掛了。
一般服務(wù)器對(duì)于爬蟲是不歡迎的。真正的用戶操作再快都需要一定的時(shí)間,而爬蟲訪問時(shí)間很短,因此相當(dāng)規(guī)模的爬蟲對(duì)服務(wù)器造成的負(fù)擔(dān)就更大。所以服務(wù)器會(huì)對(duì)爬蟲做檢測(cè),如果被抓到則可能被封掉ip或像本例一樣返回其他網(wǎng)站。
針對(duì)檢測(cè),我們的做法就是要偽裝成真正的用戶。以筆者目前的理解有兩點(diǎn):
1. 修改請(qǐng)求頭。通過Charles抓包可以看到一次請(qǐng)求的頭部信息,對(duì)照修改
2. 設(shè)定訪問延時(shí)。手速再快你也快不過自動(dòng)運(yùn)行的程序吧。
參考鏈接:
ps: 一個(gè)不錯(cuò)的爬蟲學(xué)習(xí)系列
過程中遇到最多的就是1200錯(cuò)誤碼:無法與服務(wù)器建立安全連接。網(wǎng)上大多數(shù)意見是服務(wù)器SSL版本不夠,因?yàn)閕OS最低要求使用TLSv1.2的版本。對(duì)于更低一點(diǎn)的,就需要特別指定版本。( 由于我這里是代理字典https key用錯(cuò)了,才導(dǎo)致的1200。所以只能先在這mark一下 )
以下是網(wǎng)上給出的解決方法:
這是一個(gè)測(cè)試TLS的控制臺(tái)命令:
nscurl --ats-diagnostics --verbose
這里能自動(dòng)測(cè)試哪種key能通過,隨便找個(gè)https的網(wǎng)站試一下吧。
附上 connectionProxyDictionary keys 參見 Table 3-7