你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> iOS開發的10個奇襲

iOS開發的10個奇襲

編輯:IOS開發基礎

1468898303629619.jpg

本文授權轉載,作者:吳白

1.關於關鍵字volatile

一個定義為volatile的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設這個變量的值了。精確地說就是,優化器在用到這個變量時必須每次都小心地重新讀取這個變量的值,而不是使用保存在寄存器裡的備份。就像大家更熟悉的const一樣,volatile是一個類型修飾符。它是被設計用來修飾被不同線程訪問和修改的變量。如果不加入volatile,基本上會導致這樣的結果:要麼無法編寫多線程程序,要麼編譯器失去大量優化的機會。

Volatile變量具有 synchronized 的可見性特性,但是不具備原子特性。這就是說線程能夠自動發現 volatile變量的最新值。Volatile變量可用於提供線程安全,但是只能應用於非常有限的一組用例:多個變量之間或者某個變量的當前值與修改後值之間沒有約束。因此,單獨使用 volatile 還不足以實現計數器、互斥鎖或任何具有與多個變量相關的不變式(Invariants)的類(例如 “start <=end”)。

出於簡易性或可伸縮性的考慮,您可能傾向於使用 volatile變量而不是鎖。當使用 volatile變量而非鎖時,某些習慣用法更加易於編碼和閱讀。此外,volatile變量不會像鎖那樣造成線程阻塞,因此也很少造成可伸縮性問題。在某些情況下,如果讀操作遠遠大於寫操作,volatile變量還可以提供優於鎖的性能優勢。

代碼示例

volatile int i=10;
int j = i;
...
int k = i;

volatile 告訴編譯器i是隨時可能發生變化的,每次使用它的時候必須從i的地址中讀取,因而編譯器生成的可執行碼會重新從i的地址讀取數據放在k中。編譯器在產生release版可執行碼時會進行編譯優化,加volatile關鍵字的變量有關的運算,將不進行編譯優化。而優化做法是,由於編譯器發現兩次從i讀數據的代碼之間的代碼沒有對i進行過操作,它會自動把上次讀的數據放在k中。而不是重新從i裡面讀。這樣以來,如果i是一個寄存器變量或者表示一個端口數據就容易出錯,所以說volatile可以保證對特殊地址的穩定訪問,不會出錯。

int square(volatile int *ptr) { return *ptr * *ptr; }

這段代碼的目的是用來返指針ptr指向值的平方,但是,由於ptr指向一個volatile型參數,編譯器將產生類似下面的代碼:

int square(volatile int *ptr) {
 int a,b;
 a = *ptr;
 b = *ptr;
 return a * b;
}

由於*ptr的值可能被意想不到地該變,因此a和b可能是不同的。結果,這段代碼可能返不是你所期望的平方值!正確的代碼如下:

long square(volatile int *ptr) { int a; a = *ptr; return a * a; }

下面是volatile變量的幾個使用:

  • 並行設備的硬件寄存器(如:狀態寄存器)

  • 一個中斷服務子程序中會訪問到的非自動變量(Non-automatic variables)

  • 多線程應用中被幾個任務共享的變量

那麼問題來了:

  • 一個參數既可以是const還可以是volatile嗎?答案是是的。一個例子是只讀的狀態寄存器。它是volatile因為它可能被意想不到地改變。它是const因為程序不應該試圖去修改它。

  • 一個指針可以是volatile 嗎?答案是是的。盡管這並不很常見。一個例子是當一個中服務子程序修該一個指向一個buffer的指針時。

在編寫多線程程序中使用volatile的關鍵點:

1)將所有的共享對象聲明為volatile;

2)不要將volatile直接作用於基本類型;

3)當定義了共享類的時候,用volatile成員函數來保證線程安全;

在多線程中,我們可以利用鎖的機制來保護好資源臨界區。在臨界區的外面操作共享變量則需要volatile,在臨界區的裡面則non-volatile了。

2.關鍵字const的位置

const意味著”只讀”,分析下面的含義:

const int a;
int const a;// 前兩個的作用是一樣,a是一個常整型數。
const int *a;// 第三個意味著a是一個指向常整型數的指針(整型數是不可修改的,但指針可以)
int * const a;// 第四個意思a是一個指向整型數的常指針(指針指向的整型數是可以修改的,但指針是不可修改的)
int const * const a;
// a是一個指向常整型數的常指針(指針指向的整型數是不可修改的,同時指針也是不可修改的)。
//表示a是一個指針常量,初始化的時候必須固定指向一個int常量或者int變量,之後就不能再指向別的地方了,它總是把它所指向的目標當作一個int常量。
//也可以寫成const int* const a;含義相同。

合理地使用關鍵字const可以使編譯器很自然地保護那些不希望被改變的參數,防止其被無意的代碼修改。這樣可以減少bug的出現。欲阻止一個變量被改變,可以使用 const 關鍵字。

