Страницы

Поиск по вопросам

Показаны сообщения с ярлыком objective-c. Показать все сообщения
Показаны сообщения с ярлыком objective-c. Показать все сообщения

понедельник, 13 апреля 2020 г.

Копирование NSManagedObject-подкласса

#objective_c #coredata

                    
Существует некий NSManagedObject-подкласс Visit. Появилась необходимость получить
почти точную копию обьекта - из двадцати полей нужно изменить значение у трех. Можно
ли сделать копию не таким трудоемким процессом как 
....
for(Visit *copiedVisit in arrayOfVisits) // массив обьектов с которых делаются копии
{
    Visit *newVisit = (Visit *)[NSEntityDescription insertNewObjectForEntityForName:@"Visit"
inManagedObjectContext:[self managedObjectContext]];
newVisit.date = [NSDate someNewDate];  // поле которое нужно изменить
newVisit.name = copiedVisit.name;         // далее переприсвоение значений полей
одного объекта = полям     другого
newVisit.attribute = copiedVisit.attribute;
newVisit.time = copiedVisit.time;
...

NSError *err = nil;
if (![self managedObjectContext] save:&err])
 {
    ...
 };
}

а потом переприсвоением значений полей одного объекта полям другого? Некий аналог
copy для NSManagedObject-подкласса?    


Ответы

Ответ 1



Насколько мне известно, у Core Data нет такой возможности из коробки. Мне кажется, вполне уместно определить для вашего класса Visit соответствующий метод -copyWithZone: в котором можно описать всю процедуру порождения копии, и затем пользоваться просто обычным copy, как вы и предполагаете в своем вопросе - только не "аналогом copy", а самым настоящим copy, потому что именно так он и работает - через определение copyWithZone. Смотри мой ответ про клонирование UIView: Objective C: как клонировать UIView? .

суббота, 11 апреля 2020 г.

Core Data не сохраняется число

#macos #xcode #binding #coredata #objective_c

                    
Здравствуйте! Создал простенькую программку с поддержкой Core Data, типа Document–Based
app. Имеется текстовое поле, соединённое с arrayController'ом, который в свою очередь
соединён с Entity, у которой есть атрибут "name" типа "string" и атрибут "score" типа
"decimal". Введённая в текстовое поле строка сохраняется без проблем.
Также имеется другое текстовое поле: в него вводится число и после нажатия кнопки
"Go" значение из поля передаётся в метку. Метка соединена абсолютно точно так же как
и первое текстовое поле, но почему-то значение метки не сохраняется.
С чем это связано и как это исправить?
Для наглядности, проект можно скачать отсюда: https://www.dropbox.com/sh/kfp61xu3i4zj3kz/QCnPtlVqtE    


Ответы

Ответ 1



У вас проблема в том, что "запись" в базу не происходит. Изыскания показали, что данные из TextField записываются в базу только после переключения "фокуса" из этой TextField в другое место. А у вас получается, что фокусировки нет совсем. Попробуйте дополнить код "принудительно" записю данных в Базу. Например: - (IBAction)changeScore:(id)sender { [_scoreLabel setDoubleValue:[_scoreField doubleValue]]; id saveObj = [_arrayController selectedObjects][0]; double newDob = [_scoreField doubleValue]; NSNumber * decim = [NSNumber numberWithDouble:newDob]; [saveObj setValue:decim forKey:@"score"]; }

Как генерировать объекты за экраном с заданным промежутком

#spritekit #xcode #разработка_игр #objective_c #ios7

                    
Приветствую всех! Делаю игру на spritekit с бесконечным уровнем (like Doodle jump)и
возникла проблема:
Не могу понять как генерировать платформы за экраном так, чтобы новые генерировались
только после того, как предыдущая платформа уехала на определенное расстояние?
Вот пример кода для генирации платформ
- (void)addPlatforms
{
    int random = arc4random() % (int)(self.frame.size.width-80)+100;

    // right end platform
    SKSpriteNode *rightEndPlatform = [SKSpriteNode spriteNodeWithImageNamed:@"leftPlatform"];
    rightEndPlatform.size = CGSizeMake(16, 16);
    rightEndPlatform.physicsBody =
    [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(rightEndPlatform.size.width,
rightEndPlatform.size.height - 5)];
    rightEndPlatform.position = CGPointMake(random, 0);

    // left end platform
    SKSpriteNode *leftEndPlatform = [SKSpriteNode spriteNodeWithImageNamed:@"rightPlatform"];
    leftEndPlatform.size = CGSizeMake(16, 16);
    leftEndPlatform.physicsBody =
    [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(leftEndPlatform.size.width,
leftEndPlatform.size.height - 5)];
    leftEndPlatform.position = CGPointMake(rightEndPlatform.position.x - PLATFORM_RANGE,
rightEndPlatform.position.y);

    // left platform
    SKSpriteNode *leftPlatform = [SKSpriteNode spriteNodeWithImageNamed:@"centerPlatform"];
    leftPlatform.size = CGSizeMake(leftEndPlatform.position.x, 16);
    leftPlatform.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:leftPlatform.frame.size];
    leftPlatform.position =
    CGPointMake(leftEndPlatform.position.x - leftPlatform.size.width/2,
                leftEndPlatform.position.y);

    // right platform
    SKSpriteNode *rightPlatform = [SKSpriteNode spriteNodeWithImageNamed:@"centerPlatform"];
    rightPlatform.size = CGSizeMake(self.frame.size.width+rightEndPlatform.position.x, 16);
    rightPlatform.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:rightPlatform.frame.size];
    rightPlatform.position =
    CGPointMake(rightEndPlatform.position.x + rightPlatform.size.width/2,
                rightEndPlatform.position.y);

    // add to the scene
    [self addChild:rightEndPlatform];
    [self addChild:leftEndPlatform];
    [self addChild:leftPlatform];
    [self addChild:rightPlatform];

    // add platforms to array
    [platformArray addObject:rightEndPlatform];
    [platformArray addObject:leftEndPlatform];
    [platformArray addObject:leftPlatform];
    [platformArray addObject:rightPlatform];

    for (int i = 0; i < [platformArray count]; i++)
    {
        SKSpriteNode *sprite = [platformArray objectAtIndex:i];
        sprite.physicsBody.usesPreciseCollisionDetection = YES;
        sprite.physicsBody.dynamic = NO;
        sprite.name = [NSString stringWithFormat:@"beforePlayer"];
    }
}

Генерирую платформу, потом напротив через промежуток другую платформу и достраиваю
от краев экрана до этих платформ линии, получая стенку с проходом.
Далее двигаю созданную конструкцию
-(void)update:(CFTimeInterval)currentTime
{
    for (int i = 0; i < [platformArray count]; i++)
    {
        SKSpriteNode *platform = [platformArray objectAtIndex:i];
        platform.position = CGPointMake(platform.position.x, platform.position.y
+ PLATFORM_SPEED);
        if (platform.position.y > self.frame.size.height+100)
        {
            [platform removeFromParent];
        }
    }
}

а генерация платформ происходит по времени
timer = [NSTimer scheduledTimerWithTimeInterval:TIME_INTERVAL target:self selector:@selector(addPlatforms)
userInfo:nil repeats:YES];

Вот и вопрос, вообще правильно ли я делаю или есть лучше вариант, как генерировать
платформы не по времени а по расстоянию (первая сгенерированная платформа уехала на
100 единиц , тогда генерируем вторую, вторая уехала на 100 единиц- генерируем третью и т.д)
Спасибо за внимание!    


Ответы

Ответ 1



Сразу прошу прощения, не стал вчитываться в код, (как известно, разбирать чужой код это, как лезть кому-то в душу) ). Наиболее изящный, по моему скромному мнению, выход из этой ситуации таков: 1) Остановите движение платформ, временно закомментировав соответствующую часть кода в update 2) На неподвижном экране создайте максимально возможное число платформ (на нужном Вам расстоянии друг от друга). Это легко сделать, с помощью цикла for. 3) Сдвиньте точку генерации первой из платформ на нужное расстояние за экраном. 4) Далее, в методе update начинайте двигать платформы (кстати, доступ к платформе можно получить, присвоив ей имя (если не знаете как, я напишу)) и, при этом, как только платформа пройдет нужное расстояние (то, что между каждой из платформ) за экран, Вам необходимо переместить ее в начальную точку (в ту, в которой происходила генерация первой платформы). При выполнении данного алгоритма у Вас получится непрерывный "поток" платформ, причем без наложений и дополнительной генирации (то макимальное число платформ вы просто перемещаете "по кругу") Надеюсь, у меня получилось донести до Вас мысль об общем построении таких конструкций. Если нужно что-то описать подробней, пишите, не стесняйтесь.

UML диаграммы в Xcode 6.3.2

#objective_c #xcode #uml

                    
Всем привет!
Возникла необходимость в создании UML диаграммы классов в среде разработки Xcode 6.3.2.  

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

http://www.developers-life.com/tag/uml


Подскажите пожалуйста, существует ли способ создания UML диаграммы классов  в последних
версиях Xcode ?
    


Ответы

Ответ 1



Я не совсем знаком с UML, но если Вам необходимо показать ориентированный граф зависимостей между классами на Objective-C, то можно использовать вот этот плагин KSHObjcUML для Xcode 6.3.2 Так же можно посмотреть и этот плагин ObjectGraph-Xcode

Apple сделала reject приложению

#ios #objective_c #apple

                    
Ребята, у меня в принципе простое приложение. Которое должно проигрывать музыку посредством
AVPlayer'a. 
Вроде все хорошо, сделал чтобы она играла и тогда когда приложение идет в background.

Но я все сделал так как Apple говорит Здесь

И так: 


  First, declare your application provides specific background services
  and must be allowed to continue running while in the background. To do
  this, add the UIBackgroundModes key in your app's Info.plist file. Its
  value is an array that contains one or more strings that identify
  which background tasks your application supports. Specify the string
  value audio to indicate the application plays audible content to the
  user while in the background:


Плюс так:


  Listing 1  Setting the audio category to allow playback when the
  screen locks or when the Ring/Silent switch is set to silent.


#import 
#import 

AVAudioSession *audioSession = [AVAudioSession sharedInstance];

NSError *setCategoryError = nil;
BOOL success = [audioSession setCategory:AVAudioSessionCategoryPlayback error:&setCategoryError];
if (!success) { /* handle the error condition */ }

NSError *activationError = nil;
success = [audioSession setActive:YES error:&activationError];
if (!success) { /* handle the error condition */ }


Но сегодня пришел реджект со словами:


  
    June 17, 2015 at 6:12 AM От: Apple
    2.16 - Multitasking Apps may only use background services for their intended
purposes: VoIP, audio playback, location, task completion,
    local notifications, etc.
    2.16 Details
  
  
  Your app declares support for audio in the UIBackgroundModes key in
  your Info.plist, but we were unable to play any audible content when
  the application was running in the background.
  
  Next Steps
  
  The audio key is intended for use by applications that provide audible
  content to the user while in the background, such as music player or
  streaming audio applications. Please revise your app to provide
  audible content to the user while the app is in the background or
  remove the "audio" setting from the UIBackgroundModes key.
  
  Resources
  
  If you have difficulty reproducing a reported issue, please try
  testing the workflow described in Technical Q&A QA1764: How to
  reproduce bugs reported against App Store submissions.
  
  If you have code-level questions after utilizing the above resources,
  you may wish to consult with Apple Developer Technical Support. When
  the DTS engineer follows up with you, please be ready to provide:
  - complete details of your rejection issue(s)
  - screenshots
  - steps to reproduce the issue(s)
  - symbolicated crash logs - if your issue results in a crash log


