Задание 1 Ваши решения

807 views
Skip to first unread message

tatiana.kornilova

unread,
Feb 7, 2015, 2:46:19 AM2/7/15
to swi...@googlegroups.com
Помешайте сюда свои решения Домашнего задания 1. Можно видео, но лучше ссылку на код для обсуждения вариантов решения.

tatiana.kornilova

unread,
Feb 7, 2015, 3:03:27 AM2/7/15
to swi...@googlegroups.com
Просьба не только смотреть решения, но и давать комментарии по поводу качества решений

Vladimir Kasatkin

unread,
Feb 7, 2015, 3:04:13 AM2/7/15
to swi...@googlegroups.com
Вот часть решения, там же публикую ссылки на видео по ходу обновлений: https://github.com/d3QUone/Calculator
Я еще не сделал второй дисплей для вывода истории операций. Зато поиграл с авто-размещением и притянул кнопки к краям, как в стандартном iOS-калькуляторе 

Vladimir Kasatkin

unread,
Feb 7, 2015, 1:01:49 PM2/7/15
to swi...@googlegroups.com
Тестирую свое решение на Айподе 5 (по железу должно быть аналог айфона 4S) и при нажатии на ввод (вызов функции enter не вводя никаких чисел в стэк) происходит Unwrapping Error - хотя условия, включенные в логику 

if let result = brain.pushOperand(displayValue){
   displayValue = result

} else {

   displayValue = 0

}


должны были это предотвращать. На симуляторах всё окей, как и Должно быть. В чем же проблема работы на железе? Какие идеи? 

Михаил Пашнёв

unread,
Feb 8, 2015, 9:18:29 AM2/8/15
to swi...@googlegroups.com
а displayValue не опциональное случаем?
суббота, 7 февраля 2015 г., 20:01:49 UTC+2 пользователь Vladimir Kasatkin написал:

Vladimir Kasatkin

unread,
Feb 8, 2015, 1:49:04 PM2/8/15
to swi...@googlegroups.com

Нет,  displayValue абсолютно Double


воскресенье, 8 февраля 2015 г., 17:18:29 UTC+3 пользователь Михаил Пашнёв написал:

tatiana.kornilova

unread,
Feb 11, 2015, 1:15:07 AM2/11/15
to swi...@googlegroups.com

Замечание. Если вы запускаете на реальном устройстве, в котором Регион установлен так, что там не применяется "." для десятичных чисел, приложение закончится аварийно. Но на симуляторе оно работает.

Решение смотрите на сайте - в разделе Задание 1

Vladimir Kasatkin

unread,
Feb 12, 2015, 11:24:18 AM2/12/15
to swi...@googlegroups.com
То есть лучше заменить Точку на Запятую? Может лучше сделать определение/изменение региона и в зависимости от этого выдавать вьюху? Как стандартный калькулятор короче


среда, 11 февраля 2015 г., 9:15:07 UTC+3 пользователь tatiana.kornilova написал:

tatiana.kornilova

unread,
Feb 12, 2015, 11:02:10 PM2/12/15
to swi...@googlegroups.com
Да, это об этом, о запятой и Регионе. Но я не пробовала. Попробуйте сменить Регион. Потом расскажите.

четверг, 12 февраля 2015 г., 19:24:18 UTC+3 пользователь Vladimir Kasatkin написал:

Алексей Ракеев

unread,
Feb 19, 2015, 6:29:35 PM2/19/15
to swi...@googlegroups.com
В NsNumberFormatter есть проп decimalSeparator, там будет точка или запятая в зависимости от локали.
Вот пример — после загрузки вьюшки текущий decimalSeparator пишется в title кнопки, и в appendDigit символ сравнивается с ним же.

tatiana.kornilova

unread,
Feb 20, 2015, 8:43:28 AM2/20/15
to swi...@googlegroups.com

Да, здорово! Вы даже поместили символ на  кнопку.

Dmitrii Tyrylgin

unread,
Feb 26, 2015, 11:38:59 PM2/26/15
to swi...@googlegroups.com
А кто-нибудь рассматривал вариант решения задачи с плавающей точкой на основе подсказки (Hints, пункты 1 и 2)? Интересует реализация в одну строчку, у меня получилось следующее, может есть у кого еще мысли по этому поводу. Интересно было бы посмотреть.

@IBAction func appendDigit(sender: UIButton) {


        let digit = sender.currentTitle!


        if userIsInTheMiddleOfTypingANumber {


            display.text! += display.text!.rangeOfString(".") != nil && digit == "." ? "" : digit


        }


        else {


            display.text = digit


            userIsInTheMiddleOfTypingANumber = true


        }


    }



Алексей Ракеев

unread,
Feb 27, 2015, 5:34:06 AM2/27/15
to swi...@googlegroups.com
Да, я примерно так же делал (но там, разумеется, никаким locale-aware не пахнет, точка в качестве разделителя захардкожена)

tatiana.kornilova

unread,
Feb 27, 2015, 6:48:40 AM2/27/15
to swi...@googlegroups.com
Да, Дмитрий, вы изобретательны в составлении условий, надо отдать вам должное. Но позвольте на вашем примере показать, как все-таки сделать действительно одной строкой и действовать в соответствии с логикой iOS 8.  
Вы привязали кнопку с точкой к тому же самому Action AppendDigit, что и цифры, но логика их использования - разная. Вначале вы их "смешали" : и "точку", и цифры в одну func, а потом изобретательно разделяете. Как говорится, "сами нашли себе работу". 
Я предлагаю для кнопки с "точкой" создать отдельный Action

    @IBAction func decimalPoint(sender: UIButton) {

        if !userAlreadyEnteredADecimalPoint {

            appendDigit(sender)

            userAlreadyEnteredADecimalPoint = true

        }

    }

