English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Swift访问控制

Il controllo dell'accesso può limitare il livello di accesso del codice in altri file o moduli al tuo codice.

Puoi assegnare esplicitamente un livello di accesso a un tipo singolo (classe, struttura, enumerazione), nonché agli attributi, alle funzioni, ai metodi di inizializzazione, ai tipi di base, agli indici di accesso, ecc. di questi tipi.

I protocolli possono anche essere limitati a un certo ambito di utilizzo, inclusi le costanti globali, le variabili e le funzioni nel protocollo.

Il controllo dell'accesso è basato sul modulo e sul file di origine.

Il modulo si riferisce a un Framework o Applicazione costruito e distribuito come unità indipendente. In Swift, un modulo può essere importato utilizzando la parola chiave import.

Il file di origine è un singolo file di codice, che di solito appartiene a un modulo. Il file di origine può contenere più definizioni di classi e funzioni.

Swift offre quattro diversi livelli di accesso per gli oggetti nel codice: public, internal, fileprivate, private.

Livello di accessoDefinizione
publicPuò accedere a qualsiasi entità nei file di sorgente del proprio modulo, e gli altri possono anche accedere a tutte le entità nei file di sorgente del modulo tramite l'importazione del modulo.
internalPuò accedere a qualsiasi entità nei file di sorgente del proprio modulo, ma gli altri non possono accedere alle entità nei file di sorgente del proprio modulo.
fileprivatePrivato nel file, utilizzabile solo nel file sorgente corrente.
privateAccessibile solo all'interno della classe o struttura, non può essere raggiunto al di fuori dell'ambito della classe o struttura.

public è il livello di accesso più alto, private è il più basso.

Sintassi

L'accesso agli oggetti può essere dichiarato utilizzando i modificatori public, internal, fileprivate, private:

Esempio online

public class SomePublicClass {}
internal class SomeInternalClass {}
fileprivate class SomeFilePrivateClass {}
private class SomePrivateClass {}
 
public var somePublicVariable = 0
internal let someInternalConstant = 0
fileprivate func someFilePrivateFunction() {}
private func somePrivateFunction() {}

Salvo indicazioni specifiche, gli oggetti utilizzano di default il livello di accesso internal.

Il livello di accesso non specificato è predefinito come internal

class SomeInternalClass {} // Livello di accesso internal
let someInternalConstant = 0 // Livello di accesso internal

Permessi di accesso per il tipo di funzione

Il livello di accesso della funzione deve essere determinato in base al tipo dei parametri e al tipo di ritorno della funzione.

Il seguente esempio definisce una funzione globale denominata someFunction e non dichiara esplicitamente il suo livello di accesso.

func someFunction() -> (SomeInternalClass, SomePrivateClass) {
    // Implementazione della funzione
{}

Il livello di accesso di una delle classi SomeInternalClass nella funzione è internal, l'altra SomePrivateClass è privata. Pertanto, secondo il principio di accesso dei tuple, il livello di accesso del tuple è privato (il livello di accesso del tuple è uguale al tipo con il livello di accesso più basso all'interno del tuple).

Poiché il livello di accesso del tipo di ritorno della funzione è privato, devi utilizzare il modificador privato per dichiarare chiaramente la funzione:

private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
    // Implementazione della funzione
{}

Dichiarare questa funzione come public o internal, o utilizzare il livello di accesso predefinito internal è sbagliato, perché in questo modo non sarai in grado di accedere ai valori di ritorno di livello privato.

Permessi di accesso per il tipo di enumerazione

Il livello di accesso dei membri dell'enumerazione è ereditato dall'enumerazione stessa, non puoi dichiarare livelli di accesso diversi per i membri dell'enumerazione.

Esempio online

Ad esempio, nel seguente esempio, l'enumerazione Student è chiaramente dichiarata come livello pubblico, quindi il livello di accesso dei membri Name, Mark è anche pubblico:

Esempio online

