欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

iOS開發(fā)中使用UIScrollView實現(xiàn)無限循環(huán)的圖片瀏覽器

 更新時間:2016年03月16日 14:27:17   作者:KenshinCui  
這篇文章主要介紹了iOS開發(fā)中使用UIScrollView實現(xiàn)無限循環(huán)的圖片瀏覽器的方法,感興趣的小伙伴們可以參考一下

一、概述
UIKit框架中有大量的控件供開發(fā)者使用,在iOS開發(fā)中不僅可以直接使用這些控件還可以在這些控件的基礎上進行擴展打造自己的控件。在這個系列中如果每個控件都介紹一遍確實沒有必要,所謂授人以魚不如授人以漁,這里會盡可能讓大家明白其中的原理,找一些典型的控件進行說明,這樣一來大家就可以觸類旁通。今天我們主要來看一下UIScrollView的內容:

  • UIView
  • UIScrollView
  • 實戰(zhàn)--圖片瀏覽器

二、UIView
在熟悉UIScrollView之前很有必要說一下UIView的內容。在上一篇文章也簡單的對UIView進行了介紹,但是由于那篇文章的主要內容是給大家一個iOS開發(fā)的總體印象,因此并沒有系統(tǒng)的介紹。另外由于UIScrollView的父類是UIView,所有在討論UIScrollView之前也很有必要把UIView的知識給補充上,這樣大家在使用UIScrollView的某些方法時也不至于無從下手。

既然UIView是所有控件的父類,那么對于一些常用的方法我們很有必要弄清楚,其實在Xcode中要了解一個類有哪些屬性和方法特別簡單,只要按住apple鍵點擊類名就可以定位到這個類中查看相關定義(在日后的開發(fā)中我們會經常這么來做,畢竟要記住iOS開發(fā)中所有的API是不現(xiàn)實的,有些API我們可以通過這種方法來查找),例如我們可以查看這個類的內容:

當然UIView的定義文件(.h文件)也是相當長的,我們如果全部截圖也沒有意義。這里列出常用的屬性和方法。

注意上面所有的位置屬性都是相對于其父控件而言(不是相對于屏幕而言),多數(shù)屬性比較簡單這里不再詳細解釋,我們重點解釋一下autoresizingMask、transform屬性。

三、autoresizingMask

autoresizingMask這個屬性一般我們進行屏幕旋轉的時候經常用到,它的值是一個枚舉類型:

typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
 UIViewAutoresizingNone   = 0, //不進行自動調整
 UIViewAutoresizingFlexibleLeftMargin = 1 << 0, //自動調整與superview左側距離,右側距離保持不變
 UIViewAutoresizingFlexibleWidth = 1 << 1, //自動調整控件自身寬度,保證與superview左右距離不變
 UIViewAutoresizingFlexibleRightMargin = 1 << 2, //自動調整與superview右側距離,左側距離保持不變
 UIViewAutoresizingFlexibleTopMargin = 1 << 3, //自動調整與superview頂部距離,底部距離保持不變
 UIViewAutoresizingFlexibleHeight = 1 << 4, //自動調整控件自身高度,保證與superview上下距離不變
 UIViewAutoresizingFlexibleBottomMargin = 1 << 5 //自動調整與superview底部距離,頂部距離保持不變
};

通過注釋大家應該大概了解每個枚舉值的意義,但是我們知道枚舉經常進行按位或操作(“|”),例如如果autoresizingMask=UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleLeftMargin那么iOS如何處理呢?此時會自動調整左邊的距離和控件自身寬度,右側距離不變,同時保證左側距離和控件寬度同等比例的調整(延長或縮短)。例如在iPhone 5中,如果一個按鈕假設自身寬度為200,左右側距離均為60(左側和寬度比例3:10),當從豎屏旋轉到橫屏的時候(此時寬度由320變?yōu)?68,注意如果有狀態(tài)欄則寬度變?yōu)?68-20=548),由于右側邊距不變?yōu)?0,根據比例左側邊距應該是(568-60)*(3/13)=117,寬度為:(568-60)*(10/13)=391。

請看下面的代碼(下面例子通過純代碼方式創(chuàng)建iOS應用,并且自定義一個KCMainViewController):

AppDelegate.m

//
// AppDelegate.m
// UIViewAndUIScrollView
//
// Created by Kenshin Cui on 14-2-23.
// Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "AppDelegate.h"
#import "KCMainViewController.h"
#import "KCTransformViewController.h"

@interface AppDelegate ()

@end

@implementation AppDelegate
  

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
 
 self.window=[[UIWindow alloc]initWithFrame:[UIScreen mainScreen].applicationFrame];
 
 KCMainViewController *mainController=[[KCMainViewController alloc]init];
 self.window.rootViewController=mainController;
 self.window.backgroundColor=[UIColor colorWithRed:249/255.0 green:249/255.0 blue:249/255.0 alpha:1];

 [self.window makeKeyAndVisible];
 
 return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application {
 // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
 // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
 // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
 // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
 // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
 // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}

- (void)applicationWillTerminate:(UIApplication *)application {
 // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

@end

KCMainViewController.m

//
// KCMainViewController.m
// UIViewAndUIScrollView
//
// Created by Kenshin Cui on 14-2-23.
// Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "KCMainViewController.h"

@interface KCMainViewController (){
 UIButton *_btn; //私有變量
}

@end

@implementation KCMainViewController

- (void)viewDidLoad {
 [super viewDidLoad];
 
 //添加一個Button
 _btn=[[UIButton alloc]initWithFrame:CGRectMake(60, 100, 200, 50)];
 _btn.backgroundColor=[UIColor orangeColor];
 [_btn setTitle:@"Hello,world!" forState:UIControlStateNormal];
 _btn.autoresizingMask=UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleLeftMargin;
 [self.view addSubview:_btn];
 
}

#pragma mark 屏幕旋轉事件
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
 NSLog(@"%@",NSStringFromCGRect(_btn.frame));
}
@end

在上面的代碼中設置了window的背景為灰色,雖然上面有一個UIView但是我們可以看到最終效果是灰色的,這說明UIView默認是透明的。另外定義了一個私有成員變量_btn,這種定義方式大家以后會經常用到。

運行效果:

豎屏

橫屏

 

注意上面執(zhí)行前請先隱藏iOS狀態(tài)欄目,全局隱藏iO狀態(tài)欄的方法:

1.在info.plist 中設置Status bar is initially hidden為YES

2.在info.plist中設置View controller-based status bar appearance 為NO

四、transform

transform我們一般稱為形變屬性,其本質是通過矩陣變化改變控件的大小、位置、角度等,這里我們通過一個例子來看一下具體的操作,在下面的例子中我們也會看到UIImageView控件的常用操作。

KCTransformViewController.m

//
// KCTransformViewController.m
// UIViewAndUIScrollView
//
// Created by Kenshin Cui on 14-2-23.
// Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "KCTransformViewController.h"
//定義rgb顏色
#define NORMAL_COLOR [UIColor colorWithRed:75/255.0 green:160/255.0 blue:253/255.0 alpha:1]
#define HIGHLIGHTED_COLOR [UIColor colorWithRed:197/255.0 green:221/225.0 blue:249/225.0 alpha:1]
//按鈕操作
typedef void(^ ButtonHandle)();

@interface KCTransformViewController (){
 UIImageView *_imageView;//圖片控件
 UIButton *_btnRotation;//旋轉按鈕
 UIButton *_btnScale;//縮放按鈕
 UIButton *_btnTranslate;//移動按鈕
}

@end

@implementation KCTransformViewController

- (void)viewDidLoad {
 [super viewDidLoad];
 
 [self addImageView];
 [self addRotationButton];
 [self addScaleButton];
 [self addTranslateButton];
 
}

#pragma mark 添加圖片控件
-(void)addImageView{
 //直接使用圖片名稱,系統(tǒng)會自動到資源文件中找到對應的文件
 UIImage *image=[UIImage imageNamed:@"promo_ios8.png"];
 //如果使用initWithImage進行初始化則控件大小會自動設置成圖片大小
 _imageView=[[UIImageView alloc]initWithImage:image];
 _imageView.frame=CGRectMake(20, 20, 280, 154);
 //設置內容填充模式為等比例填充
 _imageView.contentMode=UIViewContentModeScaleAspectFit;
 //self.view就是每個視圖控制器中的view屬性
 [self.view addSubview:_imageView];
}

#pragma mark 添加旋轉按鈕
-(void)addRotationButton{
 _btnRotation=[self getButton];
 _btnRotation.frame=CGRectMake(20, 400, 280, 30);
 [_btnRotation setTitle:@"旋轉" forState:UIControlStateNormal];
 //添加按鈕點擊事件
 [_btnRotation addTarget:self action:@selector(rotation:) forControlEvents:UIControlEventTouchUpInside];
 [self.view addSubview:_btnRotation];
}

#pragma mark 添加縮放按鈕
-(void)addScaleButton{
 //在上面一個按鈕位置的基礎上確認當前位置
 CGRect scaleButtonFrame=_btnRotation.frame;
 scaleButtonFrame.origin.y+=40;
 _btnScale =[self getButton];
 _btnScale.frame=scaleButtonFrame;
 [_btnScale setTitle:@"縮放" forState:UIControlStateNormal];
 //添加按鈕點擊事件
 [_btnScale addTarget:self action:@selector(scale:) forControlEvents:UIControlEventTouchUpInside];
 [self.view addSubview:_btnScale];
}

#pragma mark 添加移動按鈕
-(void)addTranslateButton{
 CGRect translateButtonFrame=_btnScale.frame;
 translateButtonFrame.origin.y+=40;
 _btnTranslate =[self getButton];
 _btnTranslate.frame=translateButtonFrame;
 [_btnTranslate setTitle:@"移動" forState:UIControlStateNormal];
 [_btnTranslate addTarget:self action:@selector(translate:) forControlEvents:UIControlEventTouchUpInside];
 [self.view addSubview:_btnTranslate];
 
}

#pragma mark 圖片旋轉方法,注意參數(shù)中的btn表示當前點擊按鈕
-(void)rotation:(UIButton *)btn{
 [self animation:^{
 //注意旋轉角度必須是弧度,不是角度
 CGFloat angle=M_PI_4;//M開頭的宏都是和數(shù)學(Math)相關的宏定義,M_PI_4表示四分之派,M_2_PI表示2派
 //使用CGAffineTransformMakeRotation獲得一個旋轉角度形變
 //但是需要注意tranform的旋轉不會自動在原來的角度上進行疊加,所以下面的方法旋轉一次以后再點擊按鈕不會旋轉了
 //_imageView.transform=CGAffineTransformMakeRotation(angle);
 //利用CGAffineTransformRotate在原來的基礎上產生一個新的角度(當然也可以定義一個全局變量自己累加)
 _imageView.transform=CGAffineTransformRotate(_imageView.transform, angle);
 
 }];
}

#pragma mark 圖片縮放方法
-(void)scale:(UIButton *)btn{
// [self animation:^{
// CGFloat scalleOffset=0.9;
// //_imageView.transform=CGAffineTransformMakeScale(scalleOffset, scalleOffset);
// _imageView.transform= CGAffineTransformScale(_imageView.transform, scalleOffset, scalleOffset);
// }];
 //通常我們使用UIView的靜態(tài)方法實現(xiàn)動畫而不是自己寫一個方法
 [UIView animateWithDuration:0.5 animations:^{
 CGFloat scalleOffset=0.9;
 //_imageView.transform=CGAffineTransformMakeScale(scalleOffset, scalleOffset);
 _imageView.transform= CGAffineTransformScale(_imageView.transform, scalleOffset, scalleOffset);
 }];
}

#pragma mark 圖片移動方法
-(void)translate:(UIButton *)btn{
 [self animation:^{
 CGFloat translateY=50;
 //_imageView.transform=CGAffineTransformMakeTranslation(0, translateY);
 _imageView.transform=CGAffineTransformTranslate(_imageView.transform, 0, translateY);
 }];
}

#pragma mark 動畫執(zhí)行方法,注意這里可以使用UIView的animateWithDuration方法代替這里只是為了演示
-(void)animation:(ButtonHandle)handle{
 //開始動畫
 [UIView beginAnimations:@"animation" context:nil];
 //設置動畫執(zhí)行時間
 [UIView setAnimationDuration:0.5];
 
 handle();
 
 //執(zhí)行動畫操作
 [UIView commitAnimations];
 
}

#pragma mark 取得一個按鈕,統(tǒng)一按鈕樣式
-(UIButton *)getButton{
 UIButton *button =[[UIButton alloc]init ];
 //設置正常狀態(tài)下字體顏色
 [button setTitleColor:NORMAL_COLOR forState:UIControlStateNormal];
 //設置高亮狀態(tài)下的字體顏色
 [button setTitleColor:HIGHLIGHTED_COLOR forState:UIControlStateHighlighted];
 return button;
}

@end

1)、獲得CGAffineTransform有多種方法,例如使用CGAffineTransformMake,但是對于矩陣操作相對比較麻煩,事實上iOS已經為我們準備好了三個方法:CGAffineTransformMakeRotation(旋轉)、CGAffineTransformMakeScale(縮放)、CGAffineTransformMakeTranslation(移動);
2)、transform進行旋轉、縮放、移動的時候不是在原來的基礎上增量形變的,因此如果需要持續(xù)在原來的基礎上旋轉、縮放、移動那么每次需要在原來的基礎上增加或減少。當然,我們可以定義一個全局變量進行累加,但是事實上iOS已經為我們提供好了三個對應的方法,分別用于在原來的角度、縮放、移動位置的基礎上做出修改:CGAffineTransformRotate、CGAffineTransformScale、CGAffineTransformTranslate;
3)、Objc語法規(guī)定不允許直接修改一個對象的結構體屬性的成員,只能給這個屬性直接賦值為一個結構體類型,例如上面的代碼中如果寫成“_btnRotation.frame.origin.x=380;”是不正確的;
4)、上面的代碼中我們用到了UIView的動畫相關方法,在iOS開發(fā)中動畫開發(fā)異常簡單,而且動畫和邏輯處理是完全分離的,只要在兩個動畫方法之間修改一個控件的屬性那么當代碼執(zhí)行時就會自動添加動畫效果,為了復習前面的block這里我們實現(xiàn)了一個類似于animation方法,類似于UIView的animateWithDuration靜態(tài)方法的功能,僅僅為了說明它的實現(xiàn)原理,實際開發(fā)中可以直接調用animateWithDuration即可(而且它有多種重載);
運行效果:

注意在iOS開發(fā)中推薦使用png圖片,iOS會對png圖片進行優(yōu)化。

五、UIScrollView
通過上面的介紹相信大家對于UIView的基本操作應該比較熟悉了,那么下面就看一下UIView的子控件UIScrollView 。顧名思義,這是一個可以處理滾動操作的視圖,UIScrollView在開發(fā)過程中使用很頻繁,而且它也經常作為其他控件的子控件,例如UITableView就繼承自UIScrollView。 我們還是先看一下UIScrollView的常用屬性和方法:

contentSize、contentInset、contentOffset在開發(fā)中會經常使用,為了幫助大家理解這里以圖形的形式展現(xiàn)三者之間的關系:

關于上面列出的幾個方法,我們有必要說一下它們的執(zhí)行順序:

a.如果我們拖動一個UIScrollView中的子控件移動的時候它的執(zhí)行順序如下:開始拖拽,滾動,滾動…,停止拖拽,將要停止?jié)L動,滾動,滾動…,停止?jié)L動。

紅色部分有可能執(zhí)行也有可能不執(zhí)行,關鍵看你拖拽的停止的時候是突然停止還是有一段慣性讓他繼續(xù)執(zhí)行(就好像剎車一樣,如果是急剎車就沒有后面的慣性滑動了,如果是慢慢踩剎車可能會有一段滑動距離)。但是不管怎么樣滾動事件會一直執(zhí)行,因此如果在這個事件中進行某種操作一定要注意性能。

b.如果我們縮放UIScrollView的子控件的時候它的執(zhí)行順序如下:開始縮放,滾動,滾動…,停止縮放。同樣在這個過程中滾動事件會一直調用(當然如果縮放過程中手指有別的動作也可能會觸發(fā)其他事件,這個大家可以自己體會一下)。

下面我們簡單做一個例子

KCScrollViewController.h

//
// KCScrollViewController.h
// UIViewAndUIScrollView
//
// Created by Kenshin Cui on 14-2-23.
// Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface KCScrollViewController : UIViewController

@property (nonatomic,strong) UIScrollView *scrollView;

@property (nonatomic,strong) UIImageView *imageView;

@end

KCScrollViewController.m

//
// KCScrollViewController.m
// UIViewAndUIScrollView
//
// Created by Kenshin Cui on 14-2-23.
// Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "KCScrollViewController.h"

//實現(xiàn)UIScrollView代理
@interface KCScrollViewController ()<UIScrollViewDelegate>

@end

@implementation KCScrollViewController

- (void)viewDidLoad {
 [super viewDidLoad];
 
 //添加scrollView控件
 //注意UIScreen代表當前屏幕對象,其applicationFrame是當前屏幕內容區(qū)域
 _scrollView =[[UIScrollView alloc]initWithFrame:[UIScreen mainScreen].applicationFrame];
 //_scrollView.backgroundColor=[UIColor redColor];
 _scrollView.contentMode=UIViewContentModeScaleToFill;
 [self.view addSubview:_scrollView];
 
 
 //添加圖片控件
 UIImage *image=[UIImage imageNamed:@"wwdc14-labs-hero-background.jpg"];
 _imageView=[[UIImageView alloc]initWithImage:image];
 [_scrollView addSubview:_imageView];
 
 
 
 //contentSize必須設置,否則無法滾動,當前設置為圖片大小
 _scrollView.contentSize=_imageView.frame.size;
 
 //實現(xiàn)縮放:maxinumZoomScale必須大于minimumZoomScale同時實現(xiàn)viewForZoomingInScrollView方法
 _scrollView.minimumZoomScale=0.6;
 _scrollView.maximumZoomScale=3.0;
 //設置代理
 _scrollView.delegate=self;
 

 //邊距,不屬于內容部分,內容坐標(0,0)指的是內容的左上角不包括邊界
 //_scrollView.contentInset=UIEdgeInsetsMake(10, 20, 10, 20);
 
 //顯示滾動內容的指定位置
 //_scrollView.contentOffset=CGPointMake(10, 0);
 
 //隱藏滾動條
 _scrollView.showsHorizontalScrollIndicator=NO;
 _scrollView.showsVerticalScrollIndicator=NO;
 
 //禁用彈簧效果
 //_scrollView.bounces=NO;
}