Подскажите что не так делаю, запутался если честно((

Заранее спасибо!
    


Ответы

Ответ 1



В принципе все так как советовал товарищ Sega-Zero. в коде исправил мелкие недочеты написал развернутое сообщение интервьюеру, от том как правильно запустить и зачем, а главное когда нужно воспроизведения музыки в фоне После чего получил одобрение в apple store.

четверг, 9 апреля 2020 г.

Как нарисовать рваную линию?

#ios #objective_c #swift

                    
Есть ли возможность, стандартная, а если и нет, то скажите, как можно нарисовать
рваную линию, похожу на баллончик, или рваную кисть, которая не полностью зарисовывает
область, а как бы оставляет след. Я реализовываю такую вот штуку. Заранее, спасибо
за помощь.

[Обновление] Задача упростилась, теперь просто нужно узнать как рисовать линию изображением.
    


Ответы

Ответ 1



Я так понимаю, единственный вариант это накладывать одно и то же изображение снова и снова, каждый раз, когда курсор смещается. В том примере, который у вас просто рисуется одно и то же изображение, именно так, как я описал в комментарии выше. просто изображение необычной формы и по краям, судя по всему есть полупрозрачные пиксели. если предположить, что у вас есть заднее изображение и переднее. то вам надо по клику в переднем изображении создавать прозрачный кусок установленной формы. вот пример с SO как это сделать // get access to the image bytes CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage)); // create a buffer to hold the mask values size_t width = CGImageGetWidth(image.CGImage); size_t height = CGImageGetHeight(image.CGImage); uint8_t *maskData = malloc(width * height); // iterate over the pixel data, reading the alpha value uint8_t *alpha = (uint8_t *)CFDataGetBytePtr(pixelData) + 3; uint8_t *mask = maskData; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { *mask = *alpha; mask++; alpha += 4; // skip to the next pixel } } // create the mask image from the buffer CGDataProviderRef maskProvider = CGDataProviderCreateWithData(NULL, maskData, width * height, NULL); CGImageRef maskImage = CGImageMaskCreate(width, height, 8, 8, width, maskProvider, NULL, false); // cleanup CFRelease(pixelData); CFRelease(maskProvider); free(maskData); Потом, чтобы все это запустить сделать: CGImageRef subtractedImage = CGImageCreateWithMask(b.CGImage, maskImage); Еще добавлю, что этот фокус скорее всего будет есть очень много ресурсов для большой картинки. может есть смысл поделить на несколько маленьких.

Ответ 2



Менее ресурсоемким решением было бы использование GLKit, работало бы быстро и на всех девайсах, но не на всех iOS, кажется начиная с iOS 7. С другой стороны, можно поиграться с CGPath, UIBezierPath, маской картинкой и получить "почти" тот же результат, ключевое слово почти :) UPD: Приведу пару ссылок Линк 1 Линк 2 Линк 3

вторник, 17 марта 2020 г.

Получение идентификатора в iOS 7 (UDID, OpenUDID, UUID, и т.п)

#xcode #ios #objective_c


В приложении требуется получение идентификатора, но так как UDID запретили использовать
еще в iOS 6, я вынужден спрашивать вас :C. Что может заменить UDID? 
Пробовал NSUUID
NSString *uuid = [[NSUUID UUID]
UUIDString];

Меняется после переустановки приложения.
Пробовал "IDFV" Identifier for Vendor:
NSString *idfv = [[[UIDevice
currentDevice] identifierForVendor]
UUIDString];

Но он тоже меняется (и не понятно почему, он бывает снова возвращает старый идентификатор).
Так же хотел попробовать Advertiser Identifier, но ASIdentifierManager и advertisingIdentifier
не распознается xCode. Программа уже готова для обновления в xCode и в iTunesConnect,
уже перед заливкой в iTunes заметил что идентификатор менялся. Пожалуйста подскажите
уже готовым решением, до 18:00 планирую залить в iTunes. Заранее большое спасибо).    


Ответы

Ответ 1



