Pull to refresh

Comments 103

> Если мы не знает тип объекта, в Objective-C можно просто указать тип объекта id, что значит — переменная может принимать значение любого типа. Ведь фактически, id — указатель на произвольный объект.

Верно, но все же лучше указывать, ибо тогда на этапе компиляции статический анализатор кода выдаст возможную ошибку.

> Небольшое отступление: поскольку Objective-C — надстройка над C, мы вынуждены заботится также и памяти. Компилятор LLVM поддерживает одну интересную фичу — Automatic Reference Counting, которая берет заботы об освобождении памяти на себя. Xcode версии 4.2 и выше использует компилятор от LLVM по-умолчанию, то есть о управлении памятью можно и не заботится, хотя, в принципе, для полного понимания языка было бы не плохо понять и такую, не совсем простую, тему как управление памятью.

В Obj-C 2.0 был (и есть) GC и он имел 3 режима: вкл, выкл, гибрид. А на iOS всегда надо было посылать retail/release для управления памятью.
> А на iOS всегда надо было посылать retail/release для управления памятью.
Зато теперь об этом заботиться не надо.
Ого! Не знал. Но мне кажется, я не скоро отучусь от автоматической привычки ставить [object release];
Ну обычные retain/release любой опытный objective-cишник ставит и так на полном автомате, а от retain cycles эта штука не избавляет. А их периодически как раз провтыкиваешь, но в принципе в 99% случаях за памятью действительно можно не следить.
Я имел ввиду, что это утверждение правда только для разработки под iOS. (у разработчиков под Mac уже давно есть GC)
Основная проблема разработки под мак и ios это как раз objective-c, не спорю, язык интересный, и сам на нем работаю, но он применяется в основном для продуктов яблочной фирмы.

Именно поэтому все время требуется поддерживать в актуальном состоянии и развивать знания о любом другом распространенным языке, что бы не «попасть в просак» при очередном изменении трендов.

Ведь получится довольно патовая ситуация, если (хоть и сомнительно в ближайшей перспективе) Apple потеряет лидирующие позиции на рынке, соответственно интерес к платформе пропадет, нет интереса — нет денег, а в копилке актуальных и практических знаний при этом — objective-c и только.
Ну что вы такое рассказываете, как будто Apple вчера появился. Я программировал на платформе до того как она стала популярна благодаря iOS и уверен что буду программировать и после, вся истерия вокруг iOS вообше проходит мимо, я не интересуюсь и не планирую интересоваться мобильной разработкой. Как зарабатывал прилично, так и продолжаю. Без сомнения Mac App Store сейчас существенно увеличил мои доходы, но это не критично.
UFO just landed and posted this here
Качество обеспечивается скорее высоким входным порогом (я имею в виду необходимость получения лицензии разработчика).
100$ высокий входной порог? Печаль.
С чем вы тут несогласны? Для того, кто от нечего делать написал hello, world и решил поделиться им с миром, конечно же это сильное препятствие. А человек потративший 100$ почти наверняка знает зачем он это сделал.
Пусть выкладывает сорцы на гитхаб если не собирается на этом зарабатывать. Для изучения эмулятора достаточно. А вслучаее с Mac'ом так вообще не надо ничего платить.
Я похож на того кому есть до этого дело? 100$ это настолько маленькие деньги, что порогом это назвать сложно.
честно говоря, похож.
Кстати, если есть идеи для будущих топиков — пишите.
Ruby vs Python, драма обеспечена :)
Можно добавить в статью сравнение реализаций замыканий и их особенностей в Ruby и Objective-C. Мне было бы интересно прочесть, так как не особо знаком с Ruby.
В принципе, объекты создаются достаточно легко в обоих языках. В Ruby можно просто послать классу сообщение new
myObject = myClass.new

в Objective-C же сначала необходимо выделить объекту память (alloc), а затем инициализировать его (init, initWith…)
MyClass * myObject = [[MyClass alloc] init];


