All posts by Admin

Tips & Tricks загрузки приложения в iTunes Store

После разработки приложения для iPhone возникла необходимость публикации его в iTunes Store. Основные вещи, которые нужно знать, чтобы загрузить его без проблем:

1. Желательно скачать и обязательно нужно прочитать все доступные руководства самого Apple. Если вы пользуетесь XCode 4, то скачайте XCode 4 User Guide. Не пожалеете.  А лучше и вовсе используйте XCode 3 пока, потому что лично у меня и у других XCode 4 падал при Submit приложения. Он еще очень сырой. Лучше всю документацию читать с первых рук, из первоисточников и самые свежие версии, скачав их самостоятельно с сайта Apple. Нужно прочитать iOS Development Guide. Инструменты разработки и публикации все время меняются и нужно всегда быть в курсе, читать все только самое свежее и не читать устаревшие руководства, в том числе и устаревшие YouTube видеоролики. Они вам слабо помогут и даже принесут вред и дезинформацию. Если нет ничего свежего, то лучше читать в первоисточниках, то есть руководствах самого Apple, так как все постоянно у них меняется. Читать устаревшию информацию и смотреть старые видеоролики – это все равно, что пить прокисшее молоко. Польза есть, но может быть и вред, причем это довольно невкусно.

2. Нужно учитывать и знать, что есть 2 типа Provisioning Profiles(Профайлы подготовки приложений) – Distribution и Development. В Distribution профайле недоступна привязка девайса(Device). Не нужно ломать голову на счет этого. У вас не получится сделать Distribution Build с привязкой к девайсу. На девайс можно поставить приложение только в Development Build. Я на этот пункт потратил очень много времени, пытаясь понять, почему я не могу привязать Device к Distribution Provisioning Profile.

3. На сайте Apple все написано, но и там есть устаревшая информация и неработающие руководства. Например, я потратил кучу времени на то, чтобы загрузить приложение с помощью приложения Application Loader. На самом же деле, после того, как я спросил на нескольких форумах, почему я не могу загрузить, я понял две вещи. Первая – это то, что Apple под Application Bundle понимает файл *.app, который лежит в Products и который заархивирован в формат *.zip. При этом оказалось, что и вовсе Application Loader’ом не надо пользоваться пока, а надо загружать в XCode. Нажимаем меню Products->Archive. Далее заходим в Organiser->Archives и нажимаем Submit. При этом учитывайте, что и то, что я написал здесь, может устареть через неделю. Поэтому если что-то не получается, сразу задавайте вопросы на форумах. Мне помогли.

4. Не следует думать, что рисунки 100х100 сами конвертируются в нужный вид, например 57×57. При тестировании у вас все будет работать, но загрузить такое приложение не получится или будут проблемы. Лучше все рисунки делать в нужных вам размерах и причем так, чтобы они затем не растягивались и не сжимались на экране iPhone. От этого только хуже. Делайте четко. 40×40 у вас иконка – так 40х40, не надо делать 100х100 в надежде, что она хорошо сконвертируется на девайсе.

5. Ярлык приложения лучше назвать icon.png, положить его в корень и прописать в info Plist. Заставку не надо нигде прописывать, нужно просто создать рисунок размерами 320х480, назвать его Default.png и положить в корень. Кроме этого, рекоммендую вам сразу нарисовать иконку приложения в более крупном варианте 512х512. Это пригодится, когда вы будете создавать страницу приложения в iTunes Store. При этом png должен быть настоящим, а не полученным искусственно из jpg. Такой вариант будет работать только на симуляторе.

6. Перед разработкой установите последнюю версию SDK, иначе придется исправлять потом ошибки, переназначать библиотеки. При этом напоминаю, что лучше продолжать пользоваться XCode 3, а не XCode 4. Когда будете компилировать приложение, в настройках укажите минимальную версию iOS, на которой ваше приложение будет работать. Лучше поставить самую маленькую версию, которая только возможна для вашего приложения, так как приложения написанные для поздних версий, могут быть недоступны в Verizon.

7. Зарегиструйтесь и задавайте вопросы на всех форумах и читайте разные блоги и сайты, посвященные разработке под iOS.

8. Когда будете загружать через кнопку Submit или через Application Loader не удивляйтесь тому, что у вас 0%. Не выключая загрузку, посмотрите в iTunes Connect состояние вашего приложения. Если оно стало Waiting for Review, значит, вам удалось загрузить приложение. У меня так было.

Итак, если что-то не знаете, спросите у знающих.

 

Все это желательно знать, чтобы сэкономить время.

Загрузка данных с сайта в собственную базу

Допустим, вам надо перенести определенные данные с какого-то сайта в свою базу данных в красивом, структурированном виде. Но вы не хотите сидеть и копи-пастить в Excel эти данные. Тогда может помочь следующий метод. Он основан на использовании C# приложения для загрузки, очистки и парсинга HTML и дальнейшей загрузке данных в Excel программно.

Для пользования данным методом нужно владеть языком C#, так как мой код надо всегда затачивать под каждый сайт.

1. Открываем среду разработки на C#(Я пользуюсь MS Visual Studio 2010 Ultimate). Создаем новый проект с простой формой:

В адресе URL мы введем страницу, из которой нужно получить контент при нажатии на кнопку. При этом автоматически откроется Excel 2007 и в него занесутся данные – этот контент.

2. Нажимаем правой кнопкой по References под названием проекта в Solution Explorer. Выбираем Add Reference. Далее во вкладке COM находим и выбираем компоненту Microsoft Excel 12.0 Object Library. Ссылки на эту компоненту понадобятся для автоматической загрузки данных в Excel.

3. Редактируем список пространств имен:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Linq;
using System.Web;
using System.IO;
using System.Net;
using System.Collections;
using System.Collections.Specialized;
using System.Configuration;
using Excel = Microsoft.Office.Interop.Excel;
using System.Reflection;

4. Пишем код для кнопки.

private void button1_Click(object sender, EventArgs e)
{
string OldText, NewText, PossibleRefText, RefText, textOfCitation, authorOfCitation;
strURL = textBox1.Text;
OldText = GetHtmlFromUrl(strURL);
int begin, begin0, i;
int end;
int length;
int lastindex;
int newindex;
int indexOfClosingTag, difference, indexOfHref;
int indexofrefbegin, indexofspanbegin, indexOfAuthorEnd, indexOfAuthorBegin, indexOfAuthorBegin0;
RefText = "<a href";
newindex = OldText.IndexOf("<p class=\"data\">");
begin = OldText.IndexOf("<p class=\"data\">");
lastindex = OldText.LastIndexOf("<p class=\"data\">");
OldText = OldText.Remove(0, newindex);
i = 0;
while (!(newindex == (-1)))
{
i = i + 1;
begin0 = OldText.IndexOf("<p class=\"data\">");
begin = OldText.IndexOf("<p class=\"data\">") + 16;
indexofrefbegin = begin;
end = OldText.IndexOf("</p>");
length = end - begin;
if (length < 0)
{
break;
}
textOfCitation = OldText.Substring(begin, length);
OldText = OldText.Remove(0, end + 4);

indexOfAuthorBegin0 = OldText.IndexOf("class=\"author\"");
OldText = OldText.Remove(0, indexOfAuthorBegin0);
indexOfAuthorBegin0 = OldText.IndexOf("class=\"author\"");
indexOfHref = OldText.IndexOf("href=");
difference = indexOfHref - (indexOfAuthorBegin0 + 15);
if (difference < 5 && difference >= 0)
{
indexOfClosingTag = OldText.IndexOf(">");
length = indexOfClosingTag - indexOfAuthorBegin0 - 14;
OldText = OldText.Remove(indexOfAuthorBegin0 + 15, length);
}
indexOfAuthorBegin = OldText.IndexOf("class=\"author\"") + 15;

indexOfAuthorEnd = OldText.IndexOf("<");
length = indexOfAuthorEnd - indexOfAuthorBegin;
if (length < 0)
{
break;
}

authorOfCitation = OldText.Substring(indexOfAuthorBegin, length);
OldText = OldText.Remove(0, indexOfAuthorEnd + 1);

//Literal1.Text = Literal1.Text + " " + i.ToString() + ". " + textOfCitation + " " + "(" + authorOfCitation + ")" + "</br>";
textOfCitation = cleanFromBr(textOfCitation);
textOfCitation = cleanFromQuot(textOfCitation);
citations[i - 1, 0] = textOfCitation;
citations[i - 1, 1] = authorOfCitation;

}

//Добавляем массив цитат в Excel
InsertToExcel();

//  движок для википедии
//{
//    string OldText, NewText, PossibleRefText, RefText;
//    strURL = TextBox1.Text;
//    OldText = GetHtmlFromUrl(strURL);
//    int begin;
//    int end;
//    int length;
//    int lastindex;
//    int newindex;
//    int indexofrefbegin, indexofspanbegin;
//    RefText = "<p class=\"data\">";
//    newindex = OldText.IndexOf(RefText);
//    begin = OldText.IndexOf(RefText);
//    lastindex = OldText.LastIndexOf("</p>");
//    while (!(newindex == (-1)))
//    {
//        begin = OldText.IndexOf(RefText) + 16;
//        end = OldText.IndexOf("</p>");
//        length = end - begin;
//        NewText = OldText.Substring(begin, length);
//        newindex = OldText.IndexOf(RefText);
//        Literal1.Text = Literal1.Text + NewText;
//    }
//}

}

