스위프트 언어로 된 추상 클래스
스위프트 언어로 추상 클래스를 만들 수 있는 방법이 있습니까, 아니면 이것은 오브젝티브-C와 같은 제한 사항입니까?자바가 추상 클래스로 정의하는 것과 비슷한 추상 클래스를 만들고 싶습니다.
Swift에는 추상 클래스가 없습니다(Objective-C와 동일).가장 좋은 방법은 Java 인터페이스와 같은 프로토콜을 사용하는 것입니다.
그런 다음 Swift 2.0을 사용하여 프로토콜 확장을 사용하여 메서드 구현 및 계산된 속성 구현을 추가할 수 있습니다.유일한 제한 사항은 구성원 변수 또는 상수를 제공할 수 없고 동적 배포가 없다는 것입니다.
이 기법의 예는 다음과 같습니다.
protocol Employee {
var annualSalary: Int {get}
}
extension Employee {
var biweeklySalary: Int {
return self.annualSalary / 26
}
func logSalary() {
print("$\(self.annualSalary) per year or $\(self.biweeklySalary) biweekly")
}
}
struct SoftwareEngineer: Employee {
var annualSalary: Int
func logSalary() {
print("overridden")
}
}
let sarah = SoftwareEngineer(annualSalary: 100000)
sarah.logSalary() // prints: overridden
(sarah as Employee).logSalary() // prints: $100000 per year or $3846 biweekly
이것은 구조체에 대해서도 기능과 같은 "추상적인 클래스"를 제공하지만 클래스는 동일한 프로토콜을 구현할 수도 있습니다.
또한 직원 프로토콜을 구현하는 모든 클래스 또는 구조는 연간 급여 자산을 다시 선언해야 합니다.
가장 중요한 것은 동적 파견이 없다는 것입니다.언제logSalary로 저장된 인스턴스에서 호출됩니다.SoftwareEngineer재지정된 메서드 버전을 호출합니다.언제logSalary인스턴스에 캐스팅된 후 호출됩니다.Employee원래 구현을 호출합니다(인스턴스가 실제로는 a-valides이지만 재정의된 버전으로 동적으로 디스패치되지 않습니다).Software Engineer.
자세한 내용은 해당 기능에 대한 훌륭한 WWDC 비디오를 확인하십시오.Swift에서 가치 유형으로 더 나은 애플리케이션 구축
이 답변은 Swift 2.0 이상을 대상으로 합니다.
프로토콜 및 프로토콜 확장을 사용하여 동일한 동작을 수행할 수 있습니다.
먼저, 프로토콜을 준수하는 모든 유형에서 구현되어야 하는 모든 메서드에 대한 인터페이스 역할을 하는 프로토콜을 작성합니다.
protocol Drivable {
var speed: Float { get set }
}
그런 다음 이를 준수하는 모든 유형에 기본 동작을 추가할 수 있습니다.
extension Drivable {
func accelerate(by: Float) {
speed += by
}
}
이제 다음을 구현하여 새 유형을 만들 수 있습니다.Drivable.
struct Car: Drivable {
var speed: Float = 0.0
init() {}
}
let c = Car()
c.accelerate(10)
기본적으로 다음과 같은 이점이 있습니다.
- 모든 것을 보장하는 시간 검사 컴파일
Drivable재봉제speed - 다음을 준수하는 모든 유형에 대해 default-behavior를 구현할 수 있습니다.
Drivable(accelerate) Drivable이것은 단지 프로토콜이기 때문에 인스턴스화되지 않을 것이 보장됩니다.
이 모델은 실제로 특성과 훨씬 더 유사하게 작동합니다. 즉, 여러 프로토콜을 준수하고 기본 구현을 수행할 수 있습니다. 반면 추상적인 슈퍼 클래스에서는 단순한 클래스 계층 구조로 제한됩니다.
여기가 자바에 가장 가까운 것 같습니다.abstract C의 또는 C#의abstract:
class AbstractClass {
private init() {
}
}
참로위의 는 다을해입니다.private수정자가 작동하려면 별도의 Swift 파일에서 이 클래스를 정의해야 합니다.
편집: 그러나 이 코드는 추상적인 메서드를 선언할 수 없으므로 강제로 구현할 수 없습니다.
가장 간단한 방법은 다음과 같은 통화를 사용하는 것입니다.fatalError("Not Implemented")(변수가 아닌) 프로토콜 확장의 추상적인 방법으로.
protocol MyInterface {
func myMethod() -> String
}
extension MyInterface {
func myMethod() -> String {
fatalError("Not Implemented")
}
}
class MyConcreteClass: MyInterface {
func myMethod() -> String {
return "The output"
}
}
MyConcreteClass().myMethod()
몇 주 동안 고심한 끝에 Java/PHP 추상 클래스를 Swift로 변환하는 방법을 알게 되었습니다.
public class AbstractClass: NSObject {
internal override init(){}
public func getFoodToEat()->String
{
if(self._iAmHungry())
{
return self._myFavoriteFood();
}else{
return "";
}
}
private func _myFavoriteFood()->String
{
return "Sandwich";
}
internal func _iAmHungry()->Bool
{
fatalError(__FUNCTION__ + "Must be overridden");
return false;
}
}
public class ConcreteClass: AbstractClass, IConcreteClass {
private var _hungry: Bool = false;
public override init() {
super.init();
}
public func starve()->Void
{
self._hungry = true;
}
public override func _iAmHungry()->Bool
{
return self._hungry;
}
}
public protocol IConcreteClass
{
func _iAmHungry()->Bool;
}
class ConcreteClassTest: XCTestCase {
func testExample() {
var concreteClass: ConcreteClass = ConcreteClass();
XCTAssertEqual("", concreteClass.getFoodToEat());
concreteClass.starve();
XCTAssertEqual("Sandwich", concreteClass.getFoodToEat());
}
}
하지만 애플은 일반적으로 대리인+프로토콜 패턴을 대신 사용하기 때문에 추상적인 클래스를 구현하지 않았다고 생각합니다.예를 들어 위의 동일한 패턴은 다음과 같이 수행하는 것이 좋습니다.
import UIKit
public class GoldenSpoonChild
{
private var delegate: IStomach!;
internal init(){}
internal func setup(delegate: IStomach)
{
self.delegate = delegate;
}
public func getFoodToEat()->String
{
if(self.delegate.iAmHungry())
{
return self._myFavoriteFood();
}else{
return "";
}
}
private func _myFavoriteFood()->String
{
return "Sandwich";
}
}
public class Mother: GoldenSpoonChild, IStomach
{
private var _hungry: Bool = false;
public override init()
{
super.init();
super.setup(self);
}
public func makeFamilyHungry()->Void
{
self._hungry = true;
}
public func iAmHungry()->Bool
{
return self._hungry;
}
}
protocol IStomach
{
func iAmHungry()->Bool;
}
class DelegateTest: XCTestCase {
func testGetFood() {
var concreteClass: Mother = Mother();
XCTAssertEqual("", concreteClass.getFoodToEat());
concreteClass.makeFamilyHungry();
XCTAssertEqual("Sandwich", concreteClass.getFoodToEat());
}
}
이러한 패턴이 필요했던 이유는 UITableViewController에서 viewWillAppear 등의 메서드를 공통화하고 싶었기 때문입니다.이것이 도움이 되었습니까?
프로토콜을 사용하여 추상 클래스를 시뮬레이션하는 방법이 있습니다.다음은 예입니다.
protocol MyProtocol {
func doIt()
}
class BaseClass {
weak var myDelegate: MyProtocol?
init() {
...
}
func myFunc() {
...
self.myDelegate?.doIt()
...
}
}
class ChildClass: BaseClass, MyProtocol {
override init(){
super.init()
self.myDelegate = self
}
func doIt() {
// Custom implementation
}
}
추상 클래스를 구현할 수 있는 또 다른 방법은 이니셜라이저를 차단하는 것입니다.저는 이런 식으로 해왔습니다.
class Element:CALayer { // IT'S ABSTRACT CLASS
override init(){
super.init()
if self.dynamicType === Element.self {
fatalError("Element is abstract class, do not try to create instance of this class")
}
}
}
정말 오래된 질문이지만 여전히...다음은 Swift 5.2에서 컴파일되고 의도한 대로 작동하는 실제 코드의 일부입니다.
protocol Context {
init() throws
func out(_ aStr: String) throws
// Other stuff
}
class AbstractContext: Context {
required init() throws {
if Self.self === AbstractContext.self {
preconditionFailure("Call to abstract method \(Self.self).\(#function)")
}
}
func out(_ aStr: String) throws {
preconditionFailure("Call to abstract method \(Self.self).\(#function)")
}
// Other stuff
}
class CompileContext: AbstractContext {
required init() throws {}
override func out(_ aStr: String) throws {
print(aStr)
}
// Other stuff
}
그리고 이것은 제가 제거한 후에 얻는 것입니다.CompileContext.out:
Fatal error: Call to abstract method CompileContext.out(_:): file swiftpg/contexts.swift, line 28
동적 디스패치가 없다는 제한을 통해 다음과 같은 작업을 수행할 수 있습니다.
import Foundation
protocol foo {
static var instance: foo? { get }
func prt()
}
extension foo {
func prt() {
if Thread.callStackSymbols.count > 30 {
print("super")
} else {
Self.instance?.prt()
}
}
}
class foo1 : foo {
static var instance : foo? = nil
init() {
foo1.instance = self
}
func prt() {
print("foo1")
}
}
class foo2 : foo {
static var instance : foo? = nil
init() {
foo2.instance = self
}
func prt() {
print("foo2")
}
}
class foo3 : foo {
static var instance : foo? = nil
init() {
foo3.instance = self
}
}
var f1 : foo = foo1()
f1.prt()
var f2 : foo = foo2()
f2.prt()
var f3 : foo = foo3()
f3.prt()
나는 그것을 만들기 위해 노력했습니다.Weather추상 수업, 하지만 프로토콜을 사용하는 것은 이상적이지 않았습니다. 왜냐하면 저는 같은 것을 써야 했기 때문입니다.init몇 번이고 되풀이되는 방법프로토콜 확장 및 문서 작성init방법에 문제가 있었습니다. 특히 제가 사용한 이후로.NSObjectNSCoding.
그래서 저는 이것을 생각해 냈습니다.NSCoding적합성:
required init?(coder aDecoder: NSCoder) {
guard type(of: self) != Weather.self else {
fatalError("<Weather> This is an abstract class. Use a subclass of `Weather`.")
}
// Initialize...
}
에 대해서는init:
fileprivate init(param: Any...) {
// Initialize
}
기본 클래스의 추상 속성 및 메서드에 대한 모든 참조를 프로토콜 확장 구현으로 이동합니다. 여기서 자체 제약 조건은 기본 클래스로 이동합니다.기본 클래스의 모든 메서드 및 속성에 액세스할 수 있습니다.추가적으로 컴파일러는 파생 클래스에 대한 프로토콜의 추상 메서드 및 속성 구현을 확인합니다.
protocol Commom:class{
var tableView:UITableView {get};
func update();
}
class Base{
var total:Int = 0;
}
extension Common where Self:Base{
func update(){
total += 1;
tableView.reloadData();
}
}
class Derived:Base,Common{
var tableView:UITableView{
return owner.tableView;
}
}
언급URL : https://stackoverflow.com/questions/24110396/abstract-classes-in-swift-language
'programing' 카테고리의 다른 글
| Sed를 사용하여 문자열을 포함하는 전체 줄 바꾸기 (0) | 2023.05.08 |
|---|---|
| .xls 파일을 읽고 쓸 수 있는 .NET Excel 라이브러리 (0) | 2023.05.08 |
| 단어 목록에 대한 PostgreSQL 와일드카드 LIKE (0) | 2023.05.08 |
| 요소에 공백이 있는 Bash 배열 (0) | 2023.05.08 |
| vba에서 dim과 set의 차이점은 무엇입니까? (0) | 2023.05.08 |