Cgrect swift что это
Русские Блоги
CGRect, CGSize и CGPoint в Swift
После того, как я перешел на Swift, я постепенно отказался от написания быстрого кода в стиле OC и начал использовать преимущества языка.
Но недавно я узнал, что CGGeometry Для структуры я все еще использую уродливый, не в стиле Swift код. CGGeometry Структура относится к:
Грамматика в стиле С, овца в волчьей шкуре
У меня есть сильное предчувствие, что многие программисты Swift чувствуют себя виноватыми по этому поводу. Поднимите руку, если вы написали следующий код:
Не волнуйтесь, этого не стоит стесняться.
Проблема с этим написанием состоит в том, что он не соответствует грамматическому стилю Swift. Хотя он может работать нормально, он больше похож на фрагмент OC или даже Java-кода.
Опытный разработчик iOS может сразу понять значение этих строк кода, они не нуждаются в CGGeometry Имя параметра в функции инициализации структуры. Но Swift надеется быть дружелюбным ко всем новичкам. Если они увидят эти коды с первого взгляда, они будут в недоумении, потому что не смогут понять значение этих чисел. Следовательно, мы должны использовать версию кода Swift:
Хотя код стал немного многословным, теперь он хорошо читается. И еще одно дополнительное преимущество заключается в том, что параметры не должны ограничиваться CGFloat Типа, мы также можем использовать Int с участием Double Тип параметра. Проверить это CGRect Определение структуры и CGRectMake Определение функции легко понять:
Вы все еще можете использовать такой код:
Пришло время обновить вашу систему знаний и использовать грамматику быстрого стиля. Не волнуйтесь, в новом синтаксисе нужно добавить только один символ:
Получите ценность
Если вы были или все еще являетесь отличным разработчиком OC, вам следовало написать такой код, чтобы получить значение в структуре:
Но давайте сначала подумаем, почему мы не можем получить значение напрямую? Например:
For this reason, your applications should avoid directly reading and writing the data stored in the CGRect data structure. Instead, use the functions described here to manipulate rectangles and to retrieve their characteristics.
Изменчивость
Теперь вы можете не только напрямую изменять значение в структуре, но и напрямую заменять всю подструктуру:
Одной этой функции нам достаточно, чтобы отказаться от OC и инвестировать в Swift. Нам не нужно воссоздавать экземпляр структуры и изменять его. Менее двух лет назад наши разработчики OC были вынуждены написать такой код:
Не знаю, что вы думаете, но написание такого кода сводит меня с ума. По мнению frame Создайте заново структуру, измените ее, а затем поместите вид frame Изменяйте эту структуру, до свидания, никогда больше!
Последнее слово
Вышеупомянутые изменения также применимы к другим структурам в UIKit:
Пример кода можно найти вГитхаб автораНайти на
Swift: CGRect, CGSize & CGPoint
You’re (probably) doing it wrong
It’s been about a solid eight months since I first decided to jump completely into the Swift wormhole. Over those months I’ve slowly learned to stop writing Objective-C style code patterns with Swift syntax, and started to actually take advantage of the new language.
But one thing I’ve recently picked up on is that I’m still using ugly non-Swift-like syntax with all my CGGeometry structures.
C syntax. A sheep in wolf’s clothing
I have a big feeling that a lot of Swift developers are going to be guilty of this. Raise your hand if you have been using either of these in your code:
Update: As of Swift 3, these functions have been removed.
Yea, I thought so. But don’t worry, it’s nothing to be ashamed of …yet.
The thing that’s wrong with this is that it breaks Swift’s coding convention, it will still work, but it looks a lot more like something that if it belongs in Objective-C or even, dare I say it, Java. *shudders*
To a seasoned iOS or OSX developer, with a short glance they could easily tell you what that code is doing. They don’t need argument labels on CGGeometry structures because everyone knows those arguments, and their sequence off by heart. Except they don’t.
A lot of what Swift is about is being friendly to language newcomers as well as complete programming beginners. If they were to look at that code, they would have no idea what those numbers represent. So let’s all vow to be good Swift citizens and start using the Swift versions:
Update: As of Swift 3, these functions have been removed.
While we’re at it, you’re probably still using these too, amirite? lel.
We should also be updating these to use the newer, Swiftier syntax. But don’t worry, the syntax is only just an extra character longer. Can you guess what it is?
Value retrieval
Update: As of Swift 3, these functions have been removed.
If you were or still are a good Objective-C citizen, you would have used these value getters when you wanted a specific value of the rect. But wait a second, why don’t we just access the values directly?
For this reason, your applications should avoid directly reading and writing the data stored in the CGRect data structure. Instead, use the functions described here to manipulate rectangles and to retrieve their characteristics.
There’s probably still a lot of you that didn’t bother with such formalities, but that’s ok. Swift has alleviated us of such an unpretty API and instead provided simple dot notation variables.
There’s plenty more examples of these niceties available in the Swift playgrounds I’ve provided to supplement this post. The link will be at the bottom of the page.
Mutability
Not only are you able to change individual values of a view’s frame, but you’re also able to replace entire sub-structs completely. Behold:
This little feature alone is enough of a reason to stop using Objective-C. Mutability on CGRect s without having to create a new one entirely and reset the value. It was only less than two years ago that we as Objective-C developers were forced to write frame modification code like this:
I don’t know about you, but writing that really stressed me out. Creating a newFrame struct from the view ’s frame, modifying it, and then resetting the frame property on the view again. No thank you, not ever, ever again please.
Don’t forget
There are also a couple of other constructs within UIKit for which these changes are applicable to:
Sample code of this post can be found on GitHub.
Seven useful methods from CGRect
Insetting, offsetting, transformation, and more!
The humble CGRect struct might seem like a primitive beast, but it has a number of useful methods that let you adjust rectangles i a variety of ways.
Here are two simple CGRect instances we can work with:
You can see that they overlap each other, and CGRect has three methods that let us evaluate that overlap. The first is the simplest: intersects() returns true if two rectangles overlap. In our case, this would be true:
If you want more details, the intersection() method tells you where the intersection lies. Both our rectangles are 100 points wide, but the second one starts at X:50 and Y:50 so that’s where our overlap will begin. So, this code will return a new CGRect containing X:50 Y:50 width:70 height:70:
The third option is the contains() method, which will return true if one rectangle entirely contains another. So, this will return false for us because the second rectangle lies partly outside the first:
For example, this will produce a rectangle at X:40 Y:40 width:60 height:60:
You’re specifying how much to grow or shrink the rectangle horizontally ( dx ) and vertically ( dy ) – these numbers apply to all four edges, which is why a horizontal change of 20 took our width from 100 to 60.
You can also make rectangles larger, like this:
I find negative insets helpful if you’re drawing behind something and want to make sure you have a fixed amount of margin on all edges.
So, this will move our rectangle 10 points down and to the right:
For more advanced transformations, you can apply any CGAffineTransform to a CGRect by calling its applying() method. You should experiment in a playground first, though – these transforms work in their own unique way.
As an example, take a look at this code:
Our rect1 constant had X:20 Y:20 width:100 height:100, so after scaling by 2x there are several possible outcomes. For example, you might think that X and Y stay the same, but width and height double, or you might think that width and height double, but X and Y go down by 50 so the rectangle stays centered.
However, what this method actually does is scale up all four coordinate components: X, Y, width, and height all double, meaning that the finished rectangle starts at X:40 Y:40 – it has been scaled relative to the top-left corner.
As an example, we could divide rect1 into two rectangles, with the first slice taking up the first 40% of rect1 and the remainder taking up everything else:
All these methods are things you could yourself, usually in a dozen lines of code or less. But do you really want to be spending your time thinking about rectangle transformations when Apple can do all that work for you? Probably not. CGRect isn’t a complex struct, but it’s worth letting it work its magic where possible!
SPONSORED Only until this Sunday, December 12th, you can join a free crash course to learn advanced techniques for testing new and legacy Swift code — it’s the fast track to becoming a complete Senior iOS Developer!
About the author
Paul Hudson is the creator of Hacking with Swift, the most comprehensive series of Swift books in the world. He’s also the editor of Swift Developer News, the maintainer of the Swift Knowledge Base, and a speaker at Swift events around the world. If you’re curious you can learn more here.
Стиль написания кода на Swift
Стиль написания кода на Swift
Имена
Используйте наглядные имена с использованием заглавных букв, для обозначения нового слова: в именах классов, переменных, методов и т.д. Имена классов и констант на уровне модуля должны начинаться с большой буквы, в то время как, имена методов и переменных должны начинаться с маленькой.
Предпочтительно
Не предпочтительно
Для функций и методов инициализации, предпочитают именованные параметры, для всех аргументов, если контекст не очень ясный. Также, хорошо использовать включение имен внешних параметров, если это делает вызов функции более читабельным.
Касательно метода, хорошо работает стандартное соглашение об использовании первого параметра, в качестве ссылки имени самого метода:
Перечисления
Используйте Горбатую нотацию Верхнего регистра для элементов перечислений
Проза
Когда вы ссылаетесь на функцию, как внутри текста (статьи, книги, комментарии), включайте необходимые имена параметров, а не вырывайте только название функции. Это придаст вашему коду большей ясности. То есть, к примеру, вы можете написать про метод tableView, но лучше, в развернутом виде tableView(_:cellForRowAtIndexPath:).
Если сомневаетесь, то вы всегда можете посмотреть как Xcode перечисляет свои методы в выпадающей панели. Наш стиль соответствует его стилю.
Префиксы класса
Типы в Swift автоматически обретают пространство имени в том модуле, в котором они содержатся. И как результат, для того, чтобы свести к минимуму конфликты имен, префиксы не требуются. Если два имени из разных модулей сталкиваются, вы можете разделить их, используя префикс имени типа с именем модуля:
Вам не следует добавлять префиксы к вашим типам Swift.
Если вам нужно работать с типом Swift в языке Objective-C, то вы можете использовать подходящий префикс, как например:
Расстановка пробелов
Предпочитительно
Не предпочтительно
Комментарии
Используйте комментарии для объяснения почему конкретный кусок кода делает что-то. Комментарии должны быть актуальными или удаленными.
Избегайте блочных комментариев встроенных в код, по возможности весь код должен быть максимально понятным, чтобы не требовалось комментариев. Исключение: это правило не относится к тем комментариям, которые используются для генерации документации.
Классы и структуры
Что из них использовать?
Иногда, что-то должно быть структурой, но должно соответствовать AnyObject или исторически так сложилось, что это уже является классом (NSDate, NSSet). Попробуйте следовать инструкциям настолько, насколько это возможно:
Пример объявления
Пример отлично стилизованного объявления класса:
Пример выше демонстрирует следующие стилистические установки:
Использование Self
Для сокращения кода избегайте использования self, так как Swift не требует его для доступа к свойствам объектов или вызовам методов.
Используйте self, когда требуется разграничить между собой имена свойства и инициализаторы аргументов, или когда ссылаетесь на свойства в выражениях замыкания (как требует компилятор):
Соответствие протоколу
Когда добавляете соответствие протоколу классу, то лучше добавить отдельное расширение класса, для методов протокола. Это оставляет связанные методы, сгруппированные вместе с протоколом, и упрощает действия по его добавлению.
Предпочтительно
Не предпочтительно
class MyViewcontroller: UIViewController, UITableViewDataSource, UIScrollViewDelegate < // all methods >
Объявление функций
Не растягивайте объявление функций более чем на одну строку, включая фигурную скобку:
Для функций с длинными названиями или списками аргументов, добавляйте переносы строк на необходимых местах и не забудьте добавить дополнительный отступ, на последующих строках объявления:
Замыкающие выражения
Используйте синтаксис последующих замыканий всегда, когда это возможно. Во всех случаях, давайте именам параметров описывающие их имена:
Предпочтительно
Не предпочтительно
Для однострочных замыканий, где контекст понятен, используйте неявный возврат значения:
По возможности используйте родные типы Swift. Swift предлагает мост в Objective-C, так что вы можете использовать все методы оттуда, если вам нужно.
Предпочитительно
Не предпочтительно
В коде Sprite Kit используйте CGFloat, если это сделает ваш код сжатым и позволит избежать большого количества конвертирования.
Константы
Совет: попробуйте все объявлять как константа, и менять на переменную, когда компилятор ругается!
Опционалы
При обращении к опциональному значению, используйте опциональную последовательность или цепочку, если вы обращаетесь к значению только один раз, или у вас несколько опционалов:
Используйте привязку опционала, когда более удобно извлечь значение и провести несколько операции сразу:
Когда вы даете имена опциональным переменным и свойствам, избегайте таких имен как optionalString или maybeView, так как их «опциональность» указана уже в типе.
Для связки опционала лучше следовать первоначальному имени, чем использовать такое как unrappedView или actualLabel
Предпочитительно
Не предпочтительно
Инициализаторы структуры
Лучше используйте родные инициализаторы Swift, а не наследие конструкторов CGGeometry:
Предпочитительно
Не предпочтительно
Вывод типа
Компилятор Swift может вывести тип переменной или константы. Вы можете явно указать тип через через алиас типа, но в большинстве случаев в этом нет необходимости.
Предпочтите в данном случае компактный вариант, пусть компилятор сам выведет тип для переменной или константы.
Предпочитительно
Не предпочтительно
Синтаксический сахар
Предпочитайте сокращенные версии объявления типов:
Предпочитительно
Не предпочтительно
Управление потоком
Лучше использовать цикл for-in, но не классический for:
Предпочитительно
Не предпочтительно
Точка с запятой
Точка с запятой после каждого выражения больше не обязательна. Они нужны только для тех случаев, когда вы хотите записать несколько выражений в одну строку.
Не пишите несколько выражений в одну строку, разделяя их точкой с запятой!
Предпочитительно
Не предпочтительно
Заметка: Swift совершенно другой язык, не похожий на JavaScript, где отсутствие запятых считается небезопасным.
Используйте правописание анлийского языка США, так как оно соответствует Apple’s API.
Предпочитительно
Не предпочтительно
Улыбающееся лицо
Улыбающиеся лица являются очень характерной чертой программирования на Swift! Это очень важно иметь правильную улыбку, означающую, огромное количество счастья и волнения в этой среде кодирования. Закрывающая квадратная скобка «]» используется потому, что она представляет собой большую улыбку и способна быть захваченной с помощью ASCII Art. В то время как закрывающая скобка «)» создает половинчатую улыбку, и, таким образом, не является предпочтительной.
Предпочитительно
Не предпочтительно
Что дальше?
Дальше, вы можете продолжить изучать наши туториалы по мере их появления, а также, параллельно читать перевод официальной книги по языку программирования Swift. И, для более подробного изучения языка, вы можете пройти наши курсы!
Немного практики функционального программирования в Swift для начинающих
Я хотела бы представить концепцию Функционального Программирования новичкам самым простейшим образом, выделив некоторые его преимущества из множества остальных, которые реально позволят сделать код более читаемым и выразительным. Я подобрала для вас интересные демонстрационные примеры, которые находятся на Playground в Github.
Функциональное Программирование: Определение
В Мире Swift для этого есть все условия, ибо функции здесь являются такими же полноправными участниками процесса программирования, как и объекты, а проблема изменяемости ( mutation ) решается на уровне концепции value ТИПОВ (структур struct и перечислений enum ), которые помогают управлять изменяемостью ( mutation ) и четко сообщают о том, как и когда это может произойти.
Однако Swift не является в полном смысле языком Функционального программирования, он не принуждает вас к Функциональному программированию, хотя и признает преимущества Функциональных подходов и находит способы встраивания их.
В этой статье мы сфокусируемся на использовании встроенных в Swift (то есть «из коробки») элементов Функционального программирования и понимании того, как можно их комфортно использовать в вашем приложении.
Императивный и Функциональный подходы: Сравнение
Чтобы оценить Функциональный подход, давайте сравним решения некоторой простой задачи двумя различными способами. Первый способ решения — «Императивный«, при котором код изменяет состояния внутри программы.
1. Чего вы пытаетесь достичь с помощью вашего кода?
2. Что произойдет, если другой поток ( thread ) попытается получить доступ к массиву numbers во время выполнения вашего кода?
Это продолжение нашего разговора о «побочных эффектах» ( side effects ). Очевидно, что изменения состояния не отслеживаются. Следовательно, при Императивном подходе мы теряем первоначальное состояние нашего массива numbers в процессе преобразования. Наше решение, основанное на Функциональном подходе, сохраняет первоначальный массив numbers и формирует на выходе новый массив result с желаемыми свойствами. Он оставляет первоначальный массив numbers нетронутым и пригодным для будущей обработки.
4. Насколько надежно можно протестировать этот код?
Так как Функциональный подход уничтожает все «побочные эффекты» ( side effects ), тестируемая функциональность полностью находится внутри метода. Вход этого метода НИКОГДА не будет испытывать изменений, так что вы можете проводить тестирование многократно с помощью цикла сколько угодно раз, и вы ВСЕГДА будете получать один и тот же результат. В этом случае тестирование проводить очень легко. В сравнении с этим, тестирование Императивного решения в цикле будет изменять начение входа и вы будете получать совершенно различные результаты после каждой итерации.
Краткое изложение преимуществ
Как мы видели из очень простого примера, Функциональный подход является классной вещью, если вы имеете дело с Моделью данных, потому что:
Функции первого класса и Функции высшего порядка
Для того, чтобы функция была первоклассной, у неё должна быть возможность быть объявленной в виде переменной. Это позволяет управлять функцией как обычным ТИПОМ данных и в то же время исполнять её. К счастью, в Swift функции являются объектами первого класса, то есть поддерживается их передача в качестве аргументов другим функциям, возврат их как результат других функций, присваивание их переменным или сохранение в структурах данных.
Возвращаемый функцией-параметром ТИП может не совпадать с ТИПОМ элементов исходной коллекции.
compactMap(_ 🙂
Нам необходимо построить другую ломанную линию, соединяющую середины отрезков первоначальной ломанной линии:
Имея такую последовательность, мы очень легко рассчитываем средние точки с помощью функции высшего порядка map(_:) и отображаем их на графике.
filter (_:)
Приведу еще пример использования функция высшего порядка filter (_:) для получения только четных первых 20 чисел Фибоначчи, у которых значения :
Мы получаем последовательность кортежей, состоящих из двух элементов последовательности Фибоначчи: n — го и (n+ 1) — го:
reduce (_:, _:)
С помощью функции reduce (_:, _:) мы можем очень просто посчитать сумму чисел Фибоначчи, удовлетворяющих определенному условию:
Несмотря на то, что функция высшего порядка reduce (_:, _:) предполагает аккумулирующий характер, она может использоваться совершенно в другом ракурсе. Например, для разделения кортежа на части в массиве кортежей:
Его можно эффективно использовать для удаления совпадающих значений в массиве целых чисел:
… или при подсчете числа разных элементов в массиве:
flatMap (_:)
Прежде чем переходить к этой функции высшего порядка, давайте рассмотрим очень простой демонстрационный пример.
Достать значение из двойного вложенного Optional реально обременительно.
В результате мы получаем вложенные массивы:
… и words имеет ТИП двойного Array :
Давайте попробуем применить flatMap к firstNumber :
… и получаем просто массив слов words без какой-либо «вложенности»:
Собираем все вместе: решение некоторых задач
ЗАДАЧА 1
Итак, мы получили все нужные нам буквы. Теперь давайте составим из них словарь, где ключом key является буква, а значением value — частота её появления в тексте.
2-ой способ связан с инициализацией словаря с помощью группировки, которая дает тот же самый результат:
Нам бы хотелось отсортировать словарь letterCount по алфавиту:
Мы видим, что на этот раз в качестве предиката в функцию sorted (by:) высшего порядка передается просто оператор » «. Функция sorted (by:) ожидает на входе «функцию сравнения» в качестве единственного аргумента. Она используется для сравнения двух смежных значений и принятия решения, являются ли они корректно упорядоченными (в этом случае возвращается true ) или нет (возвращается false ). Мы можем вручить эту «функцию сравнения» функции sorted (by:) в виде анонимного замыкания:
Если мы хотим выполнить сортировку словаря по значениям value и выяснить, какие буквы чаще всего встречаются в этой фразе, то нам придется использовать замыкание для функции sorted (by:) :
Если мы взглянем на решение задачи определения буквенного спектра какой-то многострочной фразы целиком…
Так как для некоторых коллекций доступ к свойству count выполняется путем итерации по всем элементам коллекции.
3. Проверяйте пустую строку String с помощью isEmpty
4. Получение первого элемента, который удовлетворяет определенным условиям
Иногда, когда коллекция Collection имеет очень большой размер и производительность для вас критична, то стоит вернуться к сравнению императивного и функционального подходов и выбрать приемлемый для вас.
ЗАДАЧА 2
Каждая карта имеет 4 признака, перечисленных ниже:
Количество: на каждой карте есть один, два или три символа.
Тип символов: овалы, ромбы или волны.
Цвет: символы могут быть красными, зелеными или фиолетовыми.
Заполнение: символы могут быть пустыми, зашрихованными или закрашенными.
Цель игры SET : Среди 12 карт, разложенных на столе, нужно найти SET (набор), состоящий из 3-х карт, у которых каждый из признаков либо полностью совпадает, либо полностью различается на всех 3-х картах. Все признаки должны полностью подчиняться этому правилу.
Например, количество символов на всех 3-х картах должно быть или одинаковым, или различным, цвет на всех 3-х картах должно быть или одинаковым, или различным, и так далее…
В этом примере нас будет интересовать только Модель карты SET struct SetCard и алгоритм определения SET по 3-м картам isSet( cards:[SetCard]) :
Как на этой Модели игры SET построить пользовательский интерфейс ( UI ) можно посмотреть здесь, здесь и здесь.
Чистые функции и побочные эффекты
Чистая функция выполняет два условия. Она всегда возвращает один и тот же результат при одних и тех же входных параметрах. И вычисление результата не вызывает побочных эффектов, связанных с выводом данных во вне (например, на диск) или с заимствованием исходных данных извне (например, времени). Это позволяет существенно оптимизировать код.
Эта тема для Swift прекрасно изложена на сайте point.free в самых первых эпизодах «Functions» и «Side Effects», которые переведены на русский язык и представлены как «Функции» и «Побочные эффекты».
Композиция функций
В математическом смысле это означает применение одной функции к результату другой функции. В Swift функции могут возвращать значение, которое вы можете использовать как вход для другой функции. Это общая практика программирования.
Представим, что у нас есть массив целых чисел и мы хотим на выходе получить массив квадратов уникальных четных чисел. Обычно мы реазизуем это следующем образом:
Несмотря на дополнительные затраты, это в некоторых случаях может существенно повысить производительность, читаемость и тестируемость вашего кода. Например, когда внутри map вы размещаете целую цепочку функций с помощью оператора «композиции» >>> вместо того, чтобы гонять массив через многочисленные map :
Но не всегда функциональный подход дает положительный эффект.
… в настоящий момент вам достаточно одной строки кода для получения массива блогов blogs :
Если все так легко, то мы можем «закачивать» JSON данные и в более сложные Модели. Допустим, что у нас есть файл c JSON данными, который имеет имя user.json и находится в нашей директории Resources. В нем находятся данные о некотором пользователе:
И у нас есть Codable Модель пользователя User с инициализатором из данных json :
Мы очень просто можем получить нового пользователя newUser с помощью еще более простого функционального кода:
Допустим, что у нас в директории Resources есть еще один файл с именем invoices.json и в нем находятся данные об инвойсах этого пользователя.
ТИП invoices будет [Invoice]? :
Вместо того, чтобы выполнять двукратно if let …
Мы можем и дальше развивать этот демонстрационный пример на предмет представления асинхронного считывания содержимого файла в виде специальной функции, которую вы можете посмотреть на сайте pointfree.co.
Я не являюсь фанатичной поклонницей Функционального Программирования везде и во всем, однако умеренное его использование мне представляется целесообразным.