#pragma mark 實現(xiàn)縮放視圖代理方法,不實現(xiàn)此方法無法縮放
-(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
 return _imageView;
}
-(void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView{
 NSLog(@"scrollViewWillBeginDecelerating");
}
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
 NSLog(@"scrollViewDidEndDecelerating");
}
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
 NSLog(@"scrollViewWillBeginDragging");
}
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
 NSLog(@"scrollViewDidEndDragging");
}
-(void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view{
 NSLog(@"scrollViewWillBeginZooming");
}
-(void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale{
 NSLog(@"scrollViewDidEndZooming");
}
//-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
// NSLog(@"scrollViewDidScroll");
//}

#pragma mark 當圖片小于屏幕寬高時縮放后讓圖片顯示到屏幕中間
-(void)scrollViewDidZoom:(UIScrollView *)scrollView{
 CGSize originalSize=_scrollView.bounds.size;
 CGSize contentSize=_scrollView.contentSize;
 CGFloat offsetX=originalSize.width>contentSize.width?(originalSize.width-contentSize.width)/2:0;
 CGFloat offsetY=originalSize.height>contentSize.height?(originalSize.height-contentSize.height)/2:0;

 _imageView.center=CGPointMake(contentSize.width/2+offsetX, contentSize.height/2+offsetY);
}

@end

運行效果如下:

默認情況下縮放后的內容會放到UIScrollView的內容起始位置,所以如果要想縮放后內容放到中間我們必須自己維護它的位置,上面已經給出了設置方法。

擴展—ARC

iOS5之后引入了ARC特性,程序中不用自己retain、release、autorelease操作,編譯器會自動為你管理內存,編譯時自動加上內存釋放的代碼,使用起來很方便。ARC是編譯器特性,而不是iOS運行時特性,其實質還是手動管理內存,只是相應內存管理的代碼編譯器會自動生成而已。由于ARC是編譯器特性,因此它管理內存的規(guī)則和之前ObjC內存管理是類似的,只要有一個對象引用(強引用)指向這個對象,那么這個對象就不會被釋放。

在開啟ARC之后我們可以使用四個關鍵字修飾我們的成員變量、局部變量和屬性:

strong(修飾變量用__strong):強引用,相當于原來的retain,每次賦值引用計數(shù)器加1,只要指針引用這個對象,這個對象就不會被銷毀;
weak(修飾變量用__weak):弱引用,相當于assign,和assign不同的是當對象釋放后該變量會設置為nil防止野指針(雖然之前講過的內容中assign都是應用于基本數(shù)據類型,其實它也完全可以修飾對象類型的屬性);
unsafe_unretained(修飾變量用__unsafe_unretained):和weak類似,區(qū)別就是如果對象釋放后它不會像weak一樣自動將指針設置為nil,有可能出現(xiàn)野指針;
__autoreleasing(只能修飾變量不能修飾屬性):修飾一個對象在使用完之后自動釋放,通常用于延遲釋放內存,同在MRC下調用對象的autorelease方法是等效的;
注意:

除了weak(注意不是__weak)之外其他的修飾符在非ARC(MRC)下使用也不會報錯,但是這么做并沒有什么意義,因為在編譯時會被忽略。舉例來說:在MRC下使用__autoreleasing修飾一個對象也不會自動釋放,而是應該使用autorelease方法。同樣的,在MRC下使用__strong來修飾一個變量也同樣是會直接忽略這個關鍵字;
unsafe_unretained(或者__unsafe_unretained)和weak(或__weak)的區(qū)別不大,只是weak(或__weak)做釋放之后會將變量設置為nil避免野指針,之所以目前兩個關鍵字還存在主要是因為后者在在iOS5.0及l(fā)ion之后才出現(xiàn),出于兼容性考慮,因此推薦使用weak或__weak;
__autoreleasing主要用于函數(shù)參數(shù)是ObjC對象指針的情況下(也就是參數(shù)”NSObject **obj”類型,指針的指針),典型的應用就是NSError的使用。在這種情況下,經常需要在函數(shù)內部重新創(chuàng)建一個對象給傳入的參數(shù)賦值(修改參數(shù)內容),如果使用__autorelesing參數(shù)編譯器在處理內部函數(shù)時會使用自動釋放池,即保證內部對象能夠正常釋放又可以修改外部變量。之所以很多時候使用NSError作為參數(shù)傳遞到一些方法中沒有將變量聲明為__autoreleasing是因為編譯器已經自動做了處理(因此,如果考慮到性能推薦還是加上此參數(shù));
strong和weak在iOS開發(fā)過程中經常使用,這里簡單看一個例子(注意這兩個參數(shù)仍然可以修飾屬性,意義是完全一樣的在此不再演示)

KCPerson.h

//
// KCPerson.h
// ARC
//
// Created by Kenshin Cui on 14-2-23.
// Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface KCPerson : NSObject

@property (nonatomic,assign) int no;

@end

KCPerson.m

//
// KCPerson.m
// ARC
//
// Created by Kenshin Cui on 14-2-23.
// Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "KCPerson.h"

@implementation KCPerson

-(NSString *)description{
 return [NSString stringWithFormat:@"no=%i",_no];
}

@end

main.m

//
// main.m
// ARC
//
// Created by Kenshin Cui on 14-2-23.
// Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "KCPerson.h"

int main(int argc, const char * argv[]) {
 @autoreleasepool {
 
 //strong
 __strong KCPerson *person1=[[KCPerson alloc]init];
 __strong KCPerson *person2=person1;
 person1.no=1;
 NSLog(@"%@",person2); //結果:no=1
 person1=nil;
 NSLog(@"%@",person2); //結果:no=1
 
 
 //weak
 __strong KCPerson *person3=[[KCPerson alloc]init];
 __weak KCPerson *person4=person3;
 person3.no=3;
 NSLog(@"%@",person4); //結果:no=3
 person3=nil;
 NSLog(@"%@",person4); //結果:(null)

 }
 return 0;
}

由于person1和person2都指向一個對象并且都是強引用,因此當person1設置為nil時對象仍然不會釋放,所以此時person2還是指向這個對象,可以正常輸出;person3和它指向的對象是強引用,而person4是弱引用,因此當person3設置為nil后,對象沒有了強引用就會釋放,此時再打印person4自然就是null。為了說明strong和weak的使用,下面使用圖形方式描繪上面的情況:

strong--person1和person2的關系

weak--person3和person4的關系

由此得出如下結論:

1、不管是怎么管理內存都是針對對象類型而言(無論是strong,weak都不能應用到基本數(shù)據類型),對于基本數(shù)據類型直接聲明為assign就可以了,它不需要我們自己管理內存;
2、所有的指針變量默認都是__strong類型,因此我們通常省略不寫__strong;
3、如果一個對象沒有強引用之后即使存在弱引用它也會被釋放,與此同時弱引用將被設置為nil;
回過頭來我們看一下前面UIScrollView部分的幾個屬性都設置成了strong,如果設置成weak行不行呢?答案是否定的。如果我們設置成weak,Xcode首先就會給出提出“Assigning retained object to weak variable; object will be released after assignment”,就是說ObjC對象賦值給一個弱引用變量,賦值之后對象會立即被銷毀。其實根據前面介紹的內容很容易理解,就拿上面的scrollView屬性來說,如果設置為weak,當使用“_scrollView =[[UIScrollView alloc]initWithFrame:[UIScreen mainScreen].applicationFrame];”給這個變量賦值,根據前面的知識如果一個對象沒有了強引用就會被銷毀,賦值完成后運行時看到這個對象只有一個弱引用_scrollView自然就會銷毀這個對象,因此如果運行上面的程序就達不到之前看到的效果了。

但是如果使用storyboard來設計界面的時候,我們會發(fā)現(xiàn)系統(tǒng)默認生成的屬性就是weak,此時為什么不會銷毀呢?那是因為它的頂層對象保持了一個強引用strong,因此這個對象不會被銷毀。這樣一來我們得出如下結論:

1、在iOS開發(fā)中使用strong、weak代替之前的retain、assign(基本類型使用assign);
2、如果一個屬性使用IBOutlet修飾(也就是此屬性時strongboard中組件)那么使用weak;
3、如果一個屬性不是storyboard組件(一般純代碼編寫界面時),使用strong;

六、UIScrollView實戰(zhàn)
前面介紹了iOS中UIKit的一些簡單知識,這里我們一起利用前面的知識做一個例子--圖片無限循環(huán)滾動。在這個例子中我們需要解決如下兩個問題:

如何無限循環(huán)?

我們知道在UIScrollView中如果放置其他控件后,只要設置contentSize之后這些圖片就可以滾動。如果要讓圖片無限循環(huán)那么只有兩種辦法,一種是無限循環(huán)疊加圖片,另一種就是如果最后一張圖片瀏覽完立即顯示第一張圖片。很明顯第一種方法是不現(xiàn)實的,我們考慮使用第二種方式。其實使用第二種方式實現(xiàn)原理比較簡單,只要在圖片前后各放一張圖片即可(此時共有n+2個圖片在UIScrollView中)。例如我們有5張圖片,只要使用7個UIImageView依次存放:圖片5,圖片1,圖片2,圖片3,圖片4,圖片5,圖片1。當從圖片1滾動到圖片5時由于最后一張是圖片1就給用戶一種無限循環(huán)的感覺,當這張圖完全顯示后我們迅速將UIScrollView的contentOffset設置到第二個UIImageView,也就是圖片1,接著用戶可以繼續(xù)向后滾動。當然向前滾動原理完全一樣,當滾動到第一張圖片(圖片5)就迅速設置UIScrollView的contentOffset顯示第6張圖(圖片5)。為了方便說明請看下面的示意圖(注意示意圖由于寬度有限只描述了3張圖片顯示的情景):

如何優(yōu)化性能?

無限循環(huán)實現(xiàn)了,但是我們知道如果圖片過多這些圖片勢必全部加載到內存,這是我們不愿意看到的,此時我們需要優(yōu)化上面的方案。其實從上面的方案我們也可以看出端倪,我們完全沒必要創(chuàng)建n+2個UIImageView,其實3個已經足夠(事實上也可以用兩個實現(xiàn),大家不妨自己思考一下),只要一直保持顯示中間的UIImageView,滾動時動態(tài)更改三個UIImageView的圖片即可。例如三個UIImageView默認放圖片5、圖片1、圖片2,當前顯示中間的UIImageView,也就是圖片1,。如果向后滾動那么就會顯示圖片2,當圖片2顯示完整后迅速重新設置三個UIImageView的內容為圖片1、圖片2、圖片3,然后通過contentOffset設置顯示中間的UIImageView,也就是圖片2。繼續(xù)向后看到圖片3,當圖片3滾動完成迅速重新設置3個UIImageView的內容為圖片2、圖片3、圖片4,然后設置contentOffset顯示中間的UIImageView,也就是圖片3。當然,向前滾動原理完全一樣,如此就給用戶一種循環(huán)錯覺,而且不占用過多內存。

下面給出具體的實現(xiàn),在這個程序中除了UIscrollView我們還可以看到UIPageControl的使用,實現(xiàn)并不復雜。首先我們需要將圖片信息存儲到plist文件中(日后方便擴展),并且設置plist的key表示圖片的名稱,value代表對應的圖片描述,這個描述我們需要展示在界面上方。具體內容如下:

imageInfo.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
 <key>0.jpg</key>
 <string>iphone 5s</string>
 <key>1.jpg</key>
 <string>iphone 5c</string>
 <key>2.jpg</key>
 <string>ipad min with retain</string>
 <key>3.jpg</key>
 <string>ipad air</string>
 <key>4.jpg</key>
 <string>ipod</string>
 <key>5.jpg</key>
 <string>ipod touch</string>
 <key>6.jpg</key>
 <string>mac book pro</string>
 <key>7.jpg</key>
 <string>mac book air</string>
 <key>8.jpg</key>
 <string>imac</string>
</dict>
</plist>

在程序中我們需要讀取plist文件并加載對應的圖片,這里我們將圖片按順序依次命名:0.jpg、1.jpg…8.jpg。我們的程序主要集中于自定義的KCMainViewController.m中,在這里我們聲明1個UIScrollView和3個UIImageView用于顯示圖片,同時聲明一個UILable顯示圖片描述信息,聲明一個UIPageControl來顯示當前圖片頁數(shù),具體代碼如下:

//
// KCMainViewController.m
// ImageViewer
//
// Created by Kenshin Cui on 14-2-23.
// Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "KCMainViewController.h"
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 568
#define IMAGEVIEW_COUNT 3

@interface KCMainViewController ()<UIScrollViewDelegate>{
 UIScrollView *_scrollView;
 UIImageView *_leftImageView;
 UIImageView *_centerImageView;
 UIImageView *_rightImageView;
 UIPageControl *_pageControl;
 UILabel *_label;
 NSMutableDictionary *_imageData;//圖片數(shù)據
 int _currentImageIndex;//當前圖片索引
 int _imageCount;//圖片總數(shù)
}

@end

@implementation KCMainViewController

- (void)viewDidLoad {
 [super viewDidLoad];
 //加載數(shù)據
 [self loadImageData];
 //添加滾動控件
 [self addScrollView];
 //添加圖片控件
 [self addImageViews];
 //添加分頁控件
 [self addPageControl];
 //添加圖片信息描述控件
 [self addLabel];
 //加載默認圖片
 [self setDefaultImage];
}

#pragma mark 加載圖片數(shù)據
-(void)loadImageData{
 //讀取程序包路徑中的資源文件
 NSString *path=[[NSBundle mainBundle] pathForResource:@"imageInfo" ofType:@"plist"];
 _imageData=[NSMutableDictionary dictionaryWithContentsOfFile:path];
 _imageCount=(int)_imageData.count;
}

#pragma mark 添加控件
-(void)addScrollView{
 _scrollView=[[UIScrollView alloc]initWithFrame:[UIScreen mainScreen].bounds];
 [self.view addSubview:_scrollView];
 //設置代理
 _scrollView.delegate=self;
 //設置contentSize
 _scrollView.contentSize=CGSizeMake(IMAGEVIEW_COUNT*SCREEN_WIDTH, SCREEN_HEIGHT) ;
 //設置當前顯示的位置為中間圖片
 [_scrollView setContentOffset:CGPointMake(SCREEN_WIDTH, 0) animated:NO];
 //設置分頁
 _scrollView.pagingEnabled=YES;
 //去掉滾動條
 _scrollView.showsHorizontalScrollIndicator=NO;
}

#pragma mark 添加圖片三個控件
-(void)addImageViews{
 _leftImageView=[[UIImageView alloc]initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)];
 _leftImageView.contentMode=UIViewContentModeScaleAspectFit;
 [_scrollView addSubview:_leftImageView];
 _centerImageView=[[UIImageView alloc]initWithFrame:CGRectMake(SCREEN_WIDTH, 0, SCREEN_WIDTH, SCREEN_HEIGHT)];
 _centerImageView.contentMode=UIViewContentModeScaleAspectFit;
 [_scrollView addSubview:_centerImageView];
 _rightImageView=[[UIImageView alloc]initWithFrame:CGRectMake(2*SCREEN_WIDTH, 0, SCREEN_WIDTH, SCREEN_HEIGHT)];
 _rightImageView.contentMode=UIViewContentModeScaleAspectFit;
 [_scrollView addSubview:_rightImageView];

}
#pragma mark 設置默認顯示圖片
-(void)setDefaultImage{
 //加載默認圖片
 _leftImageView.image=[UIImage imageNamed:[NSString stringWithFormat:@"%i.jpg",_imageCount-1]];
 _centerImageView.image=[UIImage imageNamed:[NSString stringWithFormat:@"%i.jpg",0]];
 _rightImageView.image=[UIImage imageNamed:[NSString stringWithFormat:@"%i.jpg",1]];
 _currentImageIndex=0;
 //設置當前頁
 _pageControl.currentPage=_currentImageIndex;
 NSString *imageName=[NSString stringWithFormat:@"%i.jpg",_currentImageIndex];
 _label.text=_imageData[imageName];
}

#pragma mark 添加分頁控件
-(void)addPageControl{
 _pageControl=[[UIPageControl alloc]init];
 //注意此方法可以根據頁數(shù)返回UIPageControl合適的大小
 CGSize size= [_pageControl sizeForNumberOfPages:_imageCount];
 _pageControl.bounds=CGRectMake(0, 0, size.width, size.height);
 _pageControl.center=CGPointMake(SCREEN_WIDTH/2, SCREEN_HEIGHT-100);
 //設置顏色
 _pageControl.pageIndicatorTintColor=[UIColor colorWithRed:193/255.0 green:219/255.0 blue:249/255.0 alpha:1];
 //設置當前頁顏色
 _pageControl.currentPageIndicatorTintColor=[UIColor colorWithRed:0 green:150/255.0 blue:1 alpha:1];
 //設置總頁數(shù)
 _pageControl.numberOfPages=_imageCount;
 
 [self.view addSubview:_pageControl];
}

#pragma mark 添加信息描述控件
-(void)addLabel{
 
 _label=[[UILabel alloc]initWithFrame:CGRectMake(0, 10, SCREEN_WIDTH,30)];
 _label.textAlignment=NSTextAlignmentCenter;
 _label.textColor=[UIColor colorWithRed:0 green:150/255.0 blue:1 alpha:1];

 [self.view addSubview:_label];
}

#pragma mark 滾動停止事件
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
 //重新加載圖片
 [self reloadImage];
 //移動到中間
 [_scrollView setContentOffset:CGPointMake(SCREEN_WIDTH, 0) animated:NO];
 //設置分頁
 _pageControl.currentPage=_currentImageIndex;
 //設置描述
 NSString *imageName=[NSString stringWithFormat:@"%i.jpg",_currentImageIndex];
 _label.text=_imageData[imageName];
}