Здесь мы сначала запрашиваем HTML в текстовую строку с помощью функции GetHtmlFromUrl. Затем мы эту текстовую строку обрабатываем, удаляя все ненужное, а нужное занося в массив. Затем добавляем получившийся массив в Excel с помощью функции InsertToExcel().

5. Пишем дополнительный вспомогательный код с функциями, которые использовались в коде для кнопки:


private string cleanFromBr(string text)
{
int indexOfStart, indexOfEnd;
indexOfStart = text.IndexOf("<br/>") - 1;
while (indexOfStart != -2)
{
indexOfEnd = indexOfStart + 6;
text = text.Remove(indexOfStart, 6);
text = text.Insert(indexOfStart, " ");
indexOfStart = text.IndexOf("<br/>") - 1;
}
return text;
}

private string cleanFromQuot(string text)
{
int indexOfStart, indexOfEnd;
indexOfStart = text.IndexOf("&quot;");
while (indexOfStart != -1)
{
indexOfEnd = indexOfStart + 6;
text = text.Remove(indexOfStart, 6);
text = text.Insert(indexOfStart, "\"");
indexOfStart = text.IndexOf("&quot;");
}
return text;
}

private void InsertToExcel()
{
Excel.Application oXL;
Excel._Workbook oWB;
Excel._Worksheet oSheet;
Excel.Range oRng;

try
{
//Start Excel and get Application object.
oXL = new Excel.Application();
oXL.Visible = true;

//Get a new workbook.
oWB = (Excel._Workbook)(oXL.Workbooks.Add(Missing.Value));
oSheet = (Excel._Worksheet)oWB.ActiveSheet;

//Add table headers going cell by cell.
//oSheet.Cells[1, 1] = "First Name";
//oSheet.Cells[1, 2] = "Last Name";
//oSheet.Cells[1, 3] = "Full Name";
//oSheet.Cells[1, 4] = "Salary";

//Format A1:D1 as bold, vertical alignment = center.
//oSheet.get_Range("A1", "D1").Font.Bold = true;
//oSheet.get_Range("A1", "D1").VerticalAlignment =
//    Excel.XlVAlign.xlVAlignCenter;

//Fill A1:B20 with an array of values (First and Last Names).
oSheet.get_Range("B1", "C20").Value2 = citations;

////Fill C2:C6 with a relative formula (=A2 & " " & B2).
//oRng = oSheet.get_Range("C2", "C6");
//oRng.Formula = "=A2 & \" \" & B2";

////Fill D2:D6 with a formula(=RAND()*100000) and apply format.
//oRng = oSheet.get_Range("D2", "D6");
//oRng.Formula = "=RAND()*100000";
//oRng.NumberFormat = "$0.00";

////AutoFit columns A:D.
//oRng = oSheet.get_Range("A1", "D1");
//oRng.EntireColumn.AutoFit();

//Manipulate a variable number of columns for Quarterly Sales Data.
//DisplayQuarterlySales(oSheet);

//Make sure Excel is visible and give the user control
//of Microsoft Excel's lifetime.
oXL.Visible = true;
oXL.UserControl = true;
}
catch (Exception theException)
{
String errorMessage;
errorMessage = "Error: ";
errorMessage = String.Concat(errorMessage, theException.Message);
errorMessage = String.Concat(errorMessage, " Line: ");
errorMessage = String.Concat(errorMessage, theException.Source);

//MessageBox.Show(errorMessage, "Error");
}
}

public enum ResponseCategories
{
Unknown = 0,       // Unknown code ( < 100 or > 599)
Informational = 1, // Informational codes (100 >= 199)
Success = 2,       // Success codes (200 >= 299)
Redirected = 3,    // Redirection code (300 >= 399)
ClientError = 4,   // Client error code (400 >= 499)
ServerError = 5    // Server error code (500 >= 599)
}