在定義 const 變量時,通常需要對它進行初始化,因為以後就沒有機會再去改變它了;對指針來說,可以指定指針本身為 const,也可以指定指針所指的數據為 const,或二者同時指定為 const;在一個函數聲明中,const 可以修飾形參,表明它是一個輸入參數,在函數內部不能改變其值;對於類的成員函數,若指定其為 const 類型,則表明其是一個常函數,不能修改類的成員變量;對於類的成員函數,有時候必須指定其返回值為 const 類型,以使得其返回值不為“左值”。

3.滑動的時候隱藏navigation bar

navigationController.hidesBarsOnSwipe = Yes;

4. 消除導航條返回鍵帶的title

[[UIBarButtonItem appearance] setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -60)
                                                 forBarMetrics:UIBarMetricsDefault];

5. 將Navigationbar變成透明而不模糊

[self.navigationController.navigationBar setBackgroundImage:[UIImage new]
                         forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar .shadowImage = [UIImage new];
self.navigationController.navigationBar .translucent = YES;

6. static

函數體內 static 變量的作用范圍為該函數體,不同於 auto 變量,該變量的內存只被分配一次,因此其值在下次調用時仍維持上次的值;在模塊內的 static 全局變量可以被模塊內所用函數訪問,但不能被模塊外其它函數訪問;在模塊內的 static 函數只可被這一模塊內的其它函數調用,這個函數的使用范圍被限制在聲明它的模塊內;在類中的 static 成員變量屬於整個類所擁有,對類的所有對象只有一份拷貝;在類中的 static 成員函數屬於整個類所擁有,這個函數不接收 this 指針,因而只能訪問類的static 成員變量。

7.用一個pan手勢來代替UISwipegesture的各個方向

- (void)pan:(UIPanGestureRecognizer *)sender
{
typedef NS_ENUM(NSUInteger, UIPanGestureRecognizerDirection) {
UIPanGestureRecognizerDirectionUndefined,
UIPanGestureRecognizerDirectionUp,
UIPanGestureRecognizerDirectionDown,
UIPanGestureRecognizerDirectionLeft,
UIPanGestureRecognizerDirectionRight
};
static  UIPanGestureRecognizerDirection direction = UIPanGestureRecognizerDirectionUndefined;
switch (sender.state) {
case  UIGestureRecognizerStateBegan: {
if  (direction == UIPanGestureRecognizerDirectionUndefined) {
CGPoint velocity = [sender velocityInView:recognizer.view];
BOOL isVerticalGesture = fabs(velocity.y) > fabs(velocity.x);
if (isVerticalGesture) {
    if (velocity.y > 0) {
    direction = UIPanGestureRecognizerDirectionDown;
    }
    else  {
    direction = UIPanGestureRecognizerDirectionUp;
    }
}
else
{
if (velocity.x > 0) {
direction = UIPanGestureRecognizerDirectionRight;
}
else
{
direction = UIPanGestureRecognizerDirectionLeft;
}
}
}
break ;
}
case UIGestureRecognizerStateChanged: {
switch (direction) {
case UIPanGestureRecognizerDirectionUp: {
[self handleUpwardsGesture:sender];
break ;
}
case UIPanGestureRecognizerDirectionDown: {
[self handleDownwardsGesture:sender];
break;
}
case  UIPanGestureRecognizerDirectionLeft: {
[self handleLeftGesture:sender];
break;
}
case UIPanGestureRecognizerDirectionRight: {
[self handleRightGesture:sender];
break ;
}
default : {
break;
}
}
break;
}
case  UIGestureRecognizerStateEnded: {
direction = UIPanGestureRecognizerDirectionUndefined;
break;
}
default:
break;
}
}

8. 拉伸圖片不變形

1468898521688776.gif

等同於:

[[UIImage imageNamed:@""] stretchableImageWithLeftCapWidth:10 topCapHeight:10];
[[UIImage imageNamed:@""] resizableImageWithCapInsets:UIEdgeInsetsMake(10, 10, 10, 10)];

9. Gif圖片顯示優化

1170656-956bd6681b580206.gif

FLAnimatedImage可以幫你完成GIF的顯示處理。解決GIF顯示卡頓的情況。

FLAnimatedImage *image = [FLAnimatedImage animatedImageWithGIFData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif"]]];
FLAnimatedImageView *imageView = [[FLAnimatedImageView alloc] init];
imageView.animatedImage = image;
imageView.frame = CGRectMake(0.0, 0.0, 100.0, 100.0);
[self.view addSubview:imageView];

使用就是這麼簡單。

10. CollectionView實現tableview的懸停header

1170656-e32d0d953b7bbf48.gif

CSStickyHeaderFlowLayout可以解決您的疑問。

#import "CSStickyHeaderFlowLayout.h"
- (void)viewDidLoad {
 [super viewDidLoad]; // Locate your layout
CSStickyHeaderFlowLayout *layout = (id)self.collectionViewLayout;
if ([layout isKindOfClass:[CSStickyHeaderFlowLayout class]]) {
layout.parallaxHeaderReferenceSize = CGSizeMake(320, 200);
 }
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { // Check the kind if it's CSStickyHeaderParallaxHeader
if ([kind isEqualToString:CSStickyHeaderParallaxHeader]) {
UICollectionReusableView *cell = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"header" forIndexPath:indexPath];
 return cell;
}
}

就是這麼簡單。

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved