Как сделать приличный код с классами из этого [Swift]

Я делаю приложение OSX для управления устройством через последовательный порт, для чего я использую библиотеку ORSSerialPort. Но у меня есть некоторые проблемы с кодированием. Я (очень) новичок в кодировании и понятия не имею, как правильно кодировать, что вызывает некоторые проблемы при попытке заставить что-то работать. Я покажу свои три "класса", опишу их функции и затем столкнусь с проблемами.

Основной класс, к которому подключен делегат библиотеки и из которого я делаю все коммуникации с последовательным устройством (AE20125Controller.swift)

import Cocoa
import ORSSerial

class AE20125Controller:NSObject, ORSSerialPortDelegate {

    var buffer = String()
    var dataProcessor = DataProcessor()

    var availablePorts = ORSSerialPortManager.sharedSerialPortManager().availablePorts

    @IBOutlet weak var selectedPort: NSPopUpButton!
    @IBOutlet weak var connectButton: NSButton!
    @IBOutlet weak var connectedLogo: NSStackView!

    var serialPort: ORSSerialPort? {
        didSet {
            oldValue?.close()
            oldValue?.delegate = nil
            serialPort?.delegate = self
        }
    }

    //Actions
    @IBAction func onOpenOrClose(sender: AnyObject) {
        if let port = self.serialPort {
            if (port.open) {
                closePort(port)

            } else {
                openPort(port)
            }
        }
    }

    //Functions
    func sendData(command: String) -> Bool {
        if let data = command.dataUsingEncoding(NSUTF8StringEncoding) {
            self.serialPort?.sendData(data)
            return true
        }
        return false
    }

    func closePort(port: ORSSerialPort){
        port.close()
        self.connectButton.title = "Verbinden"
        self.connectedLogo.hidden = true
    }

    func openPort(port: ORSSerialPort){
        port.baudRate = 9600
        port.open()
        sendData("201:T:0:;") //Gets all settings form the device
        self.connectedLogo.hidden = false
        self.connectButton.title = "Verbreken"
    }

    //Delegate
    func serialPort(serialPort: ORSSerialPort, didReceiveData data: NSData) {
        if let string = NSString(data: data, encoding: NSUTF8StringEncoding) {
            var message: String

            //Assemble the full data (Data come's in in parts)
            buffer.appendContentsOf(string as String)
            if(buffer.containsString(dataProcessor.endToken)){
                let i = buffer.rangeOfString(dataProcessor.startToken)?.startIndex
                let j = buffer.rangeOfString(dataProcessor.endToken)?.endIndex

                if((i != nil) && (j != nil)){
                    message = buffer[Range(start: i!, end: j!)]
                    buffer.removeRange(Range(start: i!, end: j!))

                    if(message != "" /*message != "201:U:0:;"*/){
                        dataProcessor.sortIncomingData(message)
                    }
                }
            }
        }
    }

    func serialPortWasRemovedFromSystem(serialPort: ORSSerialPort) {
        serialPort.close()
    }

}

Класс Dataprocessor, в котором хранятся все возможные сообщения и формы, которые я хочу собрать для отправки данных и всех текущих настроек (DataProcessor.swift)

import Foundation

class DataProcessor {

    enum dataType: String {
        case frequency = "A"
        case waveform = "B"
        case mode = "C"
        case pllReferenceEnabled = "D"
        case pllFactor = "E"
        case pllOffset = "F"
        case startUpWavefrom = "G"
        case startUpFrequency = "H"
        case calibrationOffset = "I"
        case sweepStartFrequency = "J"
        case sweepStopFrequency = "K"
        case sweepFrequency = "L"
        case modulationType = "M"
        case fskFrequency = "N"
        case pskPhase = "O"
        case modulationSource = "P"
        case internalModulationFrequency = "Q"
        case sweepMode = "R"
        case getSettings = "T"
        case keepAlive = "U"
        case returnFromSweepMod = "V"
        case hardwareRevison = "X"
        case firmwareVersion = "Y"
        case productID = "Z"
        case present1Freq = "1"
        case present1Waveform = "2"
        case present2Freq = "3"
        case present2Waveform = "4"
        case present3Freq = "5"
        case present3Waveform = "6"
        case present4Freq = "7"
        case present4Waveform = "8"
        case present5Freq = "9"
        case present5Waveform = "0"