public static string GetHtmlFromUrl(string url)
{
if (string.IsNullOrEmpty(url))
throw new ArgumentNullException("url", "Parameter is null or empty");

string html = "";
HttpWebRequest request = GenerateHttpWebRequest(url);
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
if (VerifyResponse(response) == ResponseCategories.Success)
{
// Get the response stream.
Stream responseStream = response.GetResponseStream();
// Use a stream reader that understands UTF8.
using (StreamReader reader =
new StreamReader(responseStream, Encoding.UTF8))
{
html = reader.ReadToEnd();
}
}
}
return html;
}

public static HttpWebRequest GenerateHttpWebRequest(string UriString)
{
// Get a Uri object.
Uri Uri = new Uri(UriString);
// Create the initial request.
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(Uri);
// Return the request.
return httpRequest;
}

// POST overload
public static HttpWebRequest GenerateHttpWebRequest(string UriString,
string postData,
string contentType)
{
// Get a Uri object.
Uri Uri = new Uri(UriString);
// Create the initial request.
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(Uri);

// Get the bytes for the request; should be pre-escaped.
byte[] bytes = Encoding.UTF8.GetBytes(postData);

// Set the content type of the data being posted.
httpRequest.ContentType = contentType;
//"application/x-www-form-urlencoded"; for forms

// Set the content length of the string being posted.
httpRequest.ContentLength = postData.Length;

// Get the request stream and write the post data in.
using (Stream requestStream = httpRequest.GetRequestStream())
{
requestStream.Write(bytes, 0, bytes.Length);
}
// Return the request.
return httpRequest;
}

public static ResponseCategories VerifyResponse(HttpWebResponse httpResponse)
{
// Just in case there are more success codes defined in the future
// by HttpStatusCode, we will check here for the "success" ranges
// instead of using the HttpStatusCode enum as it overloads some
// values.
int statusCode = (int)httpResponse.StatusCode;
if ((statusCode >= 100) && (statusCode <= 199))
{
return ResponseCategories.Informational;
}
else if ((statusCode >= 200) && (statusCode <= 299))
{
return ResponseCategories.Success;
}
else if ((statusCode >= 300) && (statusCode <= 399))
{
return ResponseCategories.Redirected;
}
else if ((statusCode >= 400) && (statusCode <= 499))
{
return ResponseCategories.ClientError;
}
else if ((statusCode >= 500) && (statusCode <= 599))
{
return ResponseCategories.ServerError;
}
return ResponseCategories.Unknown;
}

Часть этих функций нужна, чтобы запросить HTML, часть чтобы очистить его от тэгов. Набор этих функций, как и код кнопки будут меняться в зависимости от того, с какого именно сайта вы хотите получить контент. То есть данный метод не универсален, его надо затачивать под каждый сайт. Я не буду подробно разъяснять этот код, так как все равно нужно обладать хорошими знаниями в C#, чтобы применять данный метод. Кроме этого, тут есть неплохие комментарии.

4. Здесь http://support.microsoft.com/kb/302084 описано, как писать код для загрузки данных в Excel.

5. Далее, как я описал ранее, можно выгрузить данные из Excel в XML, а XML уже загрузить туда, куда вам надо. Смотрите предыдущий пост в этом блоге.

Метод наполнения базы SQLite через выгрузку Excel данных в XML

Здесь будет описан метод, который позволяет наполнять базу данных SQLite из Excel посредством выгрузки данных в XML.

SQLite — легковесная встраиваемая реляционная база данных. Исходный код библиотеки передан в общественное достояние. В 2005 году проект получил награду Google-O’Reilly Open Source Awards. Простота и удобство встраивания SQLite привели к тому, что библиотека используется в браузерах, музыкальных плеерах и многих других программах. Многие программы поддерживают SQLite в качестве формата хранения данных (особенно в Mac OS и iPhone OS, Android).

Можно использовать Microsoft Excel 2007, на других версиях метод не тестировался. Предположим, есть заполненная данными таблица Excel 2007 с четырьмя столбцами: ID, Text, Author, Favorite.

1. Создаем XML файл в Windows – образец будущего большого XML файла. Он будет играть роль схемы в Excel. Например,