В этом коде вы фактически используете одну строку  userAlreadyEnteredADecimalPoint = true, если точки еще нет в вашем числе, а дальше просите поработать appendDigit.
Какие плюсы?
Смотрите как выглядит код 

    @IBAction func appendDigit(sender: UIButton) {

        let digit = sender.currentTitle!

        //        println("digit = \(digit)");

        

        if userIsInTheMiddleOfTypingANumber {

            //----- Уничтожаем лидирующие нули ---------------

            if (digit == "0") && (display.text == "0") { return }

            if (digit != ".") && (display.text == "0") { display.text = digit ; return }

            //--------------------------------------------------

            display.text = display.text! + digit

        } else {

            display.text = digit

            userIsInTheMiddleOfTypingANumber = true

        }

    }


   @IBAction func decimalPoint(sender: UIButton) {

        if !userAlreadyEnteredADecimalPoint {

            appendDigit(sender)

            userAlreadyEnteredADecimalPoint = true

        }

    }


Понятно, где искать логику для обработки "точки".
 Если еще добавляется логика в , например, для устранения "лидирующих" нулей, то там "точка" не путается "под ногами".

Конечно, ваше решение абсолютно верно, но попробуйте найти более компактные и, главное, читаемые варианты кода.


Алексей Ракеев

unread,
Feb 27, 2015, 7:17:03 AM2/27/15
to swi...@googlegroups.com
Все это конечно замечательно, только вы вводите по сути избыточное поле, которое вынуждены потом сбрасывать еще в двух местах. Забудете где-то сбросить — получите сложно вылавливаемую ошибку. Между тем, единственное назначение этой переменной — проверять наличие точки на дисплее.
Простое условие display.text?.rangeOfString(".") != nil делает то же самое, только работает всегда, вне зависимости от вашей внимательности и памяти.

Если вам так нравится идея использования поля, то хотя бы сделайте его вычисляемым, а не хранимым:

userAlreadyEnteredADecimalPoint: Bool {
    return display.text?.rangeOfString(".") != nil
}

Тогда и читаемость сохранится, и уйдут разбросанные по коду артефакты вида userAlreadyEnteredADecimalPoint = true/false

tatiana.kornilova

unread,
Feb 27, 2015, 7:26:42 AM2/27/15
to swi...@googlegroups.com
А зачем ему всегда работать? Пусть работает только там, где нужно, а со сбросом - справимся, голова  на плечах все-таки имеется.


Алексей Ракеев

unread,
Feb 27, 2015, 7:46:18 AM2/27/15
to swi...@googlegroups.com
Да, действительно. Зачем программе всегда надежно работать, быть легкой в сопровождении и расширении? Спагетти родней и глазу приятней. Ну, каждому свое. Удачи

tatiana.kornilova

unread,
Feb 28, 2015, 1:02:28 AM2/28/15
to swi...@googlegroups.com
Без эмоций предлагаю компромиссный вариант
Все-таки отдельный Action с кодом

    @IBAction func decimalPoint(sender: UIButton) {

        let noPointOnDisplay = display.text?.rangeOfString(".") == nil

        if (noPointOnDisplay) || !(noPointOnDisplay || userIsInTheMiddleOfTypingANumber) {

            appendDigit(sender)

        }

    }


Может быть стало понятнее, но ушел стиль программирования.
 На вашем месте я бы убрала и  userIsInTheMiddleOfTypingANumber.
Нужно быть последовательным во всем.

Алексей Ракеев

unread,
Mar 1, 2015, 9:27:55 AM3/1/15
to swi...@googlegroups.com
С userIsInTheMiddleOfTypingANumber все несколько сложнее. Мы должны иметь возможность трактовать display как пустой, когда он фактически не пуст. Например, при выводе результата вычисления последующие нажатия цифровых кнопок должны затирать его. Я бы с радостью избавился и от этого поля, но не представляю как это можно сделать.

Александр

unread,
Mar 4, 2015, 3:18:38 PM3/4/15
to swi...@googlegroups.com
Здравствуйте! Занимаюсь второй день по первому заданию, в первый день посмотрел лекции профессора, благодаря переводам Татьяны, стал более лучше понимать о том, что говорить профессор. Сейчас застрял, на задание, где нужно что бы второй Label отображал всю историю ввода. До этого разобрался, как правильно работать в Auto Layout. 


Введите код...import UIKit


class ViewController: UIViewController {


    @IBOutlet weak var display: UILabel!

    @IBOutlet weak var historyLabel: UILabel!

    

    var userWriteANumber: Bool = false

    var userWriteAPoint: Bool = false

    

    @IBAction func digit(sender: UIButton) {

        let number = sender.currentTitle!

        if userWriteANumber  {

            display.text = display.text! + number

        } else {

            display.text = number

            userWriteANumber = true

        }

    }

    

    @IBAction func points(sender: UIButton) {

        if  userWriteANumber{

            digit(sender)

            userWriteANumber = true

        }

        

    }


    var arrayDigit = Array<Double>()

    

    @IBAction func returnDigit() {

        userWriteANumber = false

        arrayDigit.append(displayValue!)

        historyLabel.text = historyLabel.text! + "\(arrayDigit.description)"

        println("return digit = \(arrayDigit)")

        

    }

    

    var displayValue: Double! {

        get {

            return NSNumberFormatter().numberFromString(display.text!)!.doubleValue

        }

        set {

            display.text = "\(newValue)"

            userWriteANumber = false

        }

        

    }

    

    @IBAction func operand(sender: UIButton) {

        let operation = sender.currentTitle!

        if userWriteANumber {

            returnDigit()

        }

        switch operation  {

        case "×": action { $0 * $1 }

        case "÷": action { $1 / $0 }

        case "−": action { $1 - $0 }

        case "+": action { $0 + $1 }

        case "√": action { sqrt($0) }

        case "sin": action { sin($0) }

        case "cos": action { cos($0) }

        default: break

        }

    }


    func action(operation: (Double, Double) -> Double) {

        if arrayDigit.count >= 2 {

            displayValue = operation(arrayDigit.removeLast(), arrayDigit.removeLast())

            returnDigit()

        }

    }

    

    func action(operation: (Double) -> Double) {

        if arrayDigit.count >= 1 {

            displayValue = operation(arrayDigit.removeLast())

            returnDigit()

        }

    }


    @IBAction func PI() {

        let pi = M_PI

        userWriteANumber = true

        if userWriteANumber {

            displayValue = pi

        }

    }

    


    

 

    

   /* func action(operation: (Double, Double) -> Double) {

        if arrayDigit.count >= 2 {

            displayValue = operation(arrayDigit.removeLast(), arrayDigit.removeLast())

            returnDigit()

        }

    }

    func action(operation: Double -> Double){

        if arrayDigit.count >= 1 {

            displayValue = operation(arrayDigit.removeLast())

            returnDigit()

        }

    }

    

    

    

    */

    

    

    

    override func viewDidLoad() {

        super.viewDidLoad()

        // Do any additional setup after loading the view, typically from a nib.

    }


    override func didReceiveMemoryWarning() {

        super.didReceiveMemoryWarning()

        // Dispose of any resources that can be recreated.

    }

    /* var story: String! {

    get {

    return NSNumberFormatter().stringFromNumber(displayValue)!

    }

    set {

    historyLabel.text = "\(newValue)"

    userWriteANumber = false

    }

    }

    

    func history() {

    if userWriteANumber {

    historyLabel.text = historyLabel.text!

    } else {

    historyLabel.text = historyLabel.text! + story

    userWriteANumber = true

    }

    }

    */


}







IMG_0476.jpg

Александр

unread,
Mar 4, 2015, 3:20:12 PM3/4/15
to swi...@googlegroups.com
Еще хотела поблагодарить Татьяну, за то что она подсказала, что нужно изменить регион, так как на форуме Apple люди не понимали из-за чего рушиться приложение. Я так понимаю задание нужно сделать, меньше чем за 7 дней?


tatiana.kornilova

unread,
Mar 5, 2015, 1:15:33 AM3/5/15
to swi...@googlegroups.com
Для того, чтобы не зависеть Региона лучше получать в вашем калькуляторе разделитель десятичной точки

let decimalSeparator = NSNumberFormatter().decimalSeparator
Потом сделать outlet для кнопки с условным название "точка"
@IBOutlet weak var tochka: UIButton!

И в viewDidLoad() 
выставить заголовок этой условной точки
override func viewDidLoad() { super.viewDidLoad()
tochka.setTitle(format.decimalSeparator, forState: UIControlState.Normal) } Посмотрите как сделано у Алексея Ракеева https://github.com/rakeev/cs193-calc/blob/master/Calculator/ViewController.swift

Александр

unread,
Mar 12, 2015, 2:32:19 PM3/12/15
to swi...@googlegroups.com
Спасибо большое!

Erbol Gabdullin

unread,
Mar 22, 2015, 3:06:04 AM3/22/15
to swi...@googlegroups.com
 Почему format.decimalSeparator ?

четверг, 5 марта 2015 г., 12:15:33 UTC+6 пользователь tatiana.kornilova написал:

tatiana.kornilova

unread,
Mar 22, 2015, 3:12:50 AM3/22/15
to swi...@googlegroups.com
Добавьте
let format = NSNumberFormatter()
А лучше посмотрите у Алексея Ракеева https://github.com/rakeev/cs193-calc/blob/master/Calculator/ViewController.swift Это его очень хорошая идея.

воскресенье, 22 марта 2015 г., 10:06:04 UTC+3 пользователь Erbol Gabdullin написал:

Erbol Gabdullin

unread,
Mar 22, 2015, 4:04:54 AM3/22/15
to swi...@googlegroups.com
let decimalSeparator = NSNumberFormatter().decimalSeparator

и 

let format = NSNumberFormatter()

тогда

format.decimalSeparator => NSNumberFormatter().NSNumberFormatter().decimalSeparator

воскресенье, 22 марта 2015 г., 13:12:50 UTC+6 пользователь tatiana.kornilova написал:

tatiana.kornilova

unread,
Mar 22, 2015, 6:20:09 AM3/22/15
to swi...@googlegroups.com
Лучше будет так (решение не на все случаи жизни, но все же):

    @IBOutlet weak var tochka: UIButton!

    

    let decimalSeparator = NSNumberFormatter().decimalSeparator ?? "."

    override func viewDidLoad() {

        super.viewDidLoad()

        tochka.setTitle(decimalSeparator, forState: UIControlState.Normal)

    }

И далее по тексту
....

   @IBAction func appendDigit(sender: UIButton) {

        let digit = sender.currentTitle!

        //        println("digit = \(digit)");

        

        if userIsInTheMiddleOfTypingANumber {

            //----- Уничтожаем лидирующие нули ---------------

            if (digit == "0") && (display.text == "0") { return }

            if (digit != decimalSeparator) && (display.text == "0") { display.text = digit ; return }

            //--------------------------------------------------

            display.text = display.text! + digit

        } else {

            if digit == decimalSeparator {

                display.text = "0" + decimalSeparator

            } else {

                display.text = digit

            }

            userIsInTheMiddleOfTypingANumber = true

        }

    }

    

    @IBAction func decimalPoint(sender: UIButton) {

        let noPointOnDisplay = display.text?.rangeOfString(decimalSeparator) == nil

        if (noPointOnDisplay) || !noPointOnDisplay && !userIsInTheMiddleOfTypingANumber {

            appendDigit(sender)

        }

    }

......


воскресенье, 22 марта 2015 г., 11:04:54 UTC+3 пользователь Erbol Gabdullin написал:

Erbol Gabdullin

unread,
Apr 1, 2015, 2:13:36 AM4/1/15
to swi...@googlegroups.com
Прочитал в решении первого задания у Корниловой, что числовые константы "пи" и "е" можно определить как тип объекта Op

Такой подход упрощает очистку словаря для переменных

У меня при инициализации модели константы и их значения помещались в словарь для переменных. Это неудобно в том смысле, что когда очищаешь словарь приходится заново помещать туда значения констант

суббота, 7 февраля 2015 г., 13:46:19 UTC+6 пользователь tatiana.kornilova написал:
Помешайте сюда свои решения Домашнего задания 1. Можно видео, но лучше ссылку на код для обсуждения вариантов решения.

Ilya Dolgopolov

unread,
Aug 13, 2015, 2:05:20 PM8/13/15
to Swift [ru]
Привет, всем,

с начала я реализовал делитель дробной части так:

метод по нажатию кнопки "."

    @IBAction func addPoint(sender: UIButton) {

        if pointButton.enabled {

            appendDigit(sender)

            pointButton.enabled = false

        }

        

    }


в методе enter() также добавил:

pointButton.enabled = true


Работает как надо, но недовало покоя, что можно реализовать одной строкой, нашел реддите ссылку на проект (тут)

в итоге у меня реализация стала таковой:

    @IBAction func addPoint(sender: UIButton) {

        if display.text!.rangeOfString(decimalSeparator) == nil {

                appendDigit(sender)

        }

    }


суббота, 7 февраля 2015 г., 10:46:19 UTC+3 пользователь tatiana.kornilova написал:

tatiana.kornilova

unread,
Aug 14, 2015, 3:25:54 AM8/14/15
to Swift [ru]
Да, ваше последнее решение и есть решение в одну строку. Но дело даже не в количестве строк, а в том, что вы на этой очень маленькой задачке представили два подхода: один - императивный, то есть вы фиксируете некоторые состояния (в нашем случае наличие точки) и используете это состояние для изменения UI ; второй - можно назвать функциональным, то есть знать ничего не знаю, что было раньше, все буду вычислять сначала. Во втором случае не нужно хранить никакие состояния и переустанавливать их, он считается более безопасным с точки зрения возможных ошибок. Современная тенденция программирования склоняется в эту сторону. Если вам интересно, дискуссия на эту тему уже была на этом форуме: посмотрите ответ Алексея Макеева и мой пост "Задание 2. Решение - начало..."
Ваше первое решение с enable  мне очень нравится, так как явно показывает пользователю, что точка уже введена. Мы все как-то забыли об этом простом приеме. В то время как в случае решения в одну строку, пользователь нажимает на кнопку ".", а она не появляется на дисплее и нет никаких сообщений, так что непонятно, то ли приложение не работает, то ли вторая точка уже лишняя.

четверг, 13 августа 2015 г., 21:05:20 UTC+3 пользователь Ilya Dolgopolov написал:

Ilya Dolgopolov

unread,
Aug 14, 2015, 4:23:47 AM8/14/15
to Swift [ru]
Спасибо, за такой классный ответ. Я в итоге оставил 2-й вариант, т.к. мне кажется он больше соотвествует стилю Swift и некой концепции MVC от Apple, меня свойства UI больше в стиле  с#, delphi и тп, ИМХО.

Я продолжаю, честно говоря, пока с другом, делать первый асесмент (в том числе дополнительные задания)

Моя реализация кнопки Pi:

    @IBAction func enterPi(sender: UIButton) {

        if userIsInTheMiddleOfTypingANumber {

            enter()

            AddPiIntoDisplayAndStack()

        } else {

            AddPiIntoDisplayAndStack()

        }

    }

    

    func AddPiIntoDisplayAndStack (){

        display.text = "\(M_PI)"

        enter()

    }


Явно программирование не в одну строчку, но пока ничего не приходит другого.


Вопрос про 4 пункт основных заданий, поле UILabel достаточно добавить? реализация остальной логики будет в следующих заданиях?

просто с этим как-то не понятно.


Продолжу выполнять доп-ные задания 1-го ассесмента, если никто не против, буду делиться для оценки. на данный момент только 3-й день знакомства с SWIFT :)


пятница, 14 августа 2015 г., 10:25:54 UTC+3 пользователь tatiana.kornilova написал:

Ilya Dolgopolov

unread,
Aug 14, 2015, 4:39:33 AM8/14/15
to Swift [ru]
и еще один вопрос в догонку, судя по описанию решения 1-го ассемента, он должен был делаться после 3-й лекции? или все таки после 2-й? т.к. я начал делать после 2-й, а у вас, судя по коду, уже произошло разделение контролера на модель и контролер.


пятница, 14 августа 2015 г., 10:25:54 UTC+3 пользователь tatiana.kornilova написал:
Да, ваше последнее решение и есть решение в одну строку. Но дело даже не в количестве строк, а в том, что вы на этой очень маленькой задачке представили два подхода: один - императивный, то есть вы фиксируете некоторые состояния (в нашем случае наличие точки) и используете это состояние для изменения UI ; второй - можно назвать функциональным, то есть знать ничего не знаю, что было раньше, все буду вычислять сначала. Во втором случае не нужно хранить никакие состояния и переустанавливать их, он считается более безопасным с точки зрения возможных ошибок. Современная тенденция программирования склоняется в эту сторону. Если вам интересно, дискуссия на эту тему уже была на этом форуме: посмотрите ответ Алексея Макеева и мой пост "Задание 2. Решение - начало..."

Ilya Dolgopolov

unread,
Aug 14, 2015, 6:37:52 AM8/14/15
to Swift [ru]
Вопрос, в описании решения представлен код

корректно ли вместо него использовать конструкцию:

display.text = "\(newValue)" ?? " "


В описании тут, как я понял, говорится, что ?? функция для обработки, когда optional  может вернуть nil

tatiana.kornilova

unread,
Aug 14, 2015, 6:47:48 AM8/14/15
to Swift [ru]
Конечно  можно, профессор читал лекции и мы выполняли задание 1, когда был Swift 1.0 и такой возможности не было. Эта возможность появилась только в Swift 1.2. Сейчас Swift 1.2, но в сентябре официально будет Swift 2.0. Не торопитесь, выполняйте все в Swift 1.2. 

пятница, 14 августа 2015 г., 13:37:52 UTC+3 пользователь Ilya Dolgopolov написал:

Ilya Dolgopolov

unread,
Aug 14, 2015, 7:12:31 AM8/14/15
to Swift [ru]
Дело, в том, что я не могу выполнять все в 1.2, у меня детка публичная, а там 2.0

мне кажется конструкция display.text = "\(newValue)" ?? " " некорректная, тк ?? " " относиться к тексту, а если newValue будет nil, то оно не будет преобразовано в текст. Это мои соображения, поправьте, пожалуйста, если я не прав

я оставил так  

            if let new = newValue {

                display.text = "\(new)"

            } else {

                display.text = " "

            }

 

пятница, 14 августа 2015 г., 13:47:48 UTC+3 пользователь tatiana.kornilova написал:

tatiana.kornilova

unread,
Aug 14, 2015, 7:54:14 AM8/14/15
to Swift [ru]
Оператор ??  используется для замещения nil значения в Optional (в нашем случае newValue)
Можно так
display.text = "\(newValue ?? 0)" , 
 но будет 0 вместо пробела

пятница, 14 августа 2015 г., 14:12:31 UTC+3 пользователь Ilya Dolgopolov написал:

Ilya Dolgopolov

unread,
Aug 14, 2015, 8:02:52 AM8/14/15
to Swift [ru]
Да, я уже дошел до этого, но тогда суть задания нарушается.

Кстати, может отдельную ветку создать, обсуждать отличия Swift 2 от предыдущих версий? т.к. меньше через месяц, выйдет новая ОС, а там и измения

К примеру я не нахожу глобальных функций countElements и dropLast, 

они появляются если сделать display.text!.characters.count и display.text!.characters.dropLast но тогда тип возвращаемого значение, какой-то не понятный

tatiana.kornilova

unread,
Aug 14, 2015, 8:23:00 AM8/14/15
to Swift [ru]
Было бы неплохо, но я пока не располагаю временем пересматривать Задания 1 и 2 для Swift 2.0.
Честно говоря, я жду осеннюю сессию 2015 в Stanford, где уже объявлено, что профессор Пол Хэгерти будет опять читать свой курс и уже для Swift 2.0.
Конечно, он может не выбрать калькулятор в качестве демонстрационного примера, но в любом случае он поставит все на свои места в плане использования синтаксиса Swift 2.0
Если вы перепишите Assignment 1 и 2 Stanford Winter 2015 для Swift 2.0 было бы классно - открывайте ветку, это будет интересно, я по мере сил и времени вас поддержу.

пятница, 14 августа 2015 г., 15:02:52 UTC+3 пользователь Ilya Dolgopolov написал:

tatiana.kornilova

unread,
Aug 14, 2015, 8:29:53 AM8/14/15
to Swift [ru]
Кстати, Swift 2.0 гораздо сильнее отличается от Swift 1.2, чем Swift 1.2 от Swift 1.0, кроме того 5-ая бэта версия Swift 2.0 вообще является своего рода революционной.
Но все равно, конечно, нужно двигаться к Swift 2.0 


пятница, 14 августа 2015 г., 15:02:52 UTC+3 пользователь Ilya Dolgopolov написал:
Да, я уже дошел до этого, но тогда суть задания нарушается.

Тимур Усманов

unread,
Aug 16, 2015, 5:35:26 AM8/16/15
to Swift [ru]
Здравствуйте! Я начал изучение языка Swift по лекциям и вашим переводам. И у меня возникла такая проблема: я разместил элементы UI почти так же как профессор Хэгарти, однако у меня возникла следующая проблема:
Профессор в своих лекциях запускает всё на симуляторе iPhone 6. У меня есть пятый айфон и я хочу позже запускать свой первый калькулятор на своем айфоне. Пока я запускаю его в симуляторе именно 5-го айфона. И вот при расположении элементов UI  как показно на скриншоте в симуляторе не показывается самый правый ряд кнопок. Не подскажите как это решается? Autolayout не выдает никаких предупреждений. Спасибо. 



tatiana.kornilova

unread,
Aug 16, 2015, 6:14:47 AM8/16/15
to Swift [ru]
Autolayout  может и не давать никаких сообщений, а элементы UI могут уходить за пределы экрана. Профессор это демонстрировал на примере метки display. Чтобы что-то сказать, нужен доступ к коду. Можно через Github или Dropbox или как-то еще дайте ссылку на ваш код. 

воскресенье, 16 августа 2015 г., 12:35:26 UTC+3 пользователь Тимур Усманов написал:

Тимур Усманов

unread,
Aug 16, 2015, 6:52:46 AM8/16/15
to Swift [ru]
Татьяна, вот ссылка на гитхаб:
https://github.com/senator14/firstcalculator

воскресенье, 16 августа 2015 г., 16:14:47 UTC+6 пользователь tatiana.kornilova написал:

tatiana.kornilova