Дак это UIID на то и UIID - он должен быть разным каждую долю сикунды во всем мире один такой. Если вы хотите не изменяемый UIID, то раньше, да использовали идентификатор устройства. В связи с чем рекламщики злоупотребляли сбором данной информации. И теперь эта функция контралируется пользователем. На сегодняший день мы вышли из данной ситуации зпросом MAC адреса GSM/Wi-Fi подулей, после хеша md5-подобной функции мы получили UID. Вот пример реализации: @implementation TCMacAddress + (NSString *)getMacAddress { int mgmtInfoBase[6]; char *msgBuffer = NULL; size_t length; unsigned char macAddress[6]; struct if_msghdr *interfaceMsgStruct; struct sockaddr_dl *socketStruct; NSString *errorFlag = NULL; // Setup the management Information Base (mib) mgmtInfoBase[0] = CTL_NET; // Request network subsystem mgmtInfoBase[1] = AF_ROUTE; // Routing table info mgmtInfoBase[2] = 0; mgmtInfoBase[3] = AF_LINK; // Request link layer information mgmtInfoBase[4] = NET_RT_IFLIST; // Request all configured interfaces // With all configured interfaces requested, get handle index if ((mgmtInfoBase[5] = if_nametoindex("en0")) == 0) errorFlag = @"if_nametoindex failure"; else { // Get the size of the data available (store in len) if (sysctl(mgmtInfoBase, 6, NULL, &length, NULL, 0) < 0) errorFlag = @"sysctl mgmtInfoBase failure"; else { // Alloc memory based on above call if ((msgBuffer = malloc(length)) == NULL) errorFlag = @"buffer allocation failure"; else { // Get system information, store in buffer if (sysctl(mgmtInfoBase, 6, msgBuffer, &length, NULL, 0) < 0) errorFlag = @"sysctl msgBuffer failure"; } } } // Befor going any further... if (errorFlag != NULL) { NSLog(@"Error: %@", errorFlag); return errorFlag; } // Map msgbuffer to interface message structure interfaceMsgStruct = (struct if_msghdr *) msgBuffer; // Map to link-level socket structure socketStruct = (struct sockaddr_dl *) (interfaceMsgStruct + 1); // Copy link layer address data in socket structure to an array memcpy(&macAddress, socketStruct->sdl_data + socketStruct->sdl_nlen, 6); // Read from char array into a string object, into traditional Mac address format NSString *macAddressString = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", macAddress[0], macAddress[1], macAddress[2], macAddress[3], macAddress[4], macAddress[5]]; //NSLog(@"Mac Address: %@", macAddressString); // Release the buffer memory free(msgBuffer); return macAddressString; } @end

Ответ 2



Отслеживать устройства запрещено apple. Можете отслеживать пользователей например по их логину но для этого в вашем приложении это должно как-то быть реализовано. Отлеживать сами устройства у вас не получится.

Apple push notification - как правильно отобразить нужный контроллер?

#objective_c #ios #apple #ios7


Доброе время суток! В общем столкнулся с проблемой, приходит уведомление, скажем
"Вам пришло новое сообщение", мне необходимо открыть чат с этим пользователем, но что
бы попасть в чат, нужно прочти 3 экрана от стартового, либо же пользователь не выходит
с приложения, а заблокировал телефон на контроллере чата, подскажите пожалуйста, каким
образом нужно/можно/будет правильно открывать нужный контроллер? Если к нему нужно
добиратся через 3-9 земель? или не наоборот?
Заранее спасибо за помощь!     


Ответы

Ответ 1



Думаю здесь больше зависит от архитектуры приложения. Вот у меня, например, несколько NavigationControllers и у каждого есть переход в чат. Дак контрол чата принимает на вход модель собеседников и таким образом я могу его вызвать в любом месте через пуш, сформулировав перед этим все модели данных для чат контрола. - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { UINavigationController *navController = (UINavigationController *)self.window.rootViewController; NotificationViewController *notificationViewController = [[NotificationViewController alloc] init]; [navController.visibleViewController.navigationController pushViewController:notificationViewController]; } Но в этом примере я пушаюсь сразу же в чат без промежуточных экранов. Если же задача стоит именно пропушиться туда где чат пройдя по промежуточным экраном, то тут нужно придумать какой-нибудь алгоритм переходов с неким path пушей экранов с анимацией, с блоком завершения анимации и пушингом следующего контрола в path . В общем много вариантов, на самом деле, все зависит от ТЗ.

воскресенье, 15 марта 2020 г.

Рассчитать размер прямоугольника с текстом

#ios #objective_c #swift


В делегате func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath:
NSIndexPath) -> CGFloat я должен высчитать высоту моего текста в UILabel. Какими путями
мне это сделать, скажите, пожалуйста?

upd1(к первому комментарию) :

    let text = self.posts[indexPath.row]["story"]! as NSString
    let sizeOfLabel = text.boundingRectWithSize(
        CGSize(width: <>, height: Int.min),
        options: NSStringDrawingOptions.UsesLineFragmentOrigin,
        attributes: ["NSFontAttributeName":UIFont.systemFontOfSize(17)],
        context: nil)

    


Ответы

Ответ 1



Если я правильно понял, то у Вас проблема с размером UILabel в UITableView. При создании вашей UILabel в методе UITableViewDataSource нужно указать yourLabel.layoutIfNeeded(). Если это не то, опишите проблему точнее

Ответ 2



extension UILabel { func calculateHeight() -> Float { let text = self.text as NSString let size = text.sizeWithAttributes([NSFontAttributeName: self.font]) return size.height } }

Ответ 3



То, что у вас в апдейте должно работать, единственноheight не минимальный а максимальный let sizeOfLabel = text.boundingRectWithSize( CGSize(width: <>, height: DBL_MAX), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: ["NSFontAttributeName":UIFont.systemFontOfSize(17)], context: nil)

воскресенье, 8 марта 2020 г.

Как получать html документы из другого приложения?

#objective_c #xcode #swift


Во многих программах есть кнопка "Share", которая открывает список приложений, умеющих
обрабатывать этот тип файлов, например:



Я хочу, чтобы мое приложение могло обрабатывать html файлы.
Например пользователь нажимает кнопку "Share" в Google Chrome или в DropBox, а ссылка
передается моему приложению.
Где искать информацию?
    


Ответы

Ответ 1



Сначала в Info.plist прописываете: CFBundleDocumentTypes CFBundleTypeName HTML LSHandlerRank Alternate LSItemContentTypes public.html public.xhtml В AppDelegate: //Swift func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool { //do something with html file here return true } //Objective-C - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options { //do something with html file here return YES; } И передавайте: Чтобы получить url из Safari создайте App Extension: File -> New -> Target -> Share Extension Соглашаетесь создать схему, запускаете и видите: Схема как это работает: Подробнее в Документации Далее необходимо настроить. Для начала в - (BOOL)isContentValid { // Do validation of contentText and/or NSExtensionContext attachments here return YES; } Проверяете что Вам необходимо и если подходит, return YES; если что-то не то return NO;. Включить и настроить App Groups: И сохранять данные можно через NSUserDefaults: NSUserDefaults *shared = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.test.one"]; [shared setObject:object forKey:@"yourkey"]; [shared synchronize]; Получить: NSUserDefaults *shared = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.test.one"]; id value = [shared valueForKey:@"yourkey"]; NSLog(@"%@",value);

вторник, 25 февраля 2020 г.

Библиотека для работы с JSON для iOS

#xcode #objective_c #ios #json #библиотеки


Нашел следующие библиотеки:

SBJSON
JSON kit
Touch JSON (как я понял устарел и не поддерживается)

хочется поинтересоваться что пользуется бОльшим успехом и какие особенности этих
библиотек. И возможно какая лучше.     


Ответы

Ответ 1