        func getWritable() -> Bool {
            switch self {
            case .frequency, .waveform, .mode, .pllReferenceEnabled, .pllFactor, .pllOffset, .startUpWavefrom, .startUpFrequency, .calibrationOffset, .sweepStartFrequency, .sweepStopFrequency, .sweepFrequency, .modulationType, .fskFrequency, .pskPhase, .modulationSource, .internalModulationFrequency,.sweepMode, .getSettings, .returnFromSweepMod, .present1Freq, .present1Waveform,.present2Freq,.present2Waveform, .present3Freq, .present3Waveform, .present4Freq, .present4Waveform, .present5Freq, .present5Waveform:
                return true

            default:
                return false
            }
        }

        func getReadable() -> Bool {
            switch self {
            case .frequency, .waveform, .mode, .pllReferenceEnabled, .pllFactor, .pllOffset, .startUpWavefrom, .startUpFrequency, .calibrationOffset, .sweepStartFrequency, .sweepStopFrequency, .sweepFrequency, .modulationType, .fskFrequency, .pskPhase, .modulationSource, .internalModulationFrequency, .sweepMode, .keepAlive, .hardwareRevison, .firmwareVersion, .productID:
                return true

            default:
                return false
            }

        }

       func getMaxValues() -> Int{
            switch self {
            case .frequency:
                return 10000000
            case .waveform:
                return 3
            case .mode:
                return 3
            case .pllReferenceEnabled:
                return 2
            case .pllFactor:
                return 9999
            case .pllOffset:
                return 10000000
            case .startUpWavefrom:
                return 3
            case .startUpFrequency:
                return 10000000
            case .calibrationOffset:
                return 10000
            case .sweepStartFrequency:
                fallthrough
            case .sweepStopFrequency:
                return 10000000
            case .sweepFrequency:
                return 100
            case .modulationType:
                return 2
            case .fskFrequency:
                return 10000000
            case .pskPhase:
                return 3599
            case .modulationSource:
                return 2
            case .internalModulationFrequency:
                return 10000
            case .sweepMode:
                return 2
            case .getSettings:
                return 0
            case .returnFromSweepMod, .present1Freq, .present2Freq, .present3Freq, .present4Freq, .present5Freq:
                return 10000000
            case .present1Waveform, .present2Waveform, .present3Waveform, .present4Waveform, .present5Waveform:
                return 3

            default:
                return -1
            }
        }
    }


    let endToken = ":;"
    let startToken = "201:"

    var settings:[(dataType):(String)] = [:]

    //Methodes
    func sortIncomingData(data: String){
        let i = data.rangeOfString(startToken)?.endIndex
        let j = data.rangeOfString(endToken)?.startIndex

        let sortedCode = data.substringWithRange(Range(start: i!, end: i!.advancedBy(1)))
        let sortedData = data.substringWithRange(Range(start: i!.advancedBy(2), end: j! ))

        settings[dataType(rawValue: sortedCode)!] = sortedData

    }

    func setData(data: dataType, value: Float){
        settings.updateValue(String(value), forKey: data)
        AE20125Controller.sendData(...) //<-- Is not working (Ignore the     dots)

    }
}

Класс menuItems, который должен обрабатывать все изменения и действия в графическом интерфейсе. (MenuItems.swift)

import Cocoa

class MenuItems:NSObject{
    @IBOutlet weak var freqView: NSView!
    @IBOutlet weak var test: NSTextField!

    //Actions
    @IBAction func setFreq(sender: AnyObject) {

    }


}

Я упустил AppDelegate, так как в нем ничего нет, кроме настроек для построения представления (например, изменение фона вида на белый).

Я не могу связаться между классами, например, мне нужно отправить данные с помощью метода sendData в классе AE20125Controller в классе DataProcessor, но мне нужно его инициировать. Но класс DataProcessor инициируется в классе AE20125Controller? Это также относится к классу MenuItems, когда при нажатии кнопки updateFreq должен вызываться метод setData в классе DataProcessor, но мне нужно его инициировать.

Если честно, я понятия не имею, что я делаю, как правильно эту систему, чтобы все работало, не помещая все в один файл, чтобы я мог держать это организованным. Опять же, я новичок в программировании, но (если можно так сказать сам) у меня есть некоторые знания в программировании. Пожалуйста, помогите мне организовать мой (дрянной) код и дать несколько советов, как этого избежать в будущем.

(Если вы знаете хорошее руководство по программированию Advanced Swift OSX / курс, пожалуйста, скажите мне. (Это не обязательно должно быть бесплатно))

заранее спасибо

1 ответ

Способ общения между различными частями в вашем приложении - с помощью NSNotificationCenter. Проверьте здесь для документации: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/

Изменить: В этом случае я бы предложил сделать синглтон для вашего общения:

class Communicator:NSObject, ORSSerialPortDelegate {
    class let sharedInstance = Communicator()
}

так что вы можете позвонить:

Communicator.sharedInstance.sendData(...)
Другие вопросы по тегам