標籤:
說點題外話:
我剛來現在這家公司的時候,老闆讓我下載一個脈脈,上去找找自己的同行,多認識些同行。其實初衷的好的,但最近這兩天我把它卸載了,不為別的,負能量太多!iOS這行自從2016就沒景氣過,在這行混,這些自己也肯定都知道。但就是受不鳥鋪天蓋地的多久沒找到工作,滿大街都是iOS程式猿這些話題。看了也給我帶不來任何的作用,你唯一能做的就是安安靜靜的做好自己該做的。自己入iOS這行也一年半過了,除去培訓的那個幾個月,真正摸爬滾打也一年多了,有時候想想,其實也沒覺得有多差,以後怎樣不知道,但至少現在,你有份工作,有口飯吃,還有時間給你去學,有什麼不知足的呢?在我自己淺薄的意識裡,編程思想都是相同的,喜歡iOS你也可能也會喜歡安卓,Java,JS,PHP等等等。。活到老,學到老,那顆不停的去學的心就是自己最大的依靠。
迴歸正題:
以前有瞭解過Runtime,不記得是幾個月前的事情了,最近又遇到這個問題,還是總結一下吧,總結的不好的地方,見諒了。。
Runtime俗稱“運行時”,項目都有分一個編譯和運行兩個狀態,這個應該瞭解。是一套底層的C語言的API。OC是一門動態語言,有些東西不會放在我們編譯的時候去處理,會等到運行時去處理。下面說的這些,建議大家隨表這個項目,匯入下面標頭檔點進去我們一起慢慢探討!
#import <objc/runtime.h>
看看他最上面:
/// An opaque type that represents a method in a class definition.typedef struct objc_method *Method; // 方法/// An opaque type that represents an instance variable.typedef struct objc_ivar *Ivar; // 變數/// An opaque type that represents a category.typedef struct objc_category *Category; // 類別也叫分類/// An opaque type that represents an Objective-C declared property.typedef struct objc_property *objc_property_t; // 屬性
定義在上面代碼的注釋裡我們說了,再往下看你就看到的是類的表示:
struct objc_class { Class isa OBJC_ISA_AVAILABILITY;#if !__OBJC2__ Class super_class OBJC2_UNAVAILABLE; const char *name OBJC2_UNAVAILABLE; long version OBJC2_UNAVAILABLE; long info OBJC2_UNAVAILABLE; long instance_size OBJC2_UNAVAILABLE; struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; struct objc_method_list **methodLists OBJC2_UNAVAILABLE; struct objc_cache *cache OBJC2_UNAVAILABLE; struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;#endif} OBJC2_UNAVAILABLE;/* Use `Class` instead of `struct objc_class *` */
Class super_class指向父類。
const char *name 類的名字long version 類的版本資訊,初始化預設為0,下面有函數class_setVersion和class_getVersion可以對它進行進行修改和讀
long info 標識。
long instance_size 類的執行個體變數的大小,包括繼承的父類的。
struct objc_ivar_list *ivars 成員變數的地址。
struct objc_method_list **methodLists
struct objc_cache *cache 指向最近使用的方法的指標struct objc_protocol_list *protocols 遵守的協議。
下面就是一系列的方法了,這裡總結常見的,在下面的代碼注釋裡面會說的比較詳細點:
#import "ViewController.h"#import <objc/runtime.h>/** * 定義一個測試的協議 */@protocol protocolTestDelegate <NSObject>@optional -(void)protocolTestDelegate;@end@interface ViewController ()/** * 定義三個測試的屬性 */@property (nonatomic,strong) NSString * testString1;@property (nonatomic,strong) NSString * testString2;@property (nonatomic,strong) NSString * testString3;@end@implementation ViewController-(void)viewDidLoad { [super viewDidLoad]; /** * 定義三個測試的成員變數 */ NSString * Stringone; NSString * Stringtwo; NSString * Stringthree;
unsigned int count; // OBJC_EXPORT objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount) // 下面是官方的注釋,大概翻譯; /** 描述一個類的屬性列表 * Describes the properties declared by a class. * * @param cls The class you want to inspect. 參數 outCount這個參數是返回了你這個屬性列表數組的長度 * @param outCount On return, contains the length of the returned array. * If \e outCount is \c NULL, the length is not returned. * 這個方法返回的是一個屬性的列表數組 * @return An array of pointers of type \c objc_property_t describing the properties * declared by the class. Any properties declared by superclasses are not included. 返回的數組包含的 outCount 指標用NULL結尾的,必須釋放這個array用free() * The array contains \c *outCount pointers followed by a \c NULL terminator. You must free the array with \c free(). * * If \e cls declares no properties, or \e cls is \c Nil, returns \c NULL and \c *outCount is \c 0. */ // 這裡傳的是 &count ,是 count 的地址,outCount是返回的數組的長度的指標,傳值就傳變數的地址,系統就把長度返回給了這個變數 // 屬性 objc_property_t * propertyList = class_copyPropertyList([self class],&count); for (unsigned int i = 0; i<count; i++) { // objc_property_t property // (nonnull const char *) const char * property = property_getName(propertyList[i]); NSLog(@"property %@",[NSString stringWithUTF8String:property]); } /** * 列印 2016-08-29 11:37:03.302 RunTimeTest[10078:132260] property testString1 2016-08-29 11:37:03.303 RunTimeTest[10078:132260] property testString2 2016-08-29 11:37:03.303 RunTimeTest[10078:132260] property testString3 */ // 方法 Method * methontList = class_copyMethodList([self class], &count); for (unsigned int i = 0 ; i<count; i++) { Method methond = methontList[i]; NSLog(@"methond %@",NSStringFromSelector(method_getName(methond))); } /** * 2016-08-29 14:01:30.458 RunTimeTest[16581:201546] methond ClassTestone 2016-08-29 14:01:30.458 RunTimeTest[16581:201546] methond ClassTesttwo 2016-08-29 14:01:30.459 RunTimeTest[16581:201546] methond ClassTesthree 2016-08-29 14:01:30.459 RunTimeTest[16581:201546] methond testString1 // testString1 get方法 2016-08-29 14:01:30.459 RunTimeTest[16581:201546] methond setTestString1: 2016-08-29 14:01:30.459 RunTimeTest[16581:201546] methond testString2 2016-08-29 14:01:30.459 RunTimeTest[16581:201546] methond setTestString2: 2016-08-29 14:01:30.459 RunTimeTest[16581:201546] methond testString3 2016-08-29 14:01:30.459 RunTimeTest[16581:201546] methond setTestString3: 2016-08-29 14:01:30.459 RunTimeTest[16581:201546] methond .cxx_destruct // 2016-08-29 14:01:30.459 RunTimeTest[16581:201546] methond didReceiveMemoryWarning 2016-08-29 14:01:30.460 RunTimeTest[16581:201546] methond viewDidLoad */ // 成員變數 Ivar * ivarList = class_copyIvarList([self class], &count); for (unsigned int i =0 ; i<count; i++) { Ivar ivar = ivarList[i]; const char *ivarName = ivar_getName(ivar); NSLog(@"Ivar %@",[NSString stringWithUTF8String:ivarName]); } /** * 2016-08-29 14:12:17.750 RunTimeTest[17233:209405] Ivar _testString1 2016-08-29 14:12:17.751 RunTimeTest[17233:209405] Ivar _testString2 2016-08-29 14:12:17.751 RunTimeTest[17233:209405] Ivar _testString3 */ __unsafe_unretained Protocol **protocolListm = class_copyProtocolList([self class], &count); for (unsigned int i =0 ; i<count; i++) { Protocol * myprotocal = protocolListm[i]; const char * protocalname = property_getName((__bridge objc_property_t)(myprotocal)); NSLog(@"protocal %@",[NSString stringWithUTF8String:protocalname]); } // Do any additional setup after loading the view, typically from a nib.}/** * 定義三個測試的方法 */-(void)ClassTestone{ NSLog(@"i am the viewcontroller methond");}-(void)ClassTesttwo{ }-(void)ClassTesthree{}- (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated.}@end
還有許多:
其實細說這塊的只是還有很多,像方法交換 、動態添加方法 、攔截調用等等等,但這個不能亂吹,我項目中暫時也沒用過,以後可能會用到吧,現在有導覽列漸層這樣的效果,把代碼給出來!
給UINavigationBar添加一個類別:
#import <objc/runtime.h>#import "UINavigationBar+Background.h"@implementation UINavigationBar (Background)// 給UINavigationBar添加動態屬性static char BackgroundKey;-(UIView *) BackgroundView{ return objc_getAssociatedObject(self, &overlayKey);}-(void)setOverlay:(UIView *) BackgroundView{ objc_setAssociatedObject(self, &BackgroundKey, BackgroundView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}- (void)NASetBackgroundColor:(UIColor *)backgroundColor{ if (!self. BackgroundView) { [self setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault]; self. BackgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, -20, [UIScreen mainScreen].bounds.size.width, CGRectGetHeight(self.bounds) + 20)]; // 比導航高二十,遮住狀態列 self. BackgroundView.userInteractionEnabled = NO; self. BackgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; // 給導航添加一個運行時屬性.uiview類型。。放置在導航的最上面 [self insertSubview:self. BackgroundView atIndex:0]; }
self. BackgroundView.backgroundColor = backgroundColor;}
-(void)cnReset{ [self setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault]; [self. BackgroundView removeFromSuperview]; self. BackgroundView = nil; }
@end
然後在 UIScrollViewDelegate 的代理方法裡面:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView { // 本質是讓導覽列添加的BackgroundView屬性根據你的scrollView的滑動範圍改變顏色 [self.navigationController.navigationBar NASetBackgroundColor:[color colorWithAlphaComponent:alpha]]; }
這是在網上看到的一個效果,就是這種導覽列的漸層:
iOS RunTime你知道了總得用一下