Советую выбирать Вам между NSJSONSerialization и JSONKit. Про разницу между ними ничего особенного не скажу, обе библиотеки делают свое дело. Что касается их производительности, то разница у них незначительная (JSONKit быстрее, но не намного) и к тому же редко когда вы столкнетесь с тем, что именно производительность разбора JSON будет для вас bottleneck. Смотрите на эту тему очень поучительный комментарий автора библиотеки RestKit. Единственный довод за NSJSONSerialization - это отсутствие лишней зависимости от сторонней библиотеки (я имею в виду зависимость от JSONKit в случае, если вы выберете её), хотя, если вы пользуетесь Cocoa pods, этот довод становится совсем еле заметным. Довод против NSJSONSerialization и в пользу JSONKit - это что JSONKit удобнее в использовании - я пользуюсь JSONKit главным образом из-за того, что она добавляет удобные категории к классам NSArray, NSDictionary, NSString. И вместо того, чтобы писать каждый раз заново строки NSJSONSerialization типа NSJSONSerialization *yourResponse = [NSJSONSerialization JSONObjectWithData:yourData options:0 error:&jsonError]; NSArray *yourObjects = (NSArray *)yourResponse; При использовании JSONKit Вам достаточно будет написать NSArray *yourObjects = yourData.objectFromJSONData; На мой взгляд это удобно и незаметно. Настолько незаметно, что я даже не сразу вспомнил какой JSON-библиотекой я пользуюсь, когда прочитал Ваш вопрос. ОБНОВЛЕНО ПОЗЖЕ Мой взгляд на этот вопрос изменился с тех пор, как я отвечал на него полтора месяца назад. Сейчас я бы советовал использовать исключительно родной NSJSONSerialization. Вот несколько причин: JSONKit, похоже, накрепко заброшен автором. Xcode 5 выдаёт очень много Warning'ов по поводу JSONKit, как он есть, и автор никак не реагирует на соответствующие репорты (если интересно, см. многочисленные issues вроде #121 в его репозитории на Github). Вот эти Тесты производительности на SO показывают, что NSJSONSerialization работает быстрее или как минимум наравне с JSONKit (начиная с iOS 6). Если вы используете для работы с сетью AFNetworking, то он за кулисами разбирает JSON с помощью NSJSONSerialization, и вам вообще не нужно думать о том, какой JSON парсер выбирать и использовать, так как за вас всё уже сделано и вы получаете готовые свои ответы уже завернутые из JSON в NSDictionary/NSArray. Кратко: используйте NSJSONSerialization!

Ответ 2



Мне нравится NSJSONSerialization, вполне самодостаточен, и да чутка не удобен. Очень нравится KISSXML к нему есть категории расширяющие работу с JSON и XML. ну и я за JSONKit Сравнение

NSTimer приостанавливает выполнение при скролле uitableView

#objective_c #uitableview


Есть UIVew c кнопкой старт,  UILabel  в который записывается текущее время и uitableView,
в котором время сохраняется (как простой стандартный таймер)
Проблема в том, что при скролле таблицы - таймер замерзает, как сделать чтобы они
работали синхронно ?
имею такой таймер 
- (IBAction)startTimer {
    _startButton.hidden = YES;
    _stopButton.hidden = NO;

    isRun = YES;

    UIBackgroundTaskIdentifier bgTask = UIBackgroundTaskInvalid;
    UIApplication *app = [UIApplication sharedApplication];
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        [app endBackgroundTask:bgTask];
    }];

    myTimer = [NSTimer scheduledTimerWithTimeInterval:0.01f
                                               target:self
                                             selector:@selector(tick)
                                             userInfo:nil
                                              repeats:YES];

}

и функию 
- (void)tick {

    _timeSot++;

    sot++;

    if (_timeSot > 99) {
        _timeSot = 0;
        _sec++;
    }
    if (_sec > 59) {
        _sec = 0;
        _min++;
    }
    //_min = _sec / 60;

    NSString *sotStr;
    if (_timeSot < 10) {
        sotStr = [NSString stringWithFormat:@"0%d", _timeSot];
    } else {
        sotStr = [NSString stringWithFormat:@"%d", _timeSot];
    }

    NSString *secStr;
    if (_sec < 10) {
        secStr = [NSString stringWithFormat:@"0%d", _sec];
    } else {
        secStr = [NSString stringWithFormat:@"%d", _sec];
    }

    NSString *minStr;
    if (_min < 10) {
        minStr = [NSString stringWithFormat:@"0%d", _min];
    } else {
        minStr = [NSString stringWithFormat:@"%d", _min];
    }

    myTime = [NSString stringWithFormat:@"%@:%@:%@", minStr, secStr, sotStr];

    if (sot >= ([[[_exerises objectAtIndex:_indexExercise] objectForKey:@"timeWorkOutExerciseClient"]
intValue] * 100)) {
        [self stopTimer];
        [self sendNotification];
    }

    [_timeLabel setText:myTime];
}
    


Ответы

Ответ 1



Проблема решена: [[NSRunLoop mainRunLoop] addTimer:myTimer forMode:NSRunLoopCommonModes];

В чём разница между CFDictionary и CFMutableDictionary?

#objective_c #xcode #macos #corefoundation


Здравствуйте, участники форума. Мой вопрос отражён в заголовке. Можно ли выполнить
какое-либо приведение типа, чтобы свести CFMutableDictionary к CFDictionary. Заранее
спасибо за помощь!)))    


Ответы

Ответ 1



Не совсем приведение, но может CFDictionaryCreateCopy подойдет : @function CFDictionaryCreateCopy Creates a new immutable dictionary with the key-value pairs from the given dictionary. Пример: CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); ... CFDictionaryRef copy = CFDictionaryCreateCopy(NULL, dict); CFRelease(dict);

Ответ 2



Разглядывание http://www.opensource.apple.com/source/CF/CF-476.14/CFDictionary.h показало, что все эти ...ref типы, по сути, void *. Может, попробовать через такие приведения типа (только позволит ли компилятор?). (Правда, стоит отметить, что mutable реально отличается по крайней мере флагами в дескрипторе хэш-таблицы, так что гарантировать работоспособность, не изучая тщательно код, не получится.)

четверг, 13 февраля 2020 г.