<?xml version=”1.0″ encoding=”UTF-8″ standalone=”yes”?>
<BusCits xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>
<BusCit>
<ID>1</ID>
<Text>Т1</Text>
<Author>А1</Author>
<Favorite>N</Favorite>
</BusCit>
<BusCit>
<ID>2</ID>
<Text>Т2</Text>
<Author>А2</Author>
<Favorite>N</Favorite>
</BusCit>
</BusCits>

Здесь представлены два элемента BusCit, в каждом из которых есть параметры ID, Text, Author, Favorite. Элементы являются дочерними по отношению к главному элементу BusCits. Сохраняем этот образцовый XML. Назовем его XMLSchema.xml.

2. В Excel 2007 в Ribbon’е есть вкладка Разработчик. Открываем ее. На этой вкладке есть раздел XML. Нажимаем там на кнопку “Источик”, а затем в появившейся справа панели на кнопку “Карты XML…”. Нажимаем Добавить и добавляем ранее сохраненный XMLSchema.xml. Нажимаем Ок. Соглашаемся использовать маленький XML в качестве схемы. Дальше в той же правой панели Источник XML должна появиться ваша схема. Нажимаем правой кнопкой на ID и выбираем Сопоставить элемент. Далее выбираем первый столбец в таблице с ID, нажав на букву, которая его идентифицирует, при этом заголовки тоже выделяются(A, B, C и т.д). Аналогично поступаем с каждым другим параметром: Text, Author, Favorite.  Мы привязали XML схему к таблице, теперь во вкладке Разработчик/XML в Ribbon нажимаем Export и экспортируем XML с нужным нам названием, например BusCits.xml. Готово, получившийся XML можно удобно посмотреть в программе Notepad++ и проверить. Должно получиться что-то вроде этого:

3. Запускаем Mac Os X. Заходим в XCode и, используя сайт http://www.tbxml.co.uk и  библиотеку, описанную в нем, пишем код для парсинга XML файла. Можно использовать любую другую облегченную библиотеку XML.
Пример работающего кода:


-(void) insertBusCitsToDatabase {
// Setup the database object
sqlite3 *database;
char *sqlStatement;
NSString *insert;
//Подготовка к парсингу XML
TBXML * tbxml = [[TBXML tbxmlWithXMLFile:@"BusCits.xml"] retain];
//Получение корневого элемента
TBXMLElement * rootXMLElement = tbxml.rootXMLElement;
TBXMLElement * XMLBusCit;
TBXMLElement * XMLID;
TBXMLElement * XMLText;
TBXMLElement * XMLAuthor;
TBXMLElement * XMLFavorite;
NSString *BusCitText;
NSString *BusCitId;
NSString *BusCitAuthor;
NSString *BusCitFavorite;
char *errMsg;
int returnValue;

// Init the busCits Array
busCits = [[NSMutableArray alloc] init];

//Cycle until XML ended
//1. Read XML to busCit object
//2. Insert busCit object to DB
//End Cycle

// Open the database from the users filessytem
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {

XMLBusCit = [TBXML childElementNamed:@"BusCit" parentElement:rootXMLElement];
if (XMLBusCit==nil) {
return;
}

while (XMLBusCit) {

if (XMLBusCit==nil) {
break;
}
XMLID = [TBXML childElementNamed:@"ID" parentElement:XMLBusCit];
XMLText = [TBXML childElementNamed:@"Text" parentElement:XMLBusCit];
XMLAuthor = [TBXML childElementNamed:@"Author" parentElement:XMLBusCit];
XMLFavorite = [TBXML childElementNamed:@"Favorite" parentElement:XMLBusCit];
BusCitText = [TBXML textForElement:XMLText];
BusCitId = [TBXML textForElement:XMLID];
BusCitAuthor = [TBXML textForElement:XMLAuthor];
BusCitFavorite = [TBXML textForElement:XMLFavorite];

NSLog(BusCitId);
NSLog(BusCitText);
NSLog(BusCitAuthor);
NSLog(BusCitFavorite);
sqlite3_stmt *insertStatement;
char *st;

//Генерация и подготовка SQL выражения для вставки записи

insert = [[NSString alloc] initWithFormat:@"INSERT OR REPLACE INTO BusCits (ID, Text, Author, Favorite) VALUES ('%@', '%@', '%@', '%@');", BusCitId, BusCitText, BusCitAuthor, BusCitFavorite];
st = [insert UTF8String];
//NSLog(st);
returnValue = sqlite3_exec (database, st, NULL, NULL, &errMsg);
if (returnValue != SQLITE_OK)
{
NSLog(@"Addition failed");
//NSLog(errMsg);
}
else
{
NSLog(@"Addition Ok!");

}
XMLBusCit = XMLBusCit->nextSibling;
}

// Setup the SQL Statement and compile it for faster access
const char *sqlStatement = "SELECT * FROM BusCits";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK)
{
// Loop through the results and add them to the feeds array
while(sqlite3_step(compiledStatement) == SQLITE_ROW)
{
// Read the data from the result row
NSString *aId = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
NSString *aText = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
NSString *aAuthor = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 3)];
NSString *aFavorite = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 4)];