unread,
Aug 16, 2015, 9:14:51 AM8/16/15
to Swift [ru]
Тимур, у вас задан Autolayout для метки display, но совсем нет настроек Autolayout для кнопок с цифрами и операциями. Вам нужно закончить изучать Лекцию 2 - ее 3-ая часть посвящена тому, как нужно настроить механизм Autolayout для "сетки" (grid) кнопок. У меня есть перевод этой третьей части Лекции 2, полностью посвященной  Autolayout. Кроме того есть готовое Задание 1 - его можно посмотреть на Github. Если в этом Задании вы выделите любую кнопку с цифрами и перейдете в Инспектор Размера, где можно посмотреть какие "ограничения" система Autolayout создала для вас, то увидите следующую картину.

У Вас ничего подобного нет.

воскресенье, 16 августа 2015 г., 13:52:46 UTC+3 пользователь Тимур Усманов написал:

Тимур Усманов

unread,
Aug 17, 2015, 2:02:39 AM8/17/15
to Swift [ru]
Татьяна, спасибо большое! Действительно, прочитал следующую лекцию и это стало понятно. Я смог разместить кнопки как мне нужно и использовал Auto layouts из статьи. Однако возникла проблема: в портретном режиме он показывает всё как и задумано, однако в ландшафтном кнопки наезжают на дисплей, не подскажите, как это исправить? В Auto layouts есть разграничения для портретного и ландшафтного режимов? Спасибо. Ссылка на гитхаб https://github.com/senator14/firstcalculator

воскресенье, 16 августа 2015 г., 19:14:51 UTC+6 пользователь tatiana.kornilova написал:
Тимур, у вас задан Autolayout для метки display, но совсем нет настроек Autolayout для кнопок с цифрами и операциями. Вам нужно закончить изучать Лекцию 2 - ее 3-ая часть посвящена тому, как нужно настроить механизм Autolayout для "сетки" (grid) кнопок. У меня есть перевод этой третьей части Лекции 2, полностью посвященной  Autolayout. Кроме того есть готовое Задание 1 - его можно посмотреть на Github. Если в этом Задании вы выделите любую кнопку с цифрами и перейдете в Инспектор Размера, где можно посмотреть какие "ограничения" система Autolayout создала для вас, то увидите следующую картину.

У Вас ничего подобного нет.

tatiana.kornilova

unread,
Aug 17, 2015, 3:53:47 AM8/17/15
to Swift [ru]
У вас в 5-том ряду кнопок вместо 4-х кнопок - 3. Чтобы сработало все как у профессора, нужна точная сетка кнопок, если кнопка не нужна - создайте фиктивную. Никаких специальных настроек для портретного и ландшафтного режима не нужно, не нужно настраивать и для iPhone 5 или iPhone 6. Суть Autolayout в том, чтобы не проводить настройки для отдельных приборов. Есть концепция Size Class, когда настраиваются отдельно портретный или ландшафтный режимы, но это только если интерфейсы принципиально различаются. Например, в портретном режиме - 4 х 6, а в ландшафтном - 6 x 5. Исправьте сетку кнопок - все должно работать. Можете посмотреть мое решение на Github. Можно сравнить настройки кнопок.

понедельник, 17 августа 2015 г., 9:02:39 UTC+3 пользователь Тимур Усманов написал:

tatiana.kornilova

unread,
Aug 17, 2015, 3:54:34 AM8/17/15
to Swift [ru]
У вас в 5-том ряду кнопок вместо 4-х кнопок - 3. Чтобы сработало все как у профессора, нужна точная сетка кнопок, если кнопка не нужна - создайте фиктивную. Никаких специальных настроек для портретного и ландшафтного режима не нужно, не нужно настраивать и для iPhone 5 или iPhone 6. Суть Autolayout в том, чтобы не проводить настройки для отдельных приборов. Есть концепция Size Class, когда настраиваются отдельно портретный или ландшафтный режимы, но это только если интерфейсы принципиально различаются. Например, в портретном режиме - 4 х 6, а в ландшафтном - 6 x 5. Исправьте сетку кнопок - все должно работать. Можете посмотреть мое решение на Github. Можно сравнить настройки кнопок.

понедельник, 17 августа 2015 г., 9:02:39 UTC+3 пользователь Тимур Усманов написал:

tatiana.kornilova

unread,
Aug 17, 2015, 10:14:43 AM8/17/15
to Swift [ru]
В моей версии работоспособность на iPhone 4s и iPhone 5 обеспечивается другим значением ( 749 ) Content Compression Resistance Priority для метки  display. 

этот материал представлен на Лекции 8.



понедельник, 17 августа 2015 г., 9:02:39 UTC+3 пользователь Тимур Усманов написал:

Тимур Усманов

unread,
Aug 20, 2015, 2:43:03 AM8/20/15
to Swift [ru]
Татьяна, спасибо. По инструкциям профессора всё получалось, затем я захотел попробовать сделать такой же интерфейс, как у родного калькулятор в iOS 

понедельник, 17 августа 2015 г., 20:14:43 UTC+6 пользователь tatiana.kornilova написал:
В моей версии работоспособность на iPhone 4s и iPhone 5 обеспечивается другим значением ( 749 ) Content Compression Resistance Priority для метки  display. 

этот материал представлен на Лекции 8.

Тимур Усманов

unread,
Aug 20, 2015, 2:51:58 AM8/20/15
to Swift [ru]
Вопрос для всех, скорее, даже не вопрос, а тема для размышление. Когда я использовал функцию sin() и проверял на своем калькуляторе, то результаты очень сильно расходились с результатами калькуляторов в iOS и Mac. Так, если посчитать синус 45 на своем калькуляторе, то он выдает значение 0,850..... Если на любом другом калькуляторе, то выдается 0,707..... 

