Статьи

Ява не цивилизованный язык?

Несколько недель назад мне была предоставлена ​​возможность научиться программировать на iOS. Мой начальник решил, что я скорее «ученый-компьютерщик», а не разработчик, и это означало, что я мог применить свои знания для разработки приложения для iPad или двух — все, что мне нужно было сделать, это изучить Objective-C и iOS SDK: в конце концов, насколько это может быть сложно?

Хотя в прошлом я много занимался C / C ++, я занимался Java с 2001 года, поэтому я практически забыл многое из того, что знал, и, кроме того, Objective-C во многом не похож на C ++. В результате вы чувствуете, что умылись на чужом берегу, не в состоянии говорить на этом языке, и вы вооружены не более чем загаром и словарем.

Изучая все эти новые вещи, я понял, что Java — ОЧЕНЬ хороший язык, и причина, в первую очередь, в том, что вам не нужно думать о распределении и освобождении памяти, вы можете просто приступить к написанию своего приложения. , При написании приложений для iOS в Objective-C вы должны как выделить память для ваших объектов, так и затем очистить себя, возвращая память вашего объекта обратно в свободный пул. Это кажется очень старой школой для второго десятилетия 21-го века. Кроме того, выделив память для объекта, вы должны отслеживать количество ссылок на него — практика, известная как подсчет ссылок , с чем я впервые столкнулся в своей предыдущей жизни как программист C ++. Основная идея здесь заключается в том, что каждый раз, когда вы создаете новую ссылку на объект, вы увеличиваете счетчик ссылок, а когда вы заканчиваете со ссылкой на объект, вы уменьшаете его счетчик ссылок.

Когда счетчик достигает нуля, система освобождает память обратно в свободный пул. В Objective-C функция уменьшения счетчика ссылок называется release ; следовательно, если бы в Java был подсчет ссылок, и если бы я хотел, например, попросить AddressService найти мне адрес, мне нужно было бы сделать что-то вроде этого:

1
2
3
4
5
6
7
8
// create an object and set the reference count to 1
    AddressService addressService = new AddressService(); 
    // Use the object
    Address address = addressService.findAddress(id);
    // pass it to a method
    model.addAttribute("address", address);
    // free the memory
    addressService.release();

Это простой сценарий, но что произойдет, если тот или иной метод передаст вам ссылку на объект в качестве аргумента метода? В этом случае вам нужно решить, как вы собираетесь его удерживать, и, кажется, есть два способа сделать это. Первый — сделать копию объекта, а второй — увеличить счетчик ссылок. Создание копии, вероятно, является самой безопасной идеей, но она потребляет больше памяти и будет медленнее, в то время как увеличение счетчика ссылок происходит быстро, но не так безопасно, так как какая-то другая часть программы может ошибиться в подсчете ссылок и уменьшить счетчик слишком много раз. , это означает, что у вас есть ссылка на некоторую память, которая могла быть освобождена, и когда вы пытаетесь получить доступ к вашему освобожденному объекту, ваша программа падает … Опять же, если бы в Java был подсчет ссылок, тогда метод обработчика запросов Spring Controller мог бы выглядеть примерно так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
@RequestMapping(value = "/find", method = RequestMethod.GET)
  public String findAddress(@RequestParam("id") int id, Model model) {
     
    // increment the reference count - 'retain' is the Objective-C method for doing this.
    model.retain();   
 
    // create a new string object - with reference count of one
    String msg = new String().withFormat("Processing an address page request for address with id: " + id);
    // pass the string to the logger
    logger.info(msg);
    // release the string's memory
    msg.release();
 
    AddressService addressService = new AddressService();
    Address address = addressService.findAddress(id);
    model.addAttribute("address", address);
    addressService.release();
 
    // finished with the model
    model.release();
    return "address-display";
  }

Здесь следует отметить пару моментов: во-первых, метод-обработчик передается объекту модели, поэтому я увеличиваю счетчик ссылок, вызывая retain, а затем вызываю release для модели, когда заканчиваю с ним в конце метода. , Во-вторых, даже при создании тривиальных объектов, таких как строка сообщения, которая передается в регистратор, вы должны применять правила подсчета ссылок и освободить память, как только закончите с ней.

В приведенном ниже примере демонстрируется альтернатива увеличению счетчика ссылок: создание собственной копии объекта…

01
02
03
04
05
06
07
08
09
10
11
12
@RequestMapping(value = "/find", method = RequestMethod.GET)
  public String findAddress(@RequestParam("id") int id, Model model) {
     
    // increment the reference count - 'retain' is the Objective-C method for doing this.
    Model myModel = model.copy();   
 
    // As previous example
     
    // finished with the model
    myModel.release();
    return "address-display";
  }

Эти примеры являются лишь тривиальными, есть целый ряд правил подсчета ссылок, которые вам нужно применить, и если вы ошиблись, то Ka-Bam вылетит и произойдет ошибка, если вы попытаетесь получить доступ к уже освобожденной памяти, или медленно умереть из-за утечки памяти, потому что вы забыли освободить память. Хотя я предполагаю, что ключевым моментом здесь является владение : если у вас есть объект, увеличьте его счетчик ссылок, когда вы закончите с объектом, уменьшите его счетчик ссылок.

Приведенный выше код является всего лишь наброском, написанным для иллюстрации сути — он не скомпилируется. Код был взят из моего примера Address на GitHub и в реальной жизни выглядит так:

01
02
03
04
05
06
07
08
09
10
@RequestMapping(value = "/find", method = RequestMethod.GET)
  public String findAddress(@RequestParam("id") int id, Model model) {
 
    logger.info("Processing an address page request for address with id: " + id);
 
    Address address = addressService.findAddress(id);
    model.addAttribute("address", address);
 
    return "address-display";
  }

… Намного меньше аккуратнее и понятнее. И последнее: некоторые из вас заметят, что в примере с подсчетом ссылок я выделяю (слово Objective-C) новый AddressService — это потому, что в программировании на iOS нет ничего похожего на внедрение зависимостей или среду Spring, поэтому вы вернулись к создание объектов для себя. (Примечание для парней в Spring: «Spring iOS» — звучит как идея для меня…)

Те из вас, кто в курсе, подчеркнут тот факт, что Apple недавно представила так называемый «Автоматический подсчет ссылок». Хотя это не сборка мусора, это упрощает процесс, поскольку iOS теперь автоматически отслеживает ваши ссылки на указатели и освобождает память для вас, когда счетчик достигает нуля, что означает, что вам не нужно беспокоиться о вызове методов сохранения и освобождения ,

Кроме того, этот блог не пытается очернить Objective-C — мне очень нравится Objective-C. Его синтаксис кажется довольно загадочным и кажется многословным по сравнению с Java, но он заставляет вас быть более дисциплинированным в вашей технике программирования, поэтому если вы, как и я, считаете, что хорошее программирование сводится к «ясности мышления», то при написании Objective- С программой нужно думать чуть яснее, и это мне очень нравится.

Я также предполагаю, что многие читатели могут придумать множество причин, почему они считают Java ужасным языком и почему их предпочтительный язык «делает это лучше», каким бы он ни был, поэтому я с нетерпением жду к вашим комментариям …

Наконец, я просто новичок, когда дело доходит до программирования на iOS, поэтому, если кто-нибудь из мастеров iOS / Objective-C встретит этот блог — пожалуйста, дайте мне знать, где я ошибаюсь.

Справка: разве Java не цивилизованный язык? от нашего партнера JCG