Тут тоже есть new
Используются, так быстрее и короче писать. НО есть одна интересная вещь, ни как не могу словить закономерность: у UIViewController'a есть метод initWithNibName: bundle: так вот, если имя контроллера и имя его xib'a совпадает, то можно делать так [MyController new]. Создастся этот контроллер как будто мы сделали [[MyController alloc] initWithNibName:@"MyController" bundle:nil]
Но иногда оно не срабатывает и мы или упадем, потому что что-то не создалось из xib'a или не применяться стили (к примеру таблицы сделаеные в IB)
Может кто-то знает чего оно так?
UFO just landed and posted this here
Если создавать контроллер через new, то он пытается загрузить xib с тем же именем, но лучше явно указывать как имена контроллера, так и бандла, например [[MyController alloc] initWithNibName:NSStringFromClass([MyController class]) bundle:[NSBundle mainBundle]]; Это и читается лучше и избавляет от необходимости запоминать правила поиска xib файлов при переданых параметров, и убирает строковые константы из кода, тогда компилятор сможет подсказать если ошиблись в написании.
у меня абсолютно _всегда_ init работает, если xib назвать так же, как и класс. Подозреваю, что там прямо так, как у вас выше и написано, так что не вижу никакого смысла так, как выше и писать.
В некоторых случаях лучше указывать параметры явно, особенно когда xib'ы грузятся из разных бандлов/названы отлично от класса. А по умолчанию там действительно так как выше написано. Тут еще многое зависит от внутренних соглашений/codestyle команды разработчиков.
не сработает в случае с UITableViewController
я не обращаю внимание на гугл и использую их
И каким же образом objc динамичный?

Обьекту в рантайме нельзя добавить свойство, обьекту в рантайме нельзя добавить метод — где динамика?

>Это именно посылка сообщения, а не вызов метода, поскольку если вызвать
>несуществующий метод, мы не получим никаких ошибок на этапе компиляции, только во
>время выполнения (что доказывает динамичность языка)

это доказывает убогость и неудобство средств разработки и самого языка, а не динамичность.

а «посылка сообщения» vs «вызов метода» — это просто как называть.
В AS2/AS3 динамика присутствует, но там это называется вызов метода.
Ну, например, в отличии от C++ у него есть вот что:
> Язык Objective-C поддерживает нормальную работу с метаинформацией — так у объекта непосредственно на этапе выполнения можно спросить его класс, список методов (с типами передаваемых аргументов) и instance-переменных, проверить, является ли класс потомком заданного и поддерживает ли он заданный протокол и т. п.
(Wikipedia)
Это называется рефлексия — Reflections (или интроспекция).
К динамике отношения не имеет. В С++, если не ошибаюсь, рефлексия частично реализовывается через сторонние библиотеки — boost etc
>Обьекту в рантайме нельзя добавить свойство, обьекту в рантайме нельзя добавить метод — где динамика?

а это не то (Objective-C Runtime Reference)?
оно. признаю — был неправ. динамика есть.
а «посылка сообщения» vs «вызов метода» — это просто как называть.


Не-е-е-ет, разница существенная :). Это мало где написано, но по факту вызов метода — это действие времени компиляции. При попытке вызвать метод которого нет мы получим access violation. Посылка сообщения — это действие времени выполнения. Мы можем послать объекту сообщение, для котрого у него нет метода — и это не приведет к access violation. Мы можем послать сообщение по имени. А в руби вообще можно сделать так, чтобы объект принимал ЛЮБОЕ сообщение, а дальше на основании его имени и параметров что-нибудь делал.
Пример — AS2. Там можно вызывать любой метод в рантайме по имени и можно вызов метода перехватывать (ага, как в руби). Называется «вызов метода».
А вот в objc и перехватывать то нельзя — тогда почему там сообщения.

Вызов метода через рефлекшены в строго типипзированых языках — действие в рантайме. Не вермени компиляции. От этого их не начинают называть сообщениями.