Углубившись в вопрос, я понял, что функции sin() и cos() по умолчанию принимают значения в радианах, а не градусах. И вот тут возникает тема для дискуссии: профессор ничего не говорил об этом и я проверил код некоторых участников этой группы на гитхабе, у них так же это оставлено по умолчанию. Я же посчитал, что с точки зрения юзабилити это не совсем правильно, ведь обычный пользователь больше привык оперировать градусами, да и в родных калькуляторах Apple кнопка включения вычисления в радианах вынесена отдельно, что предполагает ввод значения в градусах по умолчанию. Значит, считать по умолчанию в градусах будет более соответствовать гайдам Apple. А что вы думаете об этом?

P.S. Мой вопрос на стэковерфлоу с фиксом данной проблемы: http://stackoverflow.com/questions/32046853/trigonometric-functions-in-swift


суббота, 7 февраля 2015 г., 13:46:19 UTC+6 пользователь tatiana.kornilova написал:

tatiana.kornilova

unread,
Aug 21, 2015, 3:57:50 AM8/21/15
to Swift [ru]
Дело в том, что профессор предлагает сосредоточиться в Задании 1 на синтаксисе языка Swift, и в частности, на способах обращения к функциям, в которых аргументом является функция, и эта функция является последним параметром. То есть к функции можно обращаться, указав замыкание в качестве параметра-функции и вынося его за круглые скобки в случае, если это хвостовое замыкание, то есть так:
performOperation {$1/$0},
 а можно опустить входные и выходные параметры вообще, если тип входных и выходных параметров функции при вызове соответствует указанным в определении самой функции, в этом случае остается одно название функции,то есть так:
 performOperation (sin).

 Для этого случае и взята функция sin. Поэтому все, кто следовал за профессором были сосредоточены на синтаксисе Swift. Да и в Задании 1 не было указания вычислять sin и cos для градусов. Но с точки зрения  юзабилити  вы правы и следовало бы ввести какой-нибудь UI элемент для задания переключения радианов в градусы и писать, например, такой код

 case "sin": isRadian ? performOperation (sin) : performOperation {sin ($0 * M_PI /180.0)}

И все-таки в Задании 1, которое считается самым легким и является  как  бы "разминкой", не следует увлекаться юзабилити. Но это мое мнение.
  
четверг, 20 августа 2015 г., 9:51:58 UTC+3 пользователь Тимур Усманов написал:

Тимур Усманов

unread,
Aug 25, 2015, 5:09:09 PM8/25/15
to Swift [ru]
Татьяна, формула sin ($0 * M_PI /180.0) дает удивительные результаты для синуса 180 градусов :)