// Create a new animal object with the data from the database
BusCit *busCit = [[BusCit alloc] initWithID:aId Text:aText Author:aAuthor Favorite:aFavorite];
// Add the animal object to the animals Array
[busCits addObject:busCit];

[busCit release];
}
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);

}
sqlite3_close(database);

}

Для того, чтобы посмотреть и проверить работу используется NSLog. После отработки функции можно нажать Shift+Command+R и вызвать консоль, в которой пишется то, что в NSLog.

О runtime ошибке SIGABRT

Баг с текстом SIGABRT в NSLog может появляться при тестировании программы на iPhone Simulator. Например, при открытии нового View. То есть он возникает во время работы программы, а компилятор XCode не находит эту ошибку. На понимание причины бага или сигнала SIGABRT было потрачено 3-4 часа. Поэтому было решено написать эту статью. Посмотрим сначала, что нам пишет википедия об этой ошибке.

POSIX® (англ. Portable Operating System Interface for Unix — Переносимый интерфейс операционных систем Unix) — набор стандартов, описывающих интерфейсы между операционной системой и прикладной программой. Стандарт создан для обеспечения совместимости различных UNIX-подобных операционных систем и переносимости прикладных программ на уровне исходного кода, но может быть использован и для не-Unix систем.
В POSIX-системах, SIGABRT — сигнал, посылаемый процессом самому себе при выполнении функции abort(), для аварийного останова, в случае невозможности дальнейшего продолжения программы. Сигнал SIGABRT процесс посылает сам себе, когда вызывает функцию abort() (функция libc, с прототипом в stdlib.h). Сигнал SIGABRT может быть перехвачен или проигнорирован, но abort() принудительно завершит программу (предварительно сбросив и закрыв стандартные потоки и сделав дамп памяти программы) даже если этого не сделает обработчик сигнала. Таким образом, функция abort() гарантирует завершение программы, почему она часто используется библиотеками в аварийных ситуациях — когда выполнение не должно быть продолжено, но основная программа должна иметь возможность выполнить действия, необходимые перед аварийным завершением. Также SIGABRT вызвается утверждениями (англ. assertions; средство отладки Си — макроопределение assert() вызывает abort() если утверждение переданное в качестве аргумента ложно).

Из этого текста можно понять, что ошибка или сигнал SIGABRT посылается просто из-за вызова функции abort() при падении программы. В свою очередь эта функция может вызываться утверждением assert(), но мы не можем посмотреть и выявить точную причину бага. Поэтому SIGABRT – один из самых вредных и труднопреодолимых багов при разработке для iPhone: отладка(debugging) не помогает, так как ошибка возникает где-то в коде, который не доступен разработчику. В интернете можно прочитать много всего про этот баг приложений для iPhone. Кому-то помогла перезагрузка XCode каким-то магическим образом или “Clean all Targets”. Пишут также, что это ошибка XCode или Симулятора, а не ошибка разработчика. Я думаю, что проблема в другом.

Наверное, главная и самая распространенная причина этой ошибки(касательно iPhone, iPhone Simulator) в том, что XIB не соответствует вашим аутлетам(Outlets) или классам. Например, если написать:
@interface FavoritesTableView : UITableViewController,

когда у вас нет контроллера TableViewController, а вместо него обычный View с контролом TableView, то выскочит эта ошибка. Видимо, программа пытается обратиться к сущностям, которых нет, при загрузке View. Они либо были освобождены из памяти(deallocated) раньше времени, либо их просто нет (например, в XIB). Далее вызывается abort(), который посылает сигнал SIGABRT.

Итак, в данном случае надо было написать:
@interface FavoritesTableView : UIViewController

Также SIGABRT может быть вызван обращением к любой несуществующей сущности – к элементу за пределами массива, к переменной, объекту, XIB файлу и т.д.