И вызов метода и посылка сообщения — выполнение функции в контексте обьекта. Суть одно и тоже.
Уточню. В AS2 можно перехватывать вызов несуществующего метода тоже. Но это дальше вызов метода.
Увы, глубже мои знания не простираются, это уже к авторам языков. Чисто технически, и руби и objective c произошли от smalltalk — там ЭТО называлось message passing. Соответственно, если вдумчиво покопаться в википедии то можно найти еще критериев в чем разница message passing и method invocation. BTW, учитывая что ВСЕ конструкции языка в конечном итоге становятся очень небольшим количеством ассемблерных инструкций / байткодов — то речь может идти, ИМХО, только об условном логическом разделении — что «вот тут у нас имеет смысл назвать интерфейсом, а вот тут протоколом. Формальным.» :).
на самом деле всеравно как называть.
Я просто против того, чтоб говорить «Это именно посылка сообщения, а не вызов метода» и «Не-е-е-ет, разница существенная :)» так как разницы нет.
Это вводит в заблуждение людей пришедших с других платформ — начинают думать, что действительно есть разница.
Между вызовом метода в C++ и посылкой сообщения в Objective-C разница огромна, я ее описал выше. Чем больше в языке динамики — javascript, AS2, C# — тем более расплывается граница между этими двумя концепциями. ИМХО.
Между вызовом метода С++ и вызовом метода Action Script разница еще больше. Но это всеравно вызов метода.
Так в чем отличие, которое позволяет говорить, что в objc это именно сообщения и разница не только в названии?
Как я уже описал выше, по сравнению с C++ разница в том, что на этапе выполнения объект может как обработать сообщение, так и нет. Мы можем послать любое сбщение любому объекту не заботясь есть у него метод для его обработки или нет. В C++ это решается на этапе компиляции, на этапе выполнения — строго access violation.
мы разве говорим о разнице между objс и с++?
Мы говорили о разнице между методом и сообщением.

>на этапе выполнения объект может как обработать сообщение, так и нет
Если обьект не может обработать сообщение в objc програма завалится.

> Мы можем послать любое сбщение любому объекту не заботясь…
для метода тоже верно — в многих языках можно пробовать вызывать любые методы по имени

P.S. неужели так сложно признать «да, я ошибался»
неужели так сложно признать «да, я ошибался»


Увы, приведенные вами факты показывают что в динамических языках грань между методами и сообщеними стерта. Так же она стерта между полем класса и свойством, между примитивным типом и объектом и так далее, между много чем еще. На то они и динамические.

Разница между методом и сообщением есть применительно к ЯЗЫКАМ, реализующим эти концепции. Для каких-то языков такой разницы не будет, согласен. А для каких-то будет, и очень значительная.

Если обьект не может обработать сообщение в objc програма завалится.


Вы не правы, сморите стандарт. Сообщение будет проигнорировано, результатом отправки сообщения будет значение 0, приведенное к типу возврата, указанном в сигнатуре сообщения. Для структур — обнуление полей. Для не-POD типов поведение не определено.

P.S. неужели так сложно признать «да, я ошибался» :)
давайте по простому —
AS2
Можно в рантайме добавлять методы. Можно перехватывать вызов метода в том числе не существующего. Это сообщения?

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

насчет objc так я на нем пишу каждый день. и знаю что такое

unrecognized selector sent to instance

давайте по простому — AS2 Можно в рантайме добавлять методы. Можно перехватывать вызов метода в том числе не существующего. Это сообщения?


Термин не применим к данному языку? Он достаточно высокого уровня, чтобы для него не было разницы между процедурой, методом, сообщением?

насчет objc так я на нем пишу каждый день. и знаю что такое
unrecognized selector sent to instance


А, тут похоже я лажанулся. Я на нем меньше пишу, поэтому довольно вольно трактовал два поведения:
1. Можно отправить сообщение объекту, представленному нулевым указателем — это сообщение будет проигнорировано и вернет 0. Для C++ такое невозможно — будет access violation.
2. Можно в рантайме определить, может ли объект обработать сообщение — что-то вроде respondsToSelector. Для С++ то же самое — мы не можем в рантайме определить какие методы есть у объекта.

Достаточная разница между методом и сообщением? :).
было бы достаточное, но опятьже в AS2 методы удовлетворяют и 1 и 2. И их всеравно называют «методы».

и 1 за уши притянуто — это больше относится к обработке ошибок. Насколько язык к ошибкам строг.

1 и 2 удовлетворяют
AS2, JS, AS1…

2 удовлетворяют
C#, Java, да вообще все свежие языки