А первое задание, мне как человеку в программирование практически с нуля, кажется достаточно тяжелым, по крайней мере дисплей с историей так и не получилось прикрутить пока (((

пятница, 21 августа 2015 г., 13:57:50 UTC+6 пользователь tatiana.kornilova написал:

tatiana.kornilova

unread,
Aug 26, 2015, 1:23:27 AM8/26/15
to Swift [ru]
Вы молодец! Действительно, что называется "не верь глазам своим"

Но формула работает правильно. Видите в конце три точки? Это значит, что число не уместилось в текстовом поле. Вот мой результат эксперимента на Playground

Здесь негативно работают сразу два фактора. Один - это то, что мы используем String interpolation, то есть код в set {} displayValue выглядит так

   var displayValue: Double? {


        get {

            if let displayText = display.text {

               return numberFormatter().numberFromString(displayText)?.doubleValue

            }

            return nil

        }

        set {

            if (newValue != nil) {

               display.text = "\(newValue!)"

              // display.text = numberFormatter().stringFromNumber(newValue!)

            } else {

                display.text = " "

                addHistory( "= Error")

            }

            userIsInTheMiddleOfTypingANumber = false


        }

    }



 String interpolation для числа Double упорно старается представить все 15 цифр после точки, даже если они незначащие. Поэтому лучше использовать при выводе числа NSNumberFormatter(), но об этом позже.

Второй фактор - нам не хватило места в метке на iPhone 5, чтобы увидеть правильное число. Для того, чтобы это исправить, нужно правильно настроить метку display.

Сейчас у вас стоит, что если понадобится сжать текст в метке, то все равно будет использоваться фиксированный фонт


а вам нужно , чтобы он уменьшался в случае, если понадобится сжатие




Внизу указан размер минимального фонта.

Это исправит вывод результата следующим образом



Ну а для того, чтобы избавиться от такого некрасивого представления 0, используем форматирование.


 var displayValue: Double? {

        get {

            if let displayText = display.text {

               return numberFormatter().numberFromString(displayText)?.doubleValue

            }

            return nil

        }

        set {

            if (newValue != nil) {

             //    display.text = "\(newValue!)"

               display.text = numberFormatter().stringFromNumber(newValue!)

            } else {

                display.text = " "

                addHistory( "= Error")

            }

            userIsInTheMiddleOfTypingANumber = false


        }

    }

    

    func numberFormatter () -> NSNumberFormatter{

        let numberFormatterLoc = NSNumberFormatter()

        numberFormatterLoc.numberStyle = .DecimalStyle

        numberFormatterLoc.maximumFractionDigits = 10

        numberFormatterLoc.notANumberSymbol = "Error"

        numberFormatterLoc.groupingSeparator = " "

        return numberFormatterLoc

    }


Тогда вы получите правильный результат




Теперь я понимаю, почему Пол Хэгерти отказался от градусов на первых лекциях - слишком много тонкостей нужно объяснять вначале.
Но ваше упорство достойно всякой похвалы.
Что касается метки с историей - то смотрите коды других людей и на первых этапах просто повторяйте, что они делают, пытаясь понять почему они так делают. 
У меня есть код на Github для первого задания. Пойдите по этой метке https://github.com/BestKora/Calculator-cs193p-Winter-2015-Assigment-1 и скачайте мой вариант Задания 1 к себе на Mac.
Любые ваши вопросы приветствуются.

среда, 26 августа 2015 г., 0:09:09 UTC+3 пользователь Тимур Усманов написал:

Тимур Усманов

unread,
Aug 26, 2015, 11:53:04 AM8/26/15
to Swift [ru]
Татьяна, спасибо :)

По поводу Пи не соглашусь с вами. Во-первых, под удивительным я имел в виду, что ответ выдается не 0, а другой. И дело не в том, что число не помещается в калькулятор, а в плэйграунде выводится полностью. Дело в том, что это совсем не то число, которое должно быть. И это не некрасивое представление 0, это результат приближенного деления. Дело в том, что число Пи возвращается не полностью и этот инструментарий просто не может обеспечить нужную точность. Вы нашли выход, но там слишком много строк кода и допускаются упущения. На стэковерфлоу мне посоветовали фунуцию __sinpi(x). Из документации Эппл:
The __sinpi() function returns the sine of pi times x (measured in radians). This can be computed more accurately than sin(M_PI * x), because it can implicitly use as many bits of pi as are necessary to deliver a well-rounded result, instead of the 53-bits to which M_PI is limited. For large x it may also be more efficient, as the argument reduction involved is significantly simpler.

То есть, эта функция намного более точно вычисляет пи и таким образом код в моем случае выглядит просто:
case "Pi": PerformOperation { __sinpi($0/180) }
И результаты возвращает правильные. Единственный минус, по-моему мнению, то, что эта функция доступна только с iOS 7 и, соответственно, не будет поддерживаться старыми iOS. 

А по поводу истории, я смотрел коды участников форума и ваш, но у вас всё идет уже через brainCalculator и всё реализовано по другому, а мой калькулятор на стадии после первых двух лекций, где все идет через кейсы и я не смог внедрить ваш код в свой (((

среда, 26 августа 2015 г., 11:23:27 UTC+6 пользователь tatiana.kornilova написал:
Вы молодец! Действительно, что называется "не верь глазам своим"

Но формула работает правильно. Видите в конце три точки? Это значит, что число не уместилось в текстовом поле. Вот мой результат эксперимента на Playground

Здесь негативно работают сразу два фактора. Один - это то, что мы используем String interpolation, то есть код в set {} displayValue выглядит так

   var displayValue: Double? {


        get {

            if let displayText = display.text {

               return numberFormatter().numberFromString(displayText)?.doubleValue

            }

            return nil

        }

        set {

            if (newValue != nil) {

               display.text = "\(newValue!)"

              // display.text = numberFormatter().stringFromNumber(newValue!)

            } else {

                display.text = " "

                addHistory( "= Error")

            }

            userIsInTheMiddleOfTypingANumber = false


        }

    }



 String interpolation для числа Double упорно старается представить все 15 цифр после точки, даже если они незначащие. Поэтому лучше использовать при выводе числа NSNumberFormatter(), но об этом позже.

Второй фактор - нам не хватило места в метке на iPhone 5, чтобы увидеть правильное число. Для того, чтобы это исправить, нужно правильно настроить метку display.

Сейчас у вас стоит, что если понадобится сжать текст в метке, то все равно будет использоваться фиксированный фонт


а вам нужно , чтобы он уменьшался в случае, если понадобится сжатие




Внизу указан размер минимального фонта.

Это исправит вывод результата следующим образом



Ну а для того, чтобы избавиться от такого некрасивого представления 0, используем форматирование.


 var displayValue: Double? {

        get {

            if let displayText = display.text {

               return numberFormatter().numberFromString(displayText)?.doubleValue

            }

            return nil

        }

        set {

            if (newValue != nil) {

             //    display.text = "\(newValue!)"

               display.text = numberFormatter().stringFromNumber(newValue!)

            } else {

                display.text = " "

                addHistory( "= Error")

            }

            userIsInTheMiddleOfTypingANumber = false


        }

    }

    

    func numberFormatter () -> NSNumberFormatter{

        let numberFormatterLoc = NSNumberFormatter()

        numberFormatterLoc.numberStyle = .DecimalStyle

        numberFormatterLoc.maximumFractionDigits = 10

        numberFormatterLoc.notANumberSymbol = "Error"

        numberFormatterLoc.groupingSeparator = " "

        return numberFormatterLoc

    }


Тогда вы получите правильный результат




tatiana.kornilova

unread,
Aug 26, 2015, 12:08:09 PM8/26/15
to Swift [ru]
По поводу __sinpi(x) не знала. По поводу истории:  да, раньше у меня был код для Задания 1 с разделенной Моделью и Контроллером, но после того, как кто-то обратил на это внимание, я полностью переделала Задание 1, где только ViewController и нет CalculatorBrain. Я полностью переделала и пост, и код Задания 1 дня 3-4 назад, так что стоит посмотреть. Кстати там интересные функции работы со строками, которых в CalculatorBrain уже не будет. Еще раз даю ссылку на новый пост  Задание 1 cs193p Winter 2015 Калькулятор Swift 1.2 и Swift 2.0 и на код в Github  https://github.com/BestKora/Calculator-cs193p-Winter-2015-Assigment-1.

среда, 26 августа 2015 г., 18:53:04 UTC+3 пользователь Тимур Усманов написал:

tatiana.kornilova

unread,
Aug 26, 2015, 12:31:23 PM8/26/15
to Swift [ru]
Попробовала - здорово! Я вычисляла sin (720) обычным способом через умножение на M_PI и ошибка все равно накапливалась, а тут - все точно. Еще раз спасибо.

среда, 26 августа 2015 г., 18:53:04 UTC+3 пользователь Тимур Усманов написал:
Reply all
Reply to author
Forward
0 new messages