Проверка на лишний код в Xcode

#xcode #ios #objective_c


Здравствуйте, есть ли какой-нибудь инструмент на выявления неиспользованного кода
в Xcode?    


Ответы

Ответ 1



Кое-что может дать анализ проекта в икскоде (реально это clang analyzer), он способен найти переменные, которые были объявлены, но не использованы (int a = 10; int b = a*2; a++; return b;), да и в целом полезный инструмент. Также можно попробовать запустить gcov - он способен понять, какую строку сколько раз запускали в рантайме, но он показывает именно то, что было запущено, а это может, в свою очередь, зависеть от входных данных.

Ответ 2



Да, очень хорошо с этим справляется AppCode :) Держу его преимущественно для этих целей.

Ответ 3



В верхнем меню xCode пункт Product -> Analyze (Shift + Cmd + B).

суббота, 8 февраля 2020 г.

Перенос текста UILabel или UITextField

#xcode #ios #objective_c


Наверное, затасканый вопрос, и я запросто могу нарваться на минусы, но все же: не
могу найти, как объяснить Xcode, что нужно перенести текст. 
У меня есть UITextField, в котором ну слов +-200, задаю я его не через Xib, а хардкодом.
Как мне поставить ограничение по ширине, чтобы дойдя до него, слова перенеслись ниже?
Буду благодарен, если подскажете, как сделать это для UITextField и UILabel.    


Ответы

Ответ 1



У класса UILabel смотрите свойство lineBreakMode и соответственно перечисление видов переноса, которые он поддерживает ну и на всякий случай numberOfLines. С UITextField перенос невозможен - насколько мне известно, это поле может быть только однострочным. Для многострочного ввода посмотрите в действии на UITextView - скорее всего вам нужно использовать его. Маленькое замечание: у этого класса, хотя его поля и являются многострочными, отсутствует свойство lineBreakMode аналогичное такому в UILabel. Гляньте также соответствующие ссылки на SO: Wrap text in UITextField How to create a multiline UITextfield? UITextView character wrap but not word wrap

Как в Objective-C изменить стандартный переход в Storyboard из одной сцены к другой

#ipad #objective_c #ios #iphone


В моем проекте пока стоит стандартный переход от сцены к сцене при push. 
А мне задумалось сделать что-то поинтереснее.
Как это можно реализовать?
У меня в основе стоит Navigation Controller.
И кстати когда я пытался сделать переход типа modal - симулятор прекращал работу
приложения.
Ну и хочется сделать что-то поинтереснее чем четыре модальных варианта.
Заранее благодарен за помощь )    


Ответы

Ответ 1



Вот вам история в картинках: 1) Начинаете с того, что добавляете новый класс: 2) Делаете его подклассом UIStoryboardSegue, называете его, как хотите: 3) Добавляете в получившийся .m-метод метод perform: #import "CustomSegue.h" #import @implementation CustomSegue - (void)perform { UIViewController *sourceViewController = (UIViewController *)[self sourceViewController]; UIViewController *destinationController = (UIViewController *)[self destinationViewController]; CATransition* transition = [CATransition animation]; transition.duration = .25; transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; transition.type = kCATransitionPush; //kCATransitionMoveIn; //, kCATransitionPush, kCATransitionReveal, kCATransitionFade transition.subtype = kCATransitionFromTop; //kCATransitionFromLeft, kCATransitionFromRight, kCATransitionFromTop, kCATransitionFromBottom [sourceViewController.navigationController.view.layer addAnimation:transition forKey:kCATransition]; [sourceViewController.navigationController pushViewController:destinationController animated:NO]; } @end 4) Идете в Storyboard. Удерживая Control, тянете от одного контроллера к другому мышь - отпускаете, выбираете custom: 5) Указываете в свойствах этой Segue, что её класс - CustomSegue. 6) Добавляете в проект фреймворк QuartzCore (если он ещё не добавлен). 7) Пробуете разные способы анимации через изменение опций в методе perform. Удачи!

Возможна ли локализация UI элементов в Xcode iOS?

#xcode #ios #iphone #objective_c


Возможно ли наитивным образом поставить, чтобы надпись в searcBar для отмены была
не "cancel", а "отмена", в TableView при commitEditingStyle были надписи в строках
не "Delete", а "Удалить". Это вообще возможно как то прописать в настройках среды,
или где еще, или только самому прописывать можно? В симуляторе стоит в настройках русский
язык. Искал в сети на обоих языках - нашел информацию только что для подобных элементов
язык сам должен правильный выставляться, но в моем случае этого не происходит. Работаю
в Xcode 5, iOS 7 SDK. 
Для SearchBar пробовал этот способ:
 [[UIButton appearanceWhenContainedIn:[UISearchBar class], nil] 
                                         setTitle:@"Отмена" 
                                         forState:UIControlStateNormal];

Не помогло.    


Ответы

Ответ 1



Конечно возможно, все базовые вещи переводятся автоматом, если вы включаете поддержку других языков в своем проекте. Все остальные строки локализуются либо через NSLocalizedString либо через Base Internationalization в Storyboard. Все строки в сториборде могут быть локализованы, делается это также при добавлении Base в список Languages (у вашей сториборды появляются локализованные варианты). В UISearchBar кнопка будет локализована автоматическии, если вы добавите язык в Проект (вверху слева в дереве навигации по проекту) -> далее следует выбрать проект (не target) -> вкладка Info -> раздел Localizations - список языков. Чтобы локализовывать свои UI элементы - self.label.text = NSLocalizedString(@"Sting to be localized", @"comment for translator"); вот хороший туториал по локализации (теперь на русском): http://www.raywenderlich.com/ru/36227/Локализация-приложений-в-ios а по сторибордам там вроде и так все предельно ясно будет, единственное, autolayout должен быть включен

Как в objective-c передать массив NSString в метод?

#ios #objective_c #xcode


