Swift编程语言为了能与Objective-C与C语言兼容,而引入了指针类型。尽管官方不建议频繁使用指针类型,但很多时候,使用指针能完成更多、更灵活的任务。比如,我们要实现一个交换两个整数值的函数的时候就不得不动用指针了。就表达上,Swift使用UnsafePointer来表示指向一个常量的指针;使用UnsafeMutablePointer来表示指向一个变量的指针,也是比较直观。不过目前大多Swift开发者对于Swift指针类型的运用不太娴熟,而且官方的编程指南也没怎么提,所以俺这里将写一篇博文来详细给各位介绍一下Swift中的指针类型以及其各种用法~

//
// ViewController.swift
// SwiftTest
//
// Created by Zenny Chen on 16/4/1.
// Copyright © 2016年 GreenGames Studio. All rights reserved.
// import Cocoa /// 对输入一个数组缓存的每个元素进行求和,然后返回求和结果 <br/>
/// 最后,将该数组缓存中的中间一个元素修改为求和的结果值
func myTest(array: UnsafeMutablePointer<Int>, count: Int) -> Int {
var sum = var i = while i < count {
// tmp的值为array第i个元素的值
let tmp = array.advancedBy(i).memory
sum += tmp
i +=
} array.advancedBy(count / ).memory = sum return sum
} /// 将srcArray中后一半的元素拷贝到dstArray中的前一半中去
func myTest2(dstArray: UnsafeMutablePointer<Int>, srcArray: UnsafePointer<Int>, count: Int) {
// 这里通过构造方法将UnsafePointer<Int>转为UnsafeMutablePointer<Int>类型
dstArray.assignBackwardFrom(UnsafeMutablePointer<Int>(srcArray).advancedBy(count / ), count: count / + )
} /// 将srcArray中前一半的元素拷贝到dstArray中的前一半中去
func myTest3(dstArray: UnsafeMutablePointer<Int>, srcArray: UnsafePointer<Int>, count: Int) { // 这里从srcArray的第二个元素开始,拷贝count / 2 + 1个元素
dstArray.assignFrom(UnsafeMutablePointer<Int>(srcArray.advancedBy()), count: count / + )
} /// 用于测试distanceTo方法
func myTest4(array: UnsafeMutablePointer<Int>, count: Int) { // 这里,distanceTo就相当于distanceTo的参数所在的元素位置与array所在的位置的差
// 相当于(distanceTo参数的地址 - array的地址) / sizeof(Int)
let distance = array.distanceTo(array.advancedBy(count / ))
print("distance = \(distance)")
} class ViewController: NSViewController { override func viewDidLoad() {
super.viewDidLoad() // Do any additional setup after loading the view.
// 声明一个变量a,并用10对它初始化
var a = let ptr: UnsafeMutablePointer<Int> = UnsafeMutablePointer<Int>(bitPattern: 0x1000) let bptr = UnsafeMutableBufferPointer(start:&a, count:)
bptr[] += let cptr = UnsafeMutablePointer<Int>(bptr.baseAddress)
cptr.memory += print("a = \(a)") var x =
let p = getMutablePointerType(&x)
p.memory +=
print("x = \(x)") var array = [, , , , ] let value = myTest(&array, count: array.count) print("value = \(value), and array is: \(array)") let doubleArray: [[Int]] = [ [, , ], [, ], [, , , , ] ]
for arr in doubleArray {
print("array length: \(arr.count)")
} array = [Int](count: , repeatedValue: )
myTest2(&array, srcArray: [, , , , ], count: array.count)
print("array is: \(array)") array = [Int](count: , repeatedValue: )
myTest3(&array, srcArray: [, , , , ], count: array.count)
print("array is: \(array)") myTest4(&array, count: array.count)
} override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
}

在上述代码例子中,我们主要描述了UnsafeMutablePointer类型的特性与常用方法的使用描述。一开始,我们定义了一个

getMutablePointerType函数用于方便地获得一个变量的指针。

myTest函数描述了UnsafeMutablePointer的advancedBy方法以及memory方法的使用以及功能。

myTest2函数描述了assignBackwardFrom函数的使用以及功能

myTest3函数描述了assignFrom函数的使用以及功能

myTest4函数描述了distanceTo函数的使用以及功能

这里大家要注意的是,在Swift中由于函数是一个闭包,所以只有“函数对象”这个概念,所以不存在指向函数的指针,只有函数对象引用。如果有外部C语言的API存在指向函数指针类型,则需要用@convention(c)去做转换处理。