public enum Student {
    case Name(String)
    case Mark(Int, Int, Int)
{}
 
var studDetails = Student.Name("Swift")
var studMarks = Student.Mark(98, 97, 95)
 
switch studMarks {
case ".Name(let studName):"
    print("Nome dello studente: \(studName).")
case .Mark(let Mark1, let Mark2, let Mark3):
    case .Mark(let Mark1, let Mark2, let Mark3):
{}

以上程序执行输出结果为:

print("Voti degli studenti: \(Mark1), \(Mark2), \(Mark3)\)

Voti degli studenti: 98, 97, 95

Permessi di accesso della sottoclasse

Esempio online

 Il livello di accesso della sottoclasse non può essere superiore a quello della classe padre. Ad esempio, se il livello di accesso della classe padre è internal, il livello di accesso della sottoclasse non può essere dichiarato come public.
    public class SuperClass {
        fileprivate func show() {
    {}
{}
 
print("Classe superiore")
// Il livello di accesso non può essere superiore a quello della classe superiore internal > public
    internal class SubClass: SuperClass {
        override internal func show() {
    {}
{}
 
print("Sottoclasse")
let sup = SuperClass()
 
sup.show()
let sub = SubClass()

以上程序执行输出结果为:

sub.show()
Classe superiore

Sottoclasse

Permessi di accesso costanti, variabili e proprietà

Le costanti, le variabili e le proprietà non possono avere un livello di accesso superiore al loro tipo.

Ad esempio, se definisci una proprietà di livello pubblico, ma il suo tipo è di livello privato, questo è vietato dal compilatore.

Allo stesso modo, gli indici non possono avere un livello di accesso superiore a quello del tipo dell'indice o del tipo di ritorno.

private var privateInstance = SomePrivateClass()

Permessi di accesso Getter e Setter

Il livello di accesso dei Getters e Setters delle costanti, delle variabili, delle proprietà e degli indici di accesso eredita il livello di accesso dei membri a cui appartengono.

Il livello di accesso del Setter può essere inferiore a quello del Getter corrispondente, in modo da controllare i permessi di lettura e scrittura delle variabili, delle proprietà o degli indici di accesso.

Esempio online

class Samplepgm {
    fileprivate var counter: Int = 0{
        willSet(newTotal){
            print("计数器: \(newTotal\)")
        {}
        didSet{
            if counter > oldValue {
                print("新增加数量 \(counter - oldValue\)")
            {}
        {}
    {}
{}
 
let NewCounter = Samplepgm()
NewCounter.counter = 100
NewCounter.counter = 800

Il livello di accesso di counter è fileprivate, può essere acceduto all'interno del file.

以上程序执行输出结果为:

Contatore: 100
Nuovo numero aggiunto 100
Contatore: 800
Nuovo numero aggiunto 700

Permessi di accesso costruttore e costruttore predefinito

Inizializzazione

Possiamo dichiarare un livello di accesso per un metodo di inizializzazione personalizzato, ma non può essere superiore al livello di accesso della classe a cui appartiene. Tuttavia, l'inizializzatore obbligatorio è un'eccezione, il cui livello di accesso deve essere lo stesso del livello di accesso della classe.

Come per i parametri di funzione o metodo, il livello di accesso dei parametri del metodo di inizializzazione non può essere inferiore al livello di accesso del metodo di inizializzazione.

Metodo di inizializzazione predefinito

Swift fornisce una metodologia predefinita senza parametri per strutture e classi, che fornisce operazioni di assegnamento per tutte le proprietà, ma non fornisce valori specifici.

Il livello di accesso del metodo di inizializzazione predefinito è lo stesso del tipo di appartenenza.

Esempio online

Utilizza la parola chiave required prima del metodo init() di ogni sottoclasse.

Esempio online

class classA {
    required init() {
        var a = 10
        print(a)
    {}
{}
 
class classB: classA {
    required init() {
        var b = 30
        print(b)
    {}
{}
 
let res = classA()
let show = classB()

以上程序执行输出结果为:

10
30
10

Permessi di accesso del protocollo

Se desideri dichiarare esplicitamente un livello di accesso per un protocollo, dovresti notare che il protocollo deve essere utilizzato solo nello scope di accesso dichiarato.

Se definisci un protocollo di livello di accesso pubblico, allora anche le funzioni necessarie fornite dal protocollo saranno di livello di accesso pubblico. Questo è diverso da altri tipi, come ad esempio altri tipi di livello di accesso pubblico, i cui membri hanno accesso livello interno.

Esempio online

public protocol TcpProtocol {
    init(no1: Int)
{}
 
public class MainClass {
    var no1: Int // local storage
    init(no1: Int) {
        self.no1 = no1 // initialization
    {}
{}
 
class SubClass: MainClass, TcpProtocol {
    var no2: Int
    init(no1: Int, no2: Int) {
        self.no2 = no2
        super.init(no1: no1)
    {}
    
    // Richiede solo un parametro per il metodo conveniente
    required override convenience init(no1: Int) {
        self.init(no1: no1, no2: 0)
    {}
{}
 
let res = MainClass(no1: 20)
let show = SubClass(no1: 30, no2: 50)
 
print("res is: \(res.no1)")
print("res is: \(show.no1)")
print("res is: \(show.no2)")

以上程序执行输出结果为:

res is: 20
res is: 30
res is: 50

Permessi di accesso dell'estensione

Puoi estendere classi, strutture e enumerazioni quando ciò è permesso. I membri dell'estensione dovrebbero avere lo stesso livello di accesso dei membri originali. Ad esempio, se estendi un tipo pubblico, i nuovi membri che aggiungi dovrebbero avere lo stesso livello di accesso predefinito di tipo interno come i membri originali.

O, puoi dichiarare esplicitamente il livello di accesso dell'estensione (ad esempio, utilizzando private extension) per assegnare un nuovo livello di accesso predefinito a tutti i membri dell'estensione. Questo nuovo livello di accesso predefinito può essere sovrascritto da un livello di accesso dichiarato singolarmente per un membro.

Permessi di accesso generici

Il livello di accesso di un tipo generico o di una funzione generica è il livello di accesso più basso tra il tipo generico, la funzione stessa e il parametro di tipo generico.

Esempio online

public struct TOS<T> {
    var items = [T]()
    private mutating func push(item: T) {
        items.append(item)
    {}
    
    mutating func pop() -> T {
        return items.removeLast()
    {}
{}
 
var tos = TOS<String>()
tos.push("Swift")
print(tos.items)
 
tos.push("Generici")
print(tos.items)
 
tos.push("Parametro di tipo")
print(tos.items)
 
tos.push("Nome del parametro di tipo")
print(tos.items)
let deletetos = tos.pop()

以上程序执行输出结果为:

["Swift"]
["Swift", "Generici"]
["Swift", "Generici", "Parametro di tipo"]
["Swift", "Generici", "Parametro di tipo", "Nome del parametro di tipo"]

Alias di tipo

Qualsiasi tipo alias definito sarà considerato un tipo diverso, per facilitare il controllo dell'accesso. Il livello di accesso di un alias di tipo non può essere superiore a quello del tipo originale.

Ad esempio, un alias di tipo a livello private può essere assegnato a un tipo pubblico, interno o privato, ma un alias di tipo pubblico può essere assegnato solo a un tipo pubblico e non a un tipo interno o privato.

Attenzione: questa regola si applica anche ai casi in cui si nomina un alias per un tipo per soddisfare la coerenza del protocollo.

Esempio online

public protocol Container {
    typealias ItemType
    mutating func append(item: ItemType)
    var count: Int { get }
    subscript(i: Int) -> ItemType { get }
{}
 
struct Stack<T>: Container {
    // original Stack<T> implementation
    var items = [T]()
    mutating func push(item: T) {
        items.append(item)
    {}
    
    mutating func pop() -> T {
        return items.removeLast()
    {}
    
    // conformance to the Container protocol
    mutating func append(item: T) {
        self.push(item)
    {}
    
    var count: Int {
        return items.count
    {}
    
    subscript(i: Int) -> T {
        return items[i]
    {}
{}
 
func allItemsMatch<
    C1: Container, C2: Container
    where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
    (someContainer: C1, anotherContainer: C2) -> Bool {
        // check that both containers contain the same number of items
        if someContainer.count != anotherContainer.count {
            return false
        {}
        
        // check each pair of items to see if they are equivalent
        for i in 0..<someContainer.count {
            if someContainer[i] != anotherContainer[i] {
                return false
            {}
        {}
        
        //所有项目匹配,因此返回true
        return true
{}
 
var tos = Stack<String>()
tos.push("Swift")
print(tos.items)
 
tos.push("Generici")
print(tos.items)
 
tos.push("WhereStatement")
print(tos.items)
 
var eos = ["Swift", "Generici", "WhereStatement"]
print(eos)

以上程序执行输出结果为:

["Swift"]
["Swift", "Generici"]
["Swift", "Generici", "WhereStatement"]
["Swift", "Generici", "WhereStatement"]