В objective-c мне необходимо передать в метод двумерный массив NSString. Я его объявляю
NSString *products[10][10];, потом присваиваю какие-то значения, и не могу написать
метод, чтобы он принимал его.
Компилятор не пропускает такие объявления:

-(void) Array : (NSString *) array[][];
-(void) Array : (NSSting[][] *) array;


А так же охота, чтобы метод возвращал двумерный массив NSString. Т.е. такое тоже
не проходит:

-(NSString[][] *) ArrayCount : (int) count;


Помогите, пожалуйста! Как правильно писать такие методы, которые бы принимали и возвращали
двумерный массив NSString? Или такое вообще не возможно?
    


Ответы

Ответ 1



Традиционно в ObjC нет двумерных массивов — вместо них используется такое понятие как "массив массивов". То есть массив, каждым элементом которого является другой массив. Объявить его можно либо: NSArray *row1 = @[@"string1", @"string2"]; NSArray *row2 = @[@"string3", @"string4"]; NSArray *container = @[row1, row2]; либо: NSArray *container = @[@[@"string1", @"string2"], @[@"string3", @"string4"]]; и далее вы передаёте в метод массив container. Чтобы получить элемент из массива: container[0][0]; Так же надо добавить, что поскольку ObjC основан на C, любой C-код будет работать, включая 2D массивы, но тогда и те методы, куда эти массивы передаются надо писать на C.

Как выбрать нужную кнопку

#ios #objective_c #ios7


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

Пример

for (int i = 0; i < 5; i++) {

    UIButton * testView2 = [[UIButton alloc] initWithFrame:CGRectMake(20, hightArray1
+ 90 + 37 * i, 280, 35)];
    testView2.backgroundColor = [UIColor whiteColor];
    testView2.layer.cornerRadius = 5.f;
    testView2 addTarget:self action:@selector(actionTestView1) forControlEvents:UIControlEventTouchUpInside];
    [self.mainScrollView addSubview:testView2]; }

    


Ответы

Ответ 1



Я бы сказал, что использовать viewWithTag в этом случае не очень хорошо. В этом случае вы фактически используете view для хранения model, что неправильно в рамках MVC паттерна. Лучше было бы создать массив и в него сложить все UIButtons, и потом их получать по индексу: UIButton *myButton = (UIButton*)buttonArray[index];

Ответ 2



Добавте для кнопки tag. testView2.tag = 100; Далее можете достать кнопку по тэгу: UIButton *button = (UIButton *)[self.view viewWithTag:100];

среда, 5 февраля 2020 г.

Core Data vs FMDB->sqlite

#objective_c #ios #coredata #sqlite


Стартовые условия - есть уже работающие сервер (MSSQL->JSON) и клиент (JSON->CoreData)
под iOS, и пишется клиент под Android который будет локально работать на sqlite. Руководство
хочет уйти от привязки к JSON'у на iOS, которую сделал исполнитель, и перевести iOS-клиент
на работу с sqlite, чтобы сделать в будущем highload-backend с которым потенциально
смогут работать обе мобильные платформы (а не два бекенда для каждой платформы как
сейчас). Передо мной (нынешний исполнитель) дилемма - перепиливать CoreData на прием
из сети sqlite и ее засовывание в CoreData, или переписывать все для FMDB->sqlite.
Все склоняется к тому чтобы использовать то, что будет быстрее работать на клиенте
визуально. Причиной создания данного топика стало то что возможности попробовать нет,
так как написание приложения на FMDB с нуля займет непозволительно много времени, и
если оно не окупится по итогу то много времени будет потрачено зря. Прошу не разводить
холивар на тему кому что больше нравится а описать какие-то практические данные с реальных
проектов, околограничные проблемы обоих решений, свой личный опыт о том что из этих
вариантов работает быстрее или имеет какие-то преимущества.     


Ответы

Ответ 1