AS2, C#, Java — методы
JS, AS1 — если не ошибаюсь там называют просто «функции»
а в общем было приятно пообщатся. рад когда на хабре встречаются адекватные спорщики.
Взаимно. Там внизу ответ на «Это не разница между методом и сообщением. А разница между реализациями в разных языках». С, на мой взгляд, ультимативным аргументом про списки и ассоциативные массивы в Lua. Надеюсь. Давно на нем не писал :(.
какбы…
>Увы, приведенные вами факты показывают что в динамических
>языках грань между методами и сообщеними стерта.
Не понимаю почему «увы», но всетаки признаете, что метод и сообщение это одно и тоже?

>Разница между методом и сообщением есть применительно к
>ЯЗЫКАМ, реализующим эти концепции.
Это не разница между методом и сообщением. А разница между реализациями в разных языках.
Иначе прийдется говорить о разнице между методом и методом. А это уже нонсенс.

Это не разница между методом и сообщением. А разница между реализациями в разных языках.


Языки реализуют какой-то синтаксис и какое-то поведение. Их можно назвать как угодно. Для удобства классификации и обучения схожии концепции называют одинакого. Если в каком-то языке синтаксическая конструкция обладает признаками ОБОИХ концепций — какое право это дает говорить, что «эти концепции — одно и то же». Вы еще скажите, что списки и ассоциативные массивы это одно и то же, потому что они релизованы в Lua через одну и ту же концепцию ;-E~.
такая аргументация понятна.
Только терминология развивается. И если во времена C++ и objc так, возможно, подчеркивали разницу между поведением, то сейчас термин «метод» расширился включает в себя все свойста посылки сообщения. И термины фактически означают тоже самое.

Представте такой диалог — я перешел с АС2 и начинаю писать на objc.
я: так в objc нет методов?
вы: нет, там есть сообщения.
я: вау, а в чем разница
вы: их можна запускать по имени в рантайме
я: хм… и методы можно
вы: их можно динамически добавлять в обьект
я: так и методы можно, может это одно и тоже?
вы: нет! это сообщения!!! совсем другая вещь!!!
я:№;%:?*(???
Если я правильно понял, в Objective-C есть методы. Просто когда мы пишем [object method]; объекту посылается сообщение, и объект вызывает нужный метод, а не мы.
Хотя граница между вызовом метода и отправкой сообщения действительно размыта.
Это она сейчас размылась. А когда objective c от си отпочковывался — она была аки пропасть. Знание этого позволяет лучше понять дизайн языка и реализуемые на нем архитектурные решения :)
В целом так и есть. Но вспомните — objective-c постарше actionscript. Он отпочковался от си в одни годы с C++. И тогда концепция сообщений и концепция методов — это были два разных подхода. Ну и называли их по разному. Сейчас во многих молодых языках «функции-в-объектах» обладают как признаками методов, так и сообщений. Но не переделывать же из-за этого устоявшуюся терминологию? Может, через десяток лет и контейнеры унифицируются :)
Если мы не знает тип объекта, в Objective-C можно просто указать тип объекта id, что значит — переменная может принимать значение любого типа. Ведь фактически, id — указатель на произвольный объект.

А толку, все равно рано или поздно приводить к типу придется, это далеко не то что в руби. id — по сути, просто базовый класс обьекта, как и во всех ООП языках.

Зачем приводить? Объекту, с типом id можно послать любое сообщение. Не факт что обьект на который указывает этот указатель сможет обработать это сообщение, будет варнинг на этапе компиляции, что фактически означает ошибку, либо, чаще всего непродуманность архитектуры. Лучше использовать id.
«Лучше использовать id» имелось в виду Лучше использовать id, тогда то, что обьект сможет ответить на сообщение, описаное в протоколе будет проверятся на этапе компиляции
блин, вместо «Лучше использовать id» должно быть «Лучше использовать id < Protocol >»
в Objective-C мы должны заранее определить все используемые внутри класса переменные."
Для добавления переменных класов в рантайме используются категории и функции objc_getAssociatedObject/objc_setAssociatedObject.

«в Objective-C нам предстоит написать type * variable в разделе описания переменных класса, @property(retain) type * variable; после описания методов, и @synthesize variable; в реализации класса.»
В разделе описания можно не писать Type * ivar. Достаточно написать @property(retain) Type* myProperty, после чего в реализации @synthesize myProperty = _myIVar и компилятор сам создаст соответствующую переменную
Только в modern runtime.