#pragma mark 重新加載圖片
-(void)reloadImage{
 int leftImageIndex,rightImageIndex;
 CGPoint offset=[_scrollView contentOffset];
 if (offset.x>SCREEN_WIDTH) { //向右滑動
  _currentImageIndex=(_currentImageIndex+1)%_imageCount;
 }else if(offset.x<SCREEN_WIDTH){ //向左滑動
  _currentImageIndex=(_currentImageIndex+_imageCount-1)%_imageCount;
 }
 //UIImageView *centerImageView=(UIImageView *)[_scrollView viewWithTag:2];
 _centerImageView.image=[UIImage imageNamed:[NSString stringWithFormat:@"%i.jpg",_currentImageIndex]];
 
 //重新設置左右圖片
 leftImageIndex=(_currentImageIndex+_imageCount-1)%_imageCount;
 rightImageIndex=(_currentImageIndex+1)%_imageCount;
 _leftImageView.image=[UIImage imageNamed:[NSString stringWithFormat:@"%i.jpg",leftImageIndex]];
 _rightImageView.image=[UIImage imageNamed:[NSString stringWithFormat:@"%i.jpg",rightImageIndex]];
}

@end

在上面的代碼中需要提醒大家的是一定要謹慎在滾動時進行相關操作,前面我們說過滾動事件會循環(huán)執(zhí)行十分消耗性能,因此如果能不在其中操作的話盡可能不要在這個方法中進行相關操作,例如在上面的代碼中我們的核心邏輯主要集中在滾動停止事件中,這個事件在一次滾動操作中只需要執(zhí)行一次。

運行效果:

相關文章

  • 解決JSON數(shù)據因為null導致數(shù)據加載失敗的方法

    解決JSON數(shù)據因為null導致數(shù)據加載失敗的方法

    前段時間發(fā)現(xiàn)一個問題,當JSON數(shù)據中有null會導致數(shù)據加載失敗,后來解決了,現(xiàn)在將解決方法分享給大家,有同樣問題的朋友們可以參考。下面來一起看看吧。
    2016-09-09
  • iOS實現(xiàn)輪盤動態(tài)效果

    iOS實現(xiàn)輪盤動態(tài)效果

    這篇文章主要為大家詳細介紹了iOS實現(xiàn)輪盤動態(tài)效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • iOS中屏幕亮度與閃光燈控制詳解

    iOS中屏幕亮度與閃光燈控制詳解

    這篇文章主要給大家介紹了關于iOS中屏幕亮度與閃光燈控制的相關資料,文中介紹的非常詳細,對大家具有一定的參考學習價值,需要的朋友們下面來一起看看吧。
    2017-06-06
  • 值得收藏的iOS開發(fā)常用代碼塊

    值得收藏的iOS開發(fā)常用代碼塊

    這篇文章主要為大家詳細介紹了iOS開發(fā)常用代碼塊,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • 詳解iOS中UIButton的三大UIEdgeInsets屬性用法

    詳解iOS中UIButton的三大UIEdgeInsets屬性用法

    這篇文章主要介紹了iOS中UIButton的三大UIEdgeInsets屬性用法,分別講解了contentEdgeInsets、imageEdgeInsets和titleEdgeInsets三個屬性在創(chuàng)建UIButton時對樣式的控制,需要的朋友可以參考下
    2016-04-04
  • 你知道Tab Bar圖標原來還可以這樣玩嗎

    你知道Tab Bar圖標原來還可以這樣玩嗎

    這篇文章主要給大家介紹了關于Tab Bar圖標另外一些大家不知道的玩法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-04-04
  • 詳解Objective-C設計模式編程中對備忘錄模式的運用

    詳解Objective-C設計模式編程中對備忘錄模式的運用

    這篇文章主要介紹了Objective-C設計模式編程中對備忘錄模式的運用,文中結合了Cocoa框架下應用的實例來加以講解,需要的朋友可以參考下
    2016-03-03
  • iOS中應用內添加指紋識別的實例代碼

    iOS中應用內添加指紋識別的實例代碼

    iOS8之后蘋果發(fā)布了指紋識別的功能,通過touch ID來識別用戶,做用戶授權,主要是依賴于LocalAuthentication庫,下面通過本文給大家介紹iOS中應用內添加指紋識別的實例代碼,一起看看吧
    2016-12-12
  • IOS開發(fā)筆記之禁用手勢滑動返回功能的示例

    IOS開發(fā)筆記之禁用手勢滑動返回功能的示例

    本篇文章主要介紹了IOS開發(fā)筆記之禁用手勢滑動返回功能的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • iOS 實現(xiàn)類似QQ分組樣式的兩種方式

    iOS 實現(xiàn)類似QQ分組樣式的兩種方式

    這篇文章主要介紹了iOS 實現(xiàn)類似QQ分組樣式的兩種方式,思路很簡單,對模型數(shù)據操作或則控制界面顯示,需要的朋友可以參考下
    2017-07-07

最新評論