Я немного запутался в вашем вопросе, но все равно попробую ответить. Мне странно, что ваше руководство "хочет уйти от привязки к JSON'у на iOS" и я, честно говоря, впервые слышу, чтобы работающий клиент (JSON->CoreData) перекраивали под то, чтобы работать с sqlite (то есть даже вообще впервые слышу, чтобы sqlite служил транспортом вместо JSON особенно в целях унификации платформ). Возможно я не знаю каких-то особых подходов и тонкостей, но, кажется, JSON является абсолютным стандартом при передаче данных в сетевой схеме взаимодействия между клиентом-приложением и сервером-бэкэндом. Я ни разу не встречал, чтобы топовые библиотеки в мире Apple/iOS работали с чем-то кроме JSON. Достаточно назвать AFNetworking и RestKit. Сказав это, добавлю что такое решение вашего руководства выглядит вдвойне странным в виду того, что, повторю еще раз, если я правильно понял, они стремятся добиться максимальной универсальности решения. Исходя из сказанного выше, мне кажется, что не должно быть никаких сомнений, что ваш сервер должен отдавать JSON (ну и замечательно будет, если все по REST-конвенциям спроектировано будет или уже), и должны быть клиенты iOS и Android соответственно, которые будут этот JSON переносить уже к себе с учетом своих специфик. Если сказанное до сих пор верно, можно уже поставить немного другой вопрос, на который я могу ответить тоже лишь частично и только про Apple/iOS: "ваш опыт налаживания подобных схем" и его подвопросы: стоит ли пользоваться RestKit (так как это единственное full-stack решение подобных задач, насколько я знаю работает только с Core Data), и если нет, то пользоваться ли Core Data или отказаться от него и использовать sqlite? Мой личный опыт такой: я занимаюсь разработкой именно iOS-приложений около 11 месяцев, все это время я делаю приложение, которое можно, сказав грубо, назвать клоном FourSquare - говорю это для того, чтобы показать, что я достаточно плотно столкнулся именно с вопросами взаимодействия сервера, спроектированного в соответствии с REST и отдающего JSON, и клиента, которому нужно этот JSON разложить в Core Data. Так получилось, что о RestKit узнал далеко не сразу. Поэтому оказалось, что научение тому, как сделать все грамотно, то есть разобраться с многопоточностью, GCD, Core Data, всему тому, что RestKit делает где-то за кулисами прямо из коробки, заняло у меня очень много времени (где-то месяцев 5). Позже оказалось (когда я-таки взглянул внимательно на RestKit), что для того, чтобы полностью реализовать работающую схему JSON<->Core Data, мне пришлось сделать код, весьма напоминающий по структуре код RestKit. Он не столь идеально абстрагирован по сравнению с RestKit, но с поставленными задачами справляется, и чем дальше продвигается мой проект, он все больше начинает на него походить, хотя и с небольшой разницей в наших подходах (кстати, судя по профилю на Гитхабе, автор RestKit работает на TripAdvisor - то есть вот against what он разрабатывает RK). Про свои недоумения относительно RestKit я задавал здесь на ХК вопрос, на который, к сожалению, так и не получил хотя бы одного внятного ответа: RestKit - за и против?. То есть после года экспериментов я все еще колеблюсь по поводу того, чтобы полностью перейти на RestKit, так как уже сам почти научился решать эти задачи и немного в более близком лично мне ключе, чем это делает RestKit, но, повторю, времени и усилий это заняло достаточно много! Резюмируя эту часть: если вы хотите сэкономить время на склейке JSON в Core Data, используйте готовое решение, - постарайтесь перейти на RestKit, если готового самописного еще не стало так много, что миграция окажется очень сложной --- RestKit прекрасно справится с задачей по переводу JSON в Core Data и обратно. Некоторые задачи там решаются настолько легко, что это и впрямь выглядит как magic. Теперь отвечу совсем немного про "Core Data vs FMDB->sqlite". Я начинал изучать iOS строго по гайдам и там все время мелькало Core Data, поэтому я опять же не сразу узнал, что бывают просто разнообразные ORM и оболочки и key-value store, работающие с sqlite. Мой результат - это то, что я вполне нормально освоился с Core Data и НИ РАЗУ не встретил СЕРЬЕЗНЫХ ограничений, которые заставляли бы меня подумать о переходе к каким-то другим решениям, хотя за это время я узнал о существовании не только FMDB, но и, например, таких вот решений: NanoStore, YapDatabase, iActiveRecord (особенно близкое и понятное мне, так как я имеющ опыт работы с ActiveRecord в Ruby on Rails). На этом пока все. Возможно позже я дополню свой ответ, если придумаю, как сделать его лучше. ОБНОВЛЕНО ПОЗЖЕ Я могу себе представить только один возможный случай, когда работа с sqlite (без JSON вообще) может оказаться адекватной - это случай так называемой оффлайн-работы. Приведу простой пример: у вас есть приложение с картами (Яндекс карты) и вы в момент начала пользования приложением скачиваете разом NN мегабайтовую карту и с этого момента пользуетесь исключительно скачанной картой, так как карта обновляется очень редко и вы можете быть уверены, что скачанная карта будет служить вам верой и правдой, хм, адекватно отражать местность и завтра и послезавтра. То есть, если база, с которой будет работать ваше приложение, является более или менее статичной, вы можете при первой загрузке приложения (в момент начала использования приложения) просто разово передавать ее одним большим файлом (чуть ли не дампом базы) и просто импортировать её средствами местной на клиенте DB (не узнавал, возможно ли такое в Core Data или в SQLite, но очевидно, что подходы должны существовать). Таким образом вы на корню рубите вопросы синхронизации, JSON, весь этот парсинг, маппинг, асинхронность и много других слов и проблем. Единственное требование к специфике приложения - это, чтобы оно не должно было постоянно лазить за чем-то очень свежим и постоянно обновляющимся на ваш сервер, в сеть. Мне кажется, мое описание этого случая вполне ясно. ОБНОВЛЕНО ЕЩЕ ПОЗЖЕ Интересный топик на SO, открытый авторами вопроса и ответа на эту тему: Improve process of mirroring server database to a client database via JSON.

Ответ 2



Последний раз с CoreData (с нуля) работал довольно давно, но периодически приходилось поддерживать существующие проекты. С sqlite приходилось работать в паре проектов, но последние проекты были в основном тонкими клиентами. Все последующие мысли не являются истинной правдой, они основаны на мои знаниях, а в них есть много пробелов (я плохо знаю CoreData). CoreData это не аналог и не замена sqlite. Это два абсолютно разных инструмента, и у них разные области применения. Если нужно делать какие-то очень хитрые запросы (например вычислять географическое расстояние), то здесь будет удобнее sqlite. В остальных случаях будет достаточно CoreData'ы. CoreData - Контекст и невалидные сущности. Если в контекст попала невалидная сущность, и вы проморгали ее удаление оттуда то сохранить контекст уже не удастся. - CoreData - отдельный стек, не похожий на SQL с которым мне приходилось работать до этого. Причем стек довольно большой, а т.к. область применения относительна невелика, то зачастую очень тяжело найти решение какой-нибудь нетривиальной проблемы. + Работает "из коробки", при использовании сторонних оберток (MagicalRecord, ObjectiveRecord) работа с ней становится гораздо приятней. + Система миграций, не нужно писать raw sql (зачастую это излишне) SQLite - Приходится много писать относительно низкоуровневых вещей, либо пользоваться каким-то враппером, но даже с тем же FMDB приходится писать много, т.к. это всего лишь адаптация sqlite3 API для Objective-C. Как я указал в комментарии, пытался писать свою обертку, но задача далеко не тривиальная, вылазит много граблей/костылей - Приходится руками создавать таблицы, накатывать миграции (iActiveRecord частично решает эту проблему). + Это все же SQL и используется на многих платформах, а потому гораздо проще найти решение проблем/вопросов. + Полный контроль над взаимодействием с БД. Резюме В последующих проектах при выборе между SQLite и CoreData я в первую очередь буду опираться на требования, т.к. оба подхода имеют свои минусы и плюсы, и как правило если что-то легко в CoreData, то сложно в SQLite. И наоборот.