Кстати, а знания про objc_getAssociatedObject/objc_setAssociatedObject чисто теоретические или применяли где на практике?
UFO just landed and posted this here
Практические, но с этим нужно осторожнее быть и с Полным пониманием того что и зачем делается. В большинстве случаев лучше обойтись наследованием.
http://habrahabr.ru/blogs/macosxdev/123187/ — о рантайме, и том, чего можно добиться с его использованием. Код там исключительно учебно-ознакомительный, так что не судите строго
>В принципе, объекты создаются достаточно легко в обоих языках.
Назовите язык, в котором обьекты тяжело создавать :)
Пункт 7.
Ахренеть вот значит как в ruby называется инкапсуляция :)
Вернее я хотел спросить, что за категории такие? Это же инкапсуляция, обычная.
Расширения не связаны с инкапсуляцией. Это именно добавление методов к существующему классу, даже к тому исходных кодов которого у вас нет, как например с библиотесными NSArray / NSSet
Дорогой друг, то что вы называете расширением, в терминах ООП является наследованием, а то что в примере статьи привел автор это инкапсуляция.
Посыл code_monkey, я понял. Просто для чистоты примера надо было просто наследоваться от какого-нибудь класса и добавить метод, иначе пример в пункте 7 неочевиден.
Нет. В Objective-C вы можете расширить любой Сушествующий класс добавив к нему какие-либо методы Без наследования. Например расширив клас NSObject и добавив к нему метод myDescription вы можете вызвать этот метод как у любого наслендика NSObject ( практически все классы ), так и у самого NSObject'а. Метод будет динамически добавлен в таблицу методов класса, расширение которого мы делаем.
Т.е. без наследования я могу сказать, что теперь у класса NSObject появится к примеру метод toJSON? Можно, пожалуйста, пример или ссылку, в целях просвещения.
Ну тык это special case наследования.
Нет. Наследование — отношение между двумя классами (один наследует другой).
Тут же можно существующий класс, скажем NSObject, расширить (например добавить метод toJSON) не создавая нового.

Более того, все классы наследованные от NSObject тоже получат этот метод.
Если же вы создадите новый класс, скажем NSJsonObject, унаследуете его от NSObject и добавите новый метод toJSON, то ни NSObject, ни уже существующие наследники NSObject новый метод toJSON не получат.

Как видите, это абсолютно разные вещи.
Ибанько, который, минусует, ты либо комментируй, либо сиди тихо, если сказать нечего.
извиняюсь, что своими минусами так задел ваши нежные чувства. надеюсь минус в карму загладит мою вину.

а по сути:
1.выучи вначале что такое инкапсуляция.
2.разберись что такое наследование
3.после этого можеш попробовать освоить расширения (в C# — extension methods, в objc — Categories etc, есть еще в Ruby, JS...)
4.научись вести себя и общатся культурно
О, Ибанько, живое и говорящее.
1. Видать у тебя инкапсуляция что то другое. меня учили что это сокрытие реализации от интерфейса. Ты поясни мне, как 7-й пункт статьи в эту категорию не попадает.
2. Как бэ в курсе.
3. Куда уж мне.
4. Вроде я не хамил. Хотя ты же ибанько, у тебя инкапсуляция не инкапсуция, наследование не наследование.
несмотря ни на что обьясню.

В п. 7 добавляються новые методы в класс String (Ruby) и NSString (objc).
Оба являются классами из базовой библиотеки. Никто их не наследует.
Тоесть после этого в objc можна будет написать
[@«This is a string» helloWorld];

в C#
«another string».helloWorld();

И просто дружеский совет

Ну вот на х… очевидные вещи повторять, которые в статье и так описаны?
Я спросил конкретный вопрос чем это отличается от наследования, кроме sugar синтаксиса?
К.О. Подсказывает, что тем, что обьект дальше имеет тип String или NSString.
Также К.О. удивленно замечает, что наследованием там и не пахнет. Без синтаксического сахара это бы выглядело так (в c#)
//обьявление
string helloWorld(string thisObject)
{
return «helloWorld»;
}

//использование
helloWorld(aString);

с сахарком

//обьявление
string helloWorld(this string thisObject)
{
return «helloWorld»;
}

//использование
aString.helloWorld();

А нужно это чтоб писать более компактный и понятный код. Как и все другие инструменты и ООП в том числе.

Ну и для закрепления пройденого
Ты, как бы сам вообще понимаешь, что такое ООП?
Ну как бы на вопрос ответь где тебя найти.
При встрече и закрепишь мне.
да, я понимаю что такое ООП.
Украина, Львов, Максим Грынив — этого впринципе достаточно чтоб меня найти. Я человек публичный. Но при желании пиши в личку и можно будет встретится.
Спокойной ночи и всего наилучшего. Я б еще какуюто ссылку вставил, но ссылки закончились :)
Ну и ты какбы уже знаеш, куда идти :)
Бывал? Советуешь?
UFO just landed and posted this here
Сынок, ты как бы расскажи, где тебя в Украине, найти. Чтобы ты м не недалекому по поводу наследования и инкапсуляци просветил. А я тебя по поводу «дружеских советов».
пишите в личку батенька. всегда готов просветить.

