help@rskworld.in +91 93305 39277
RSK World
  • Home
  • Development
    • Web Development
    • Mobile Apps
    • Software
    • Games
    • Project
  • Technologies
    • Data Science
    • AI Development
    • Cloud Development
    • Blockchain
    • Cyber Security
    • Dev Tools
    • Testing Tools
  • About
  • Contact

Theme Settings

Color Scheme
Display Options
Font Size
100%
Back to Project
RSK World
swift-ios-calculator
RSK World
swift-ios-calculator
Swift iOS Calculator v1.0 - AI Math Solver + 3D Graphing + Apple Watch Integration + iOS Widgets + Siri Shortcuts + Currency Converter + Scientific Calculator + Matrix Operations + Platform Integration + Modern iOS Development
swift-ios-calculator
  • Assets.xcassets
  • Base.lproj
  • swift-ios-calculator.xcodeproj
  • AIMathSolverViewController.swift26.6 KB
  • AppDelegate.swift1.7 KB
  • CalculatorHistoryViewController.swift6.5 KB
  • CalculatorLogic.swift4.4 KB
  • CalculatorSettingsViewController.swift5.6 KB
  • CalculatorTheme.swift8.3 KB
  • CalculatorUtils.swift6.9 KB
  • CalculatorViewController.swift3.4 KB
  • CalculatorWidget.swift14.3 KB
  • CalculatorWidgetInfo.plist846 B
  • ChemistryCalculatorViewController.swift26.9 KB
  • CurrencyConverterViewController.swift13.3 KB
  • CustomFormulaBuilderViewController.swift22.1 KB
  • EngineeringCalculatorViewController.swift25.7 KB
  • EquationSolverViewController.swift22.8 KB
  • FinancialCalculatorViewController.swift27.5 KB
  • GeometryCalculatorViewController.swift29.7 KB
  • Graphing3DViewController.swift20.8 KB
  • GraphingCalculatorViewController.swift14.7 KB
  • Info.plist3.2 KB
  • LICENSE1.1 KB
  • MainTabBarController.swift22.3 KB
  • MatrixCalculatorViewController.swift26.6 KB
  • PRIVACY_POLICY.md1.6 KB
  • PhysicsCalculatorService.swift8.2 KB
  • ProgrammerCalculatorViewController.swift11 KB
  • README.md8.7 KB
  • RELEASE_NOTES.md6.5 KB
  • SceneDelegate.swift2.8 KB
  • ScientificCalculatorViewController.swift6.2 KB
  • SiriShortcutsManager.swift23.5 KB
  • Swift iOS Calculator.entitlements1.1 KB
  • UnitConverterViewController.swift14 KB
  • WatchCalculatorViewController.swift15.3 KB
  • index.html47.5 KB
CustomFormulaBuilderViewController.swift
CustomFormulaBuilderViewController.swift
Raw Download
Find: Go to:
//
//  CustomFormulaBuilderViewController.swift
//  Swift iOS Calculator
//
//  Created by RSK World on 23/01/2026.
//  Copyright © 2026 RSK World. All rights reserved.
//
//  Developer: Molla Samser (Founder, RSK World)
//  Designer & Tester: Rima Khatun
//  Contact: info@rskworld.com, +91 93305 39277
//  Website: https://rskworld.in
//  Address: Nutanhat, Mongolkote, Purba Burdwan, West Bengal, India - 713147
//

import UIKit

class CustomFormulaBuilderViewController: UIViewController {
    
    // MARK: - Outlets
    @IBOutlet weak var formulaNameTextField: UITextField!
    @IBOutlet weak var formulaExpressionTextView: UITextView!
    @IBOutlet weak var variablesTableView: UITableView!
    @IBOutlet weak var addVariableButton: UIButton!
    @IBOutlet weak var saveFormulaButton: UIButton!
    @IBOutlet weak var calculateButton: UIButton!
    @IBOutlet weak var clearButton: UIButton!
    @IBOutlet weak var savedFormulasTableView: UITableView!
    
    // MARK: - Properties
    private var variables: [FormulaVariable] = []
    private var savedFormulas: [CustomFormula] = []
    private let customFormulaManager = CustomFormulaManager()
    
    struct FormulaVariable {
        let id = UUID()
        var name: String
        var value: Double
        var unit: String
        
        init(name: String, value: Double = 0.0, unit: String = "") {
            self.name = name
            self.value = value
            self.unit = unit
        }
    }
    
    struct CustomFormula {
        let id = UUID()
        var name: String
        var expression: String
        var variables: [String]
        var createdAt: Date
        
        init(name: String, expression: String, variables: [String]) {
            self.name = name
            self.expression = expression
            self.variables = variables
            self.createdAt = Date()
        }
    }
    
    // MARK: - Lifecycle
    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
        setupTableViews()
        loadSavedFormulas()
    }
    
    // MARK: - Setup
    private func setupUI() {
        title = "Custom Formula Builder"
        view.backgroundColor = CalculatorTheme.shared.backgroundColor
        
        // Setup text field
        formulaNameTextField.backgroundColor = CalculatorTheme.shared.displayBackgroundColor
        formulaNameTextField.textColor = CalculatorTheme.shared.textColor
        formulaNameTextField.layer.cornerRadius = 8
        formulaNameTextField.layer.borderWidth = 1
        formulaNameTextField.layer.borderColor = CalculatorTheme.shared.buttonBackgroundColor.cgColor
        formulaNameTextField.placeholder = "Enter formula name"
        
        // Setup text view
        formulaExpressionTextView.backgroundColor = CalculatorTheme.shared.displayBackgroundColor
        formulaExpressionTextView.textColor = CalculatorTheme.shared.textColor
        formulaExpressionTextView.layer.cornerRadius = 8
        formulaExpressionTextView.layer.borderWidth = 2
        formulaExpressionTextView.layer.borderColor = CalculatorTheme.shared.accentColor.cgColor
        formulaExpressionTextView.font = UIFont.systemFont(ofSize: 16, weight: .medium)
        formulaExpressionTextView.text = "Enter formula (e.g., a * b + c)"
        
        // Setup buttons
        setupButton(addVariableButton, title: "+ Add Variable", color: .systemBlue)
        setupButton(saveFormulaButton, title: "Save Formula", color: .systemGreen)
        setupButton(calculateButton, title: "Calculate", color: .systemOrange)
        setupButton(clearButton, title: "Clear", color: .systemRed)
    }
    
    private func setupButton(_ button: UIButton, title: String, color: UIColor) {
        button.setTitle(title, for: .normal)
        button.backgroundColor = color
        button.setTitleColor(.white, for: .normal)
        button.layer.cornerRadius = 8
        button.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .medium)
    }
    
    private func setupTableViews() {
        // Setup variables table view
        variablesTableView.delegate = self
        variablesTableView.dataSource = self
        variablesTableView.backgroundColor = CalculatorTheme.shared.backgroundColor
        variablesTableView.layer.cornerRadius = 8
        variablesTableView.separatorStyle = .none
        
        // Setup saved formulas table view
        savedFormulasTableView.delegate = self
        savedFormulasTableView.dataSource = self
        savedFormulasTableView.backgroundColor = CalculatorTheme.shared.backgroundColor
        savedFormulasTableView.layer.cornerRadius = 8
        savedFormulasTableView.separatorStyle = .none
        
        // Register cells
        variablesTableView.register(UINib(nibName: "VariableCell", bundle: nil), forCellReuseIdentifier: "VariableCell")
        savedFormulasTableView.register(UINib(nibName: "FormulaCell", bundle: nil), forCellReuseIdentifier: "FormulaCell")
    }
    
    private func loadSavedFormulas() {
        savedFormulas = customFormulaManager.getAllFormulas()
        savedFormulasTableView.reloadData()
    }
    
    // MARK: - Actions
    @IBAction func addVariableButtonPressed(_ sender: UIButton) {
        showAddVariableAlert()
    }
    
    @IBAction func saveFormulaButtonPressed(_ sender: UIButton) {
        saveFormula()
    }
    
    @IBAction func calculateButtonPressed(_ sender: UIButton) {
        calculateFormula()
    }
    
    @IBAction func clearButtonPressed(_ sender: UIButton) {
        clearAll()
    }
    
    // MARK: - Methods
    private func showAddVariableAlert() {
        let alert = UIAlertController(title: "Add Variable", message: "Enter variable details", preferredStyle: .alert)
        
        alert.addTextField { textField in
            textField.placeholder = "Variable name (e.g., x, a, b)"
        }
        
        alert.addTextField { textField in
            textField.placeholder = "Value"
            textField.keyboardType = .decimalPad
        }
        
        alert.addTextField { textField in
            textField.placeholder = "Unit (optional)"
        }
        
        let addAction = UIAlertAction(title: "Add", style: .default) { [weak self] _ in
            guard let nameField = alert.textFields?[0],
                  let valueField = alert.textFields?[1],
                  let unitField = alert.textFields?[2],
                  let name = nameField.text, !name.isEmpty,
                  let value = Double(valueField.text ?? "0") else {
                return
            }
            
            let unit = unitField.text ?? ""
            let variable = FormulaVariable(name: name, value: value, unit: unit)
            self?.variables.append(variable)
            self?.variablesTableView.reloadData()
        }
        
        alert.addAction(addAction)
        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
        
        present(alert, animated: true)
    }
    
    private func saveFormula() {
        guard let name = formulaNameTextField.text, !name.isEmpty,
              let expression = formulaExpressionTextView.text, !expression.isEmpty else {
            showAlert(title: "Error", message: "Please enter formula name and expression")
            return
        }
        
        let variableNames = variables.map { $0.name }
        let formula = CustomFormula(name: name, expression: expression, variables: variableNames)
        
        customFormulaManager.saveFormula(formula)
        loadSavedFormulas()
        
        showAlert(title: "Success", message: "Formula saved successfully!")
    }
    
    private func calculateFormula() {
        guard let expression = formulaExpressionTextView.text, !expression.isEmpty else {
            showAlert(title: "Error", message: "Please enter a formula expression")
            return
        }
        
        let result = customFormulaManager.evaluateFormula(expression: expression, variables: variables)
        
        switch result {
        case .success(let value):
            let message = """
            Formula Result:
            
            Expression: \(expression)
            Result: \(String(format: "%.6f", value))
            
            Variables used:
            \(variables.map { "\($0.name) = \($0.value) \($0.unit)" }.joined(separator: "\n"))
            """
            
            showAlert(title: "Calculation Result", message: message)
            
            // Save to history
            saveToHistory(expression: expression, result: value)
            
        case .failure(let error):
            showAlert(title: "Calculation Error", message: error.localizedDescription)
        }
    }
    
    private func clearAll() {
        formulaNameTextField.text = ""
        formulaExpressionTextView.text = "Enter formula (e.g., a * b + c)"
        variables.removeAll()
        variablesTableView.reloadData()
    }
    
    private func saveToHistory(expression: String, result: Double) {
        let historyItem = CalculationHistoryItem(
            expression: "Custom: \(expression)",
            result: "Result: \(String(format: "%.6f", result))",
            category: "Custom Formula",
            date: Date()
        )
        
        CalculationHistoryManager.shared.addHistoryItem(historyItem)
    }
    
    private func showAlert(title: String, message: String) {
        let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default))
        present(alert, animated: true)
    }
}

// MARK: - UITableViewDataSource & UITableViewDelegate
extension CustomFormulaBuilderViewController: UITableViewDataSource, UITableViewDelegate {
    
    // MARK: - Variables Table View
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if tableView == variablesTableView {
            return variables.count
        } else {
            return savedFormulas.count
        }
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if tableView == variablesTableView {
            let cell = tableView.dequeueReusableCell(withIdentifier: "VariableCell", for: indexPath) as! VariableCell
            let variable = variables[indexPath.row]
            cell.configure(with: variable, delegate: self)
            return cell
        } else {
            let cell = tableView.dequeueReusableCell(withIdentifier: "FormulaCell", for: indexPath) as! FormulaCell
            let formula = savedFormulas[indexPath.row]
            cell.configure(with: formula, delegate: self)
            return cell
        }
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableView.automaticDimension
    }
    
    func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        return 60
    }
    
    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        if tableView == variablesTableView && editingStyle == .delete {
            variables.remove(at: indexPath.row)
            tableView.deleteRows(at: [indexPath], with: .fade)
        } else if tableView == savedFormulasTableView && editingStyle == .delete {
            let formula = savedFormulas[indexPath.row]
            customFormulaManager.deleteFormula(formula)
            savedFormulas.remove(at: indexPath.row)
            tableView.deleteRows(at: [indexPath], with: .fade)
        }
    }
}

// MARK: - Custom Formula Manager
class CustomFormulaManager {
    
    private let userDefaults = UserDefaults.standard
    private let formulasKey = "CustomFormulas"
    
    func saveFormula(_ formula: CustomFormulaBuilderViewController.CustomFormula) {
        var formulas = getAllFormulas()
        formulas.append(formula)
        saveFormulas(formulas)
    }
    
    func getAllFormulas() -> [CustomFormulaBuilderViewController.CustomFormula] {
        guard let data = userDefaults.data(forKey: formulasKey),
              let formulas = try? JSONDecoder().decode([CustomFormulaBuilderViewController.CustomFormula].self, from: data) else {
            return []
        }
        return formulas
    }
    
    func deleteFormula(_ formula: CustomFormulaBuilderViewController.CustomFormula) {
        var formulas = getAllFormulas()
        formulas.removeAll { $0.id == formula.id }
        saveFormulas(formulas)
    }
    
    func evaluateFormula(expression: String, variables: [CustomFormulaBuilderViewController.FormulaVariable]) -> Result<Double, Error> {
        var evaluatedExpression = expression
        
        // Replace variables with their values
        for variable in variables {
            evaluatedExpression = evaluatedExpression.replacingOccurrences(of: variable.name, with: "\(variable.value)")
        }
        
        // Replace mathematical functions
        evaluatedExpression = evaluatedExpression
            .replacingOccurrences(of: "sin", with: "Foundation.sin")
            .replacingOccurrences(of: "cos", with: "Foundation.cos")
            .replacingOccurrences(of: "tan", with: "Foundation.tan")
            .replacingOccurrences(of: "sqrt", with: "Foundation.sqrt")
            .replacingOccurrences(of: "log", with: "Foundation.log")
            .replacingOccurrences(of: "exp", with: "Foundation.exp")
            .replacingOccurrences(of: "abs", with: "Foundation.abs")
            .replacingOccurrences(of: "pi", with: "\(Double.pi)")
            .replacingOccurrences(of: "^", with: "**")
        
        // Evaluate using NSExpression
        guard let nsExpression = try? NSExpression(format: evaluatedExpression) else {
            return .failure(FormulaError.invalidExpression)
        }
        
        do {
            let result = try nsExpression.expressionValue(with: nil, context: nil)
            if let value = result as? Double {
                return .success(value)
            } else {
                return .failure(FormulaError.invalidResult)
            }
        } catch {
            return .failure(error)
        }
    }
    
    private func saveFormulas(_ formulas: [CustomFormulaBuilderViewController.CustomFormula]) {
        if let data = try? JSONEncoder().encode(formulas) {
            userDefaults.set(data, forKey: formulasKey)
        }
    }
}

// MARK: - Supporting Protocols and Classes
protocol VariableCellDelegate: AnyObject {
    func variableCell(_ cell: VariableCell, valueChanged: Double)
    func variableCell(_ cell: VariableCell, deleteVariable: FormulaVariable)
}

protocol FormulaCellDelegate: AnyObject {
    func formulaCell(_ cell: FormulaCell, loadFormula: CustomFormulaBuilderViewController.CustomFormula)
    func formulaCell(_ cell: FormulaCell, deleteFormula: CustomFormulaBuilderViewController.CustomFormula)
}

class VariableCell: UITableViewCell {
    
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var valueTextField: UITextField!
    @IBOutlet weak var unitLabel: UILabel!
    @IBOutlet weak var deleteButton: UIButton!
    
    weak var delegate: VariableCellDelegate?
    private var variable: CustomFormulaBuilderViewController.FormulaVariable?
    
    func configure(with variable: CustomFormulaBuilderViewController.FormulaVariable, delegate: VariableCellDelegate?) {
        self.variable = variable
        self.delegate = delegate
        
        nameLabel.text = variable.name
        valueTextField.text = String(format: "%.6f", variable.value)
        unitLabel.text = variable.unit
        
        // Apply theme
        backgroundColor = CalculatorTheme.shared.backgroundColor
        nameLabel.textColor = CalculatorTheme.shared.textColor
        valueTextField.backgroundColor = CalculatorTheme.shared.displayBackgroundColor
        valueTextField.textColor = CalculatorTheme.shared.textColor
        unitLabel.textColor = CalculatorTheme.shared.textColor
        
        // Setup text field
        valueTextField.layer.cornerRadius = 4
        valueTextField.layer.borderWidth = 1
        valueTextField.layer.borderColor = CalculatorTheme.shared.buttonBackgroundColor.cgColor
        valueTextField.textAlignment = .center
        valueTextField.keyboardType = .decimalPad
        
        // Setup delete button
        deleteButton.setTitle("Delete", for: .normal)
        deleteButton.backgroundColor = .systemRed
        deleteButton.setTitleColor(.white, for: .normal)
        deleteButton.layer.cornerRadius = 4
        
        // Add target
        valueTextField.addTarget(self, action: #selector(valueChanged), for: .editingChanged)
    }
    
    @objc private func valueChanged() {
        guard let text = valueTextField.text, let value = Double(text) else { return }
        variable?.value = value
        delegate?.variableCell(self, valueChanged: value)
    }
    
    @IBAction func deleteButtonPressed(_ sender: UIButton) {
        guard let variable = variable else { return }
        delegate?.variableCell(self, deleteVariable: variable)
    }
}

class FormulaCell: UITableViewCell {
    
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var expressionLabel: UILabel!
    @IBOutlet weak var variablesLabel: UILabel!
    @IBOutlet weak var loadButton: UIButton!
    @IBOutlet weak var deleteButton: UIButton!
    
    weak var delegate: FormulaCellDelegate?
    private var formula: CustomFormulaBuilderViewController.CustomFormula?
    
    func configure(with formula: CustomFormulaBuilderViewController.CustomFormula, delegate: FormulaCellDelegate?) {
        self.formula = formula
        self.delegate = delegate
        
        nameLabel.text = formula.name
        expressionLabel.text = formula.expression
        variablesLabel.text = "Variables: \(formula.variables.joined(separator: ", "))"
        
        // Apply theme
        backgroundColor = CalculatorTheme.shared.backgroundColor
        nameLabel.textColor = CalculatorTheme.shared.textColor
        expressionLabel.textColor = CalculatorTheme.shared.textColor
        variablesLabel.textColor = CalculatorTheme.shared.textColor
        
        // Setup buttons
        loadButton.setTitle("Load", for: .normal)
        loadButton.backgroundColor = .systemBlue
        loadButton.setTitleColor(.white, for: .normal)
        loadButton.layer.cornerRadius = 4
        
        deleteButton.setTitle("Delete", for: .normal)
        deleteButton.backgroundColor = .systemRed
        deleteButton.setTitleColor(.white, for: .normal)
        deleteButton.layer.cornerRadius = 4
    }
    
    @IBAction func loadButtonPressed(_ sender: UIButton) {
        guard let formula = formula else { return }
        delegate?.formulaCell(self, loadFormula: formula)
    }
    
    @IBAction func deleteButtonPressed(_ sender: UIButton) {
        guard let formula = formula else { return }
        delegate?.formulaCell(self, deleteFormula: formula)
    }
}

// MARK: - Error Types
enum FormulaError: LocalizedError {
    case invalidExpression
    case invalidResult
    case missingVariable
    
    var errorDescription: String? {
        switch self {
        case .invalidExpression:
            return "Invalid mathematical expression"
        case .invalidResult:
            return "Could not evaluate expression"
        case .missingVariable:
            return "Missing required variable"
        }
    }
}

// MARK: - Codable Extensions
extension CustomFormulaBuilderViewController.CustomFormula: Codable {
    enum CodingKeys: String, CodingKey {
        case id, name, expression, variables, createdAt
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let id = try container.decode(UUID.self, forKey: .id)
        let name = try container.decode(String.self, forKey: .name)
        let expression = try container.decode(String.self, forKey: .expression)
        let variables = try container.decode([String].self, forKey: .variables)
        let createdAt = try container.decode(Date.self, forKey: .createdAt)
        
        self.init(name: name, expression: expression, variables: variables)
        // Note: id and createdAt are read-only in the struct
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)
        try container.encode(name, forKey: .name)
        try container.encode(expression, forKey: .expression)
        try container.encode(variables, forKey: .variables)
        try container.encode(createdAt, forKey: .createdAt)
    }
}

// MARK: - Delegate Implementations
extension CustomFormulaBuilderViewController: VariableCellDelegate {
    func variableCell(_ cell: VariableCell, valueChanged: Double) {
        // Variable value changed
    }
    
    func variableCell(_ cell: VariableCell, deleteVariable: CustomFormulaBuilderViewController.FormulaVariable) {
        if let index = variables.firstIndex(where: { $0.id == deleteVariable.id }) {
            variables.remove(at: index)
            variablesTableView.reloadData()
        }
    }
}

extension CustomFormulaBuilderViewController: FormulaCellDelegate {
    func formulaCell(_ cell: FormulaCell, loadFormula: CustomFormulaBuilderViewController.CustomFormula) {
        formulaNameTextField.text = formula.name
        formulaExpressionTextView.text = formula.expression
        
        // Clear existing variables and add formula variables
        variables.removeAll()
        for variableName in formula.variables {
            variables.append(FormulaVariable(name: variableName))
        }
        variablesTableView.reloadData()
    }
    
    func formulaCell(_ cell: FormulaCell, deleteFormula: CustomFormulaBuilderViewController.CustomFormula) {
        customFormulaManager.deleteFormula(deleteFormula)
        loadSavedFormulas()
    }
}
566 lines•22.1 KB
swift

About RSK World

Founded by Molla Samser, with Designer & Tester Rima Khatun, RSK World is your one-stop destination for free programming resources, source code, and development tools.

Founder: Molla Samser
Designer & Tester: Rima Khatun

Development

  • Game Development
  • Web Development
  • Mobile Development
  • AI Development
  • Development Tools

Legal

  • Terms & Conditions
  • Privacy Policy
  • Disclaimer

Contact Info

Nutanhat, Mongolkote
Purba Burdwan, West Bengal
India, 713147

+91 93305 39277

hello@rskworld.in
support@rskworld.in

© 2026 RSK World. All rights reserved.

Content used for educational purposes only. View Disclaimer