Swift值類型傳遞的問題

Swift相比Objective-C不止增長了不少特性,還有很多修改,對於實際編程中最容易出現的錯誤莫過於Swift將幾乎全部Objective-C中對應的類型,都由引用類型都修改成值類型。編程

好比開發中最經常使用到的數據類型array:數組

NSMutableArray *array1 = [NSMutableArray arrayWithArray:@[@1, @2, @3]];
NSMutableArray *array2 = array1;
[array2 removeLastObject];
NSLog(@"%@", array1); // 1, 2
複製代碼
var array1 = [1, 2, 3]
var array2 = array1
array2.removeLast()
print(array1) // 1, 2, 3
複製代碼

剛開始學習Swift時,只是以爲這只是一個語言對於不一樣數據類型的設計不一樣而已,開發中只要注意對於須要函數內部修改的參數,加上inout便可。bash

可是隨着對於Swift的深刻使用,愈來愈以爲,這個設計相比於Objective-C的引用類型來講,確實是更加的難以使用。ide

好比實現一個對於數組的排序封裝類,將數組傳入並將數組按照升序排序,這裏採用最簡單的冒泡排序實現,若是是Objective-C實現:函數

#import <Foundation/Foundation.h>

@interface MySort<ObjectType>: NSObject 

- (void)sortWithArray:(NSMutableArray<ObjectType> *)array;

@end

@implementation MySort

- (void)sortWithArray:(NSMutableArray *)array {
	if (!array || array.count < 2) {
		return;
	}
	
	for (NSInteger end = array.count - 1; end > 0; end--) {
		for (NSInteger begin = 1; begin <= end; begin ++) {
			if ([array[begin] compare:array[begin - 1]] == NSOrderedAscending) {
				id tmp = array[begin];
				array[begin] = array[begin - 1];
				array[begin - 1] = tmp;
			}
		}
	}
}

@end

int main(int argc, char *argv[]) {
	NSMutableArray *array = [NSMutableArray arrayWithArray:@[@9, @8, @7, @6, @5, @4, @3, @2, @1, @0]];
	MySort *sort = [MySort new];
	[sort sortWithArray:array];
	NSLog(@"%@", array);
}
複製代碼

由於Objective-C中,數組是引用類型,直接將數組傳遞就能夠實現對其排序,若是將上述的代碼用Swift實現,須要在函數中修改array,須要將參數加上inout來實現:學習

public class MySort<ObjectType: Comparable> {
    public final func sortWithArray(array: inout [ObjectType]) {
        guard array.count > 1 else {
            return
        }
        for end in stride(from: array.count - 1, to: 0, by: -1) {
            for begin in 1 ... end {
                if array[begin] < array[begin - 1] {
                    let tmp = array[begin]
                    array[begin] = array[begin - 1]
                    array[begin - 1] = tmp
                }
            }
        }
    }
}

var array = [9,8,7,6,5,4,3,2,1,0]
var mySort = MySort<Int>()
mySort.sortWithArray(array: &array)
print(array)
複製代碼

目前來看沒有任何問題,下面假如須要排序類先將數據保存,並在其它方法中實現排序。ui

在Objective-C中,只須要爲類添加一個成員,而且將方法傳入的數組對象傳遞給它便可:spa

@interface MySort<ObjectType>: NSObject {
@private
	NSMutableArray<ObjectType> *_array;
}

- (void)sortWithArray:(NSMutableArray<ObjectType> *)array;

@end

@implementation MySort

- (void)sortWithArray:(NSMutableArray *)array {
	if (!array || array.count < 2) {
		return;
	}
	
	_array = array;
}

- (void)sort {
	for (NSInteger end = _array.count - 1; end > 0; end--) {
		for (NSInteger begin = 1; begin <= end; begin ++) {
			if ([_array[begin] compare:_array[begin - 1]] == NSOrderedAscending) {
				id tmp = _array[begin];
				_array[begin] = _array[begin - 1];
				_array[begin - 1] = tmp;
			}
		}
	}
}

@end
複製代碼

可是Swift中就會出現問題:設計

public class MySort<ObjectType: Comparable> {
    private var array: [ObjectType]?
    
    public final func sortWithArray(array: inout [ObjectType]) {
        guard array.count > 1 else {
            return
        }
        self.array = array
        sort()
    }
    
    private func sort() {
        for end in stride(from: array!.count - 1, to: 0, by: -1) {
            for begin in 1 ... end {
                if array![begin] < array![begin - 1] {
                    let tmp = array![begin]
                    array![begin] = array![begin - 1]
                    array![begin - 1] = tmp
                }
            }
        }
    }
}

var array: [Int] = [9,8,7,6,5,4,3,2,1,0]
var mySort = MySort<Int>()
mySort.sortWithArray(array: &array)
// [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
print(array)
複製代碼

由於數組是值類型,將函數傳入的數組傳遞給排序類的成員時:self.array = array 是一個默認拷貝的操做,在接下來的排序過程,只是對排序類中拷貝的數據進行排序。若是須要將函數傳入的數組也修改排序,須要在sort()調用後,將本地拷貝的數組傳遞給外部的inout 參數:指針

public final func sortWithArray(array: inout [ObjectType]) {
        guard array.count > 1 else {
            return
        }
        self.array = array
        sort()
        array = self.array!
    }
複製代碼

這樣作很是的很差,由於無緣無故的多出來兩次數據的拷貝操做,最終我是使用了一個不太好的辦法,就是利用指針來處理:

public class MySort<ObjectType: Comparable> {
    private var array: UnsafeMutablePointer<[ObjectType]>?
    
    public final func sortWithArray(array: inout [ObjectType]) {
        guard array.count > 1 else {
            return
        }
        self.array = withUnsafeMutablePointer(to: &array) { $0 }
        sort()
    }
    
    private func sort() {
        for end in stride(from: array!.pointee.count - 1, to: 0, by: -1) {
            for begin in 1 ... end {
                if array!.pointee[begin] < array!.pointee[begin - 1] {
                    let tmp = array!.pointee[begin]
                    array!.pointee[begin] = array!.pointee[begin - 1]
                    array!.pointee[begin - 1] = tmp
                }
            }
        }
    }
}

var array: [Int] = [9,8,7,6,5,4,3,2,1,0]
var mySort = MySort<Int>()
mySort.sortWithArray(array: &array)
print(array)
複製代碼

這樣子確實避免了拷貝,不過真的很是的很差看,也不方便,只是解決了問題而已。

有人有更好的辦法解決歡迎分享。

相關文章
相關標籤/搜索