我们下面举一个例子,主要描述二维数组如果通过指针进行操作的例子

//
// ViewController.swift
// SwiftTest
//
// Created by Zenny Chen on 16/4/1.
// Copyright © 2016年 GreenGames Studio. All rights reserved.
// import Cocoa /// 此函数用于将一个变量转换为指向该变量的常量指针对象
func getConstPointerType<T> (ptr: UnsafePointer<T>) -> UnsafePointer<T> {
return ptr
} /// 此函数用于将一个变量转换为指向该变量的变量指针对象
func getMutablePointerType<T> (ptr: UnsafeMutablePointer<T>) -> UnsafeMutablePointer<T> {
return ptr
} class ViewController: NSViewController { override func viewDidLoad() {
super.viewDidLoad() // Do any additional setup after loading the view. var array = [[, , ], [, , , ]] // 定义一个指向元素为数组类型的数组对象的指针
let p = getMutablePointerType(&array) // 此时,p.memory的类型为[Int]
// 将p的第1个元素的第2个元素的值加10
p.memory[] += // 将p的第2个元素的第4个元素的值加100
p.advancedBy().memory[] += print("array = \(array)") let funcRef: @convention(c) () -> Int32 = MyCFunc print("value is: \(funcRef())")
} override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
}

通过上述代码,我们可以注意到,在Swift中,一个二维数组其实就是以数组对象作为元素的数组对象。该数组对象的每个元素是一个数组对象引用。因此在用指针操作的时候,其实就是先对某一个数组对象进行操作,访问其里面的一个元素。

此外,Swift中的UnsafeMutablePointer、UnsafeMutableBufferPointer等指针类型对象对具体对象的引用都属于弱引用,也就是说它们的引用以实际对象来看是完全被别名化的,指针对实际对象的操作跟直接用实际对象的引用对对象操作的效果是完全等价的,所以Apple官方称这些类型为“non-owning pointer”。下面举一个例子:

class MyClass {
deinit {
print("MyClass is destroyed!")
}
} class ViewController: NSViewController { override func viewDidLoad() {
super.viewDidLoad() var myObj: MyClass? = MyClass()
var objptr = UnsafeMutableBufferPointer(start: &myObj, count: )
// 这句话与myObj = nil的效果完全一样,
// 这句话执行完之后就会打印:MyClass is destroyed!
objptr.baseAddress.memory = nil
}
}

以下展示用Swift来玩二级指针,其实与C语言的也类似:

class ViewController: NSViewController {

    override func viewDidLoad() {
super.viewDidLoad() var a = var size = sizeofValue(a)
print("size = \(size)") size = sizeof(ViewController)
print("size = \(size)") var arr = [, , ]
print("The size is: \(sizeofValue(arr))") var ptr = getMutablePointer(&a)
ptr[] +=
print("The value is: \(a)") let pp = getMutablePointer(&ptr) var b = ptr = getMutablePointer(&b)
pp[][] += print("b = \(b)") pp[] = getMutablePointer(&a)
pp[][] -=
print("a = \(a)")
}
}

看完上述Swift中指针操作的场景之后,本人蛋疼地用C++也封装了一些基本类型,可基本模拟出Swift对指针的操作访问模式。