ну и советую не так явно показывать кто вы
Слушай, я про ООП нихера не понимаю, а ты про личку.
Вопрос на засыпку. Ты доказать, что хочешь, ссылками в свой профайл? Что в 28-29, ты до сих пор еблан?
Все что я хочу доказать этим, что там есть такая кнопочка — «написать письмо».
Я на Obj-C когда начинал писать (собственно, пару недель назад), многое казалось странным. Потом понял, что вот это похоже на си, вот это — на паскаль, вон то — еще на что-то, и втянулся :-) Только одно дело — поверхностно знать язык, и другое — глубоко, впечатление может пменяться.
> Это именно посылка сообщения, а не вызов метода, поскольку если вызвать несуществующий метод, мы не получим никаких ошибок на этапе компиляции, только во время выполнения

Ну раз уж упомянули clang3 и arc, почему не упомянули, что clang3 на несуществующие методы умеет давать ошибки компиляции?
Категория — не совсем расширение класса, только функциональности, потому что через категорию нельзя добавить новую переменную в класс.
Можно. Для этого есть ассоциированные объекты. В интерфейсе категории нужно указать новое свойство, а в реализации — геттеры и сеттеры, использующие рантайм. Подробнее
с runtime можно и напрямую добавить ivar в класс без ассоциаций (пруф). А я имел ввиду именно категорию как таковую.
UFO just landed and posted this here
Да, я в курсе. В первых версиях черновика про это было. Исправил.
>>Все мы знаем что Ruby — динамичный язык программирования.

Может динамический всё-же?
Подскажите, есть ли в Москве активные iOS/Mac сообщества? Активные, это те, кто хотя бы раз в месяц-два пытаются собраться.
сообщение – это всего лишь строка с информацией о том что и кому отправить, и её можно переслать по сети.
Если вы пишете:

id i = [obj do: something];

1) шлётся сообщение (вызов функции obj_msgSend с получателем, селектором – строкой с именем сообщения, – и остальными аргументами);
2) в dispatch table иерархии классов ищется функция, соответствующая этому селектору, i. e. «method», если её нет, вызывается — forwardingTargetForSelector: или — forwardInvocation:, чтобы переслать сообщение, или если их не реализовали — doesNotRecognizeSelector: с исключением.
3) вызывается функция, с реализацией (у этого или, в случае пересылки, иного класса)
4) obj_msgSend возвращает значение

Именно этим способом работают прокси – они отвечают на сообщения, но не реализуют своих методов.
неужели никто не смотрел?

When it encounters a method invocation, the compiler might generate a call to any of several functions to perform the actual message dispatch, depending on the receiver, the return value, and the arguments. You can use these functions to dynamically invoke methods from your own plain C code, or to use argument forms not permitted by NSObject’s perform… methods. These functions are declared in /usr/include/objc/objc-runtime.h.

objc_msgSend sends a message with a simple return value to an instance of a class.
objc_msgSend_stret sends a message with a data-structure return value to an instance of a class.
objc_msgSendSuper sends a message with a simple return value to the superclass of an instance of a class.
objc_msgSendSuper_stret sends a message with a data-structure return value to the superclass of an instance of a class.
Sign up to leave a comment.

Articles

Change theme settings