//
// hello.cpp
// CDemo
//
// Created by Zenny Chen on 16/4/1.
// Copyright © 2016年 GreenGames Studio. All rights reserved.
// #include <iostream>
#include <functional>
using namespace std; #define object auto struct Int
{
private: int mValue; public: Int(void) : mValue(0) { } Int(int i) : mValue(i) { } inline Int& operator = (int value)
{
mValue = value; return *this;
} inline Int& operator = (Int& obj)
{
mValue = obj.mValue;
return *this;
} inline operator int& (void)
{
return mValue;
} inline operator const int (void) const
{
return mValue;
} inline size_t size(void) const
{
return sizeof(mValue);
} inline Int* address(void)
{
return this;
} inline const char* typeName(void) const
{
return "Int";
}
}; template <typename T>
struct ptr
{
private: T *mPtr; public: ptr(void) : mPtr(NULL){ } ptr(T *t) : mPtr(t) { } inline T& memory(void)
{
return *mPtr;
} inline T& memory(int index)
{
return mPtr[index];
} inline const T& memory(void) const
{
return *mPtr;
} inline const T& memory(int index) const
{
return mPtr[index];
} inline ptr<T> advancedBy(int count)
{
return ptr<T>(&mPtr[count]);
} inline ptr<T>& operator = (T* t)
{
mPtr = t;
return *this;
} inline ptr<T>& operator = (ptr<T>& p)
{
mPtr = p;
return *this;
} inline ptr<T>* address(void)
{
return this;
} inline size_t size(void) const
{
return sizeof(mPtr);
} inline uintptr_t value(void) const
{
return (uintptr_t)mPtr;
}
}; template <typename T, size_t S>
struct myArray
{
private: T mArray[S]; public: myArray(void)
{
memset(mArray, 0, sizeof(mArray));
} myArray(T arr[S])
{
memcpy(mArray, arr, sizeof(mArray));
} inline myArray<T, S>& operator = (myArray<T, S>& arr)
{
memcpy(mArray, arr.mArray, sizeof(mArray));
return *this;
} inline myArray<T, S> *address(void)
{
return this;
} inline T& operator [] (size_t index)
{
return mArray[index];
} inline size_t size(void) const
{
return sizeof(mArray);
} inline size_t count(void) const
{
return S;
}
}; template <typename FP>
class func : public function<FP>
{
private: void *mp; public: func(FP *fun) : function<FP>(fun)
{
mp = (void*)fun;
} inline size_t size(void) const
{
return sizeof(void*);
} inline ptr< func<FP> > address(void)
{
return this;
} inline uintptr_t functionAddress(void)
{
return (uintptr_t)mp;
}
}; #pragma mark - 以下为对本语言系统的使用 static void MySwap(ptr<Int> a, ptr<Int> b)
{
int tmp = a.memory();
a.memory() = b.memory();
b.memory() = tmp;
} extern "C" void CPPTest(void)
{
Int a = 100;
printf("size of a = %zu\n", a.size()); // object可表示任一对象,并且其类型根据 = 右操作数进行推导
object b = a;
printf("b type is: %s\n", b.typeName()); // 指向变量的指针
ptr<Int> p = a.address(); p.memory() += 10; printf("a = %d\n", a);
printf("size of p = %zu\n", p.size()); // 指向常量的指针
ptr<const Int> cp = a.address(); // error ==> cp.memory() -= 10; printf("memory = %d\n", cp.memory()); // 指向指针的指针
ptr< ptr<Int> > pp = p.address();
printf("content is: %d\n", pp.memory().memory()); pp.memory() = NULL; // 指针p变为空
printf("p value is: %zu\n", p.value()); myArray<Int, 3> arr = (Int[]){ 1, 2, 3 };
printf("size is: %zu, count is: %zu\n", arr.size(), arr.count()); // 指向一个数组首地址的指针
p = arr[0].address();
printf("element 1 = %d\n", p.advancedBy(1).memory());
printf("element 2 = %d\n", p.memory(2)); // 将指针指向数组第二个元素的地址
p = arr[1].address();
printf("p[1] = %d\n", p.memory(1)); // 指向数组的指针
ptr< myArray<Int, 3> > pArr = arr.address();
printf("element 2 = %d\n", pArr.memory()[2]); // 数组赋值
myArray<Int, 3> arr2; arr2 = arr;
arr2[0]++;
arr2[1]--; pArr = arr2.address();
printf("arr2[0] = %d\n", pArr.memory()[0]);
printf("arr2[1] = %d\n", pArr.memory()[1]); // 通过指针间接将arr的值赋给pArr所指向的数组对象arr2
pArr.memory() = arr;
printf("arr2[0] = %d\n", arr2[0]);
printf("arr2[1] = %d\n", arr2[1]); // 关于cv限定符对复杂类型的修饰
// 相当于:const int* const *qq = &cp;
ptr<const ptr<const Int>> qq = cp.address(); // qq.memory() = NULL; Error!
// qq.memory().memory() = 0; // Error! a = qq.memory().memory(); // OK
printf("a = %d\n", a); qq = NULL; // OK
printf("qq value is: %d\n", qq.value()); Int x = 10, y = -10; // 定义一个函数对象
func<void(ptr<Int>, ptr<Int>)> fun = MySwap;
printf("fun size is: %zu\n", fun.size()); fun(x.address(), y.address());
printf("x = %d, y = %d\n", x, y); ptr< func<void(ptr<Int>, ptr<Int>)> > pFunc = fun.address();
pFunc.memory()(x.address(), y.address());
printf("x = %d, y = %d\n", x, y); printf("fun object address: %.16tX\n", fun.address().value());
printf("MySwap address: %.16tX\n", fun.functionAddress());
}

各位可以实践一下,用的是GNU++14标准~

Swift中的指针类型的更多相关文章

  1. 关于Swift中的指针的那些事

    前言 在Objective-c的世界中,一切对象都是指针.它是一种运行时语言,具体指针的对象类型将会在运行时,由系统分配.这样虽然自由,但是却并不安全. Swift世界就不一样了,Swift的世界很安 ...

  2. Swift——(六)Swift中的值类型

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/twlkyao/article/details/34855597     在Swift中,结构体和枚举 ...

  3. Swift中的Optional类型 (可选类型)与强制解包 ? !

    我们在swift的开发中会经常遇见?和! ,理解这两个符号深层次的内容对我们的开发是相当有利的: 目前网上对swift3.0的教程还相当的少,如果去搜索会发现早期的说法,在定义变量的时候,swift是 ...

  4. Swift中的Void类型与空元祖表达式

    可能有不少Swift开发者会忽略这么一个细节:在Swift中,Void类型其实是一个别名类型,而其真正的类型为(),即一个空元祖(empty tuple)! 这种语言特性给Swift带来了一些比较方便 ...

  5. swift中的可选类型

    可选类型也是Swift语言新添加的对象.主要是为了解决对象变量或常量为空的情况.在前面定义的变量和常量都不能为空.里面必须要有值. Swift中的可选类型则允许变量(常量)中没有值(被设为nil).要 ...

  6. Swift 中的指针使用

    SWIFT 中  指针被映射为泛型 UnsafePointer<T> UnsafeMutablePointer<T> 表示一组连续数据指针的 UnsafeBufferPoint ...

  7. Swift中关于任意类型的数组

    在Objc中你是不可以把一个非对象类型放入数组的,你必须将其"封箱",然后再放入数组. 在Swift中你可将非对象类型轻松放入数组: let ary = [1,2,3] 你可以明确 ...

  8. Swift中的集合类型

    一.引子: 在2014年10月TIOBE编程语言排行榜中,Swift位居第18位,从2014WWDC发布会首次公布至今不到半年时间,swift一直受到编程人 员的追捧,其热衷程度并不亚于当红巨星Tay ...

  9. vector 对象中存放指针类型数据

    <<C++ Primer>> 第四版Exercise Section 5.6 的5.1.6 有一道题是这样的:编写程序定义一个vector对象,其每个元素都是指向string类 ...

随机推荐

  1. BZOJ 1566 管道取珠(DP)

    求方案数的平方之和.这个看起来很难解决.如果转化为求方案数的有序对的个数.那么就相当于求A和B同时取,最后序列一样的种数. 令dp[i][j][k]表示A在上管道取了i个,下管道取了j个,B在上管道取 ...

  2. 【bzoj2741】[FOTILE模拟赛]L 可持久化Trie树+分块

    题目描述 FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 ... xor A ...

  3. 【数据库_Mysql】MySQL动态语句 if set choose where foreach trim

    MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑. MyBatis中用于实现动态SQL的元素主要有: if choose(when,otherwise) ...

  4. BZOJ4896 THUSC2016补退选(trie)

    字符串扔进trie,vector记录每个前缀出现次数的最大值的更新记录即可. #include<iostream> #include<cstdio> #include<c ...

  5. Glide加载图片并保存到本地返回file,bitmap

    有很多朋友都想要知道32位和64位的区别是什么,因为大家都拿不准自己要装32位系统还是64位系统,因此彷徨是必然的.那么到底区别是啥咧?如果大家想要知道的话,下面就让小编给大家带来32位和64位的区别 ...

  6. redis分布式(主从复制)

    Redis主从复制配置和使用都非常简单.通过主从复制可以允许多个slave server拥有和master server相同的数据库副本.    Redis的复制原理:本身就是Master发送数据给s ...

  7. (转载)Cobalt Strike tutorial下针对CVE-2017-0199利用

    CVE-2017-0199利用OLE对象嵌入Word / RTF文档的方式,使得可以在没有用户交互的情况下执行其内容.OLE由许多不同的程序支持,OLE通常用于使在另一个程序中可用的程序中创建的内容. ...

  8. Django summernote 富文本

    Summernote is a simple WYSIWYG editor. GITHUB:https://github.com/summernote/django-summernote SETUP ...

  9. 「Python」pandas入门教程

    pandas适合于许多不同类型的数据,包括: 具有异构类型列的表格数据,例如SQL表格或Excel数据 有序和无序(不一定是固定频率)时间序列数据. 具有行列标签的任意矩阵数据(均匀类型或不同类型) ...

  10. Kubernetes - Deploy Containers Using YAML

    In this scenario, you'll learn how to use Kubectl to create and launch Deployments, Replication Cont ...