[закрыто] coreData, cloudKit, резервное копирование


#41

нет ))) там свой модуль аутентификации


#42

Что-то в этой теме всё-таки не так … очень сильно разнится информация … вот эти две ссылки вообще кашу в голове сделали: 1 и 2


#43

В библиотеке ест ьпример, посмотрите его для начала


#44

Тут правда на английском, но рассказывает как делать cloudKit в проекте и есть пример!


#45

Да ничего не разнится, я же вам уже несколько раз объяснял )))
Активируя “iCloud” в ИксКоде в Capabilities, вы увидите 3 опции:

  1. Кey-value - неактуальный, но до сих пор поддреживаемый сервис копирования данных корДаты в облако;
  2. iCloud Documents - доступ в iCloud пользователя;
  3. CloudKit - актуальная бэкенд БД от Эппл для резервного копирования КорДаты и не только.

Тк видимо Эпл хочет, чтобы разработчики пользовались актуальными инструментами, то обновлённая документация есть только на CloudKit, поэтому и актуальные обучающие видосы в основном на этот инструмент. Даже на iCloud Documents официальная документация часть на swift 2, часть на Obj-C

У меня всё работает. Добавил код загрузки файла в примере выше.

То что вам не нравится организация cloudKit, это уже другой вопрос. Идеальных инструментов нет. Но всегда есть много альтернатив…

Ну одно и то же, честное слово )))


#46

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


#47

Поправьте меня если я ошибаюсь, но я уже вам писал, что достаточно сгенерировать уникальный ключ для пользователя и сохранить в связку ключей. Связка ключей работает без привязки к айклауду. То есть, можно не париться, что ключ прое… пропадет! Этот ключ - идентификатор пользователя к которому весь этот хлам и относится. По нему вы можете хранить на любом сервере хоть черта лысого, не только простые данные. Далее достаточно, просто по этому ключу посмотреть, есть ли что-то, что нужно загрузить обратно. Что тут может быть непонятного?


#48

Если честно, Вы описываете несколько неверрно:

  1. Это онлайн UserDefaults. Не CoreData. И он полностью актуален.

  2. Это для Document-based apps. Не знаю, каким местом он устарел, но на последней WWDC ему 3 сессии и 4 лабы посвятили.

  3. CloudKit это онлайн БД. Никакого отношения к резервному копированию CoreData она не имеет. Ранее было iCloud CoreData, но в 16-ом году она была тихо выпилена.

  4. То, что Вы приводите как пример, это архивированная документация и она более не поддерживается почти уже год. Официальная - только reference API.


#49

Всем спасибо. Ничего у меня так и не получилось. Одни говорят одно, другие другое … а мне просто нужно было сделать резервную копию корДаты … точнее sqlite файла. Где-то вообще пишут, что нужно использовать только клоудКит … тогда зачем корДата … короче что попало …

Админы форума, конечно, хороши … могли бы и объяснить толково, что для чего и как лучше сделать … так они вообще даже ни разу не ответили, хотя всем лично отправляла приглашение … или вы считаете, что это детские вопросы?

Кто-то здесь пытался дать информацию на английском … тогда, спрашивается, зачем вообще этот русскоязычный сайт? Админы, а? Не могу я на английском понять …

Знаете, мне вообще в какой-то момент показалось, что админы больше отвечают только по курсам … потому что по другим вопросам не интересно или не знают сами, а только то, что в курсах если знают сами, а если вопрос непростой и не знают - молчат и ждут пока кто-то другой ответит … + никак не могу избавиться от чувства, что информация дублируется, словно они чужие курсы переводят на русский и продают здесь … поэтому и помогать не хотят и не могут, потому что знают только то, что самы выучили …

Позорище блин …
Наверное, и правда, не буду больше оплачивать курсы … лучше за эти деньги на фрилансе попрошу помощи …

Удачи всем …


#50

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


#51

Я же вам ответил как сохранить и загрузить файл…

Зря вы так: люди по свой инициативе бесплатно перевели главный документ - документацию по сфит. Её больше нигде нет на русском… И за это их ещё и поносят… Тут вроде ни кто не обещал, что будут отвечать ежесекундно и на любой вопрос. В основном тут отвечают такие же обучающиеся… Это, кстати, один из элементов обучения - учиться искать ответ самому. И да - это факт, что большинство ответов на английском. И тут первый вопрос себе надо задавать, а не админам. Я вот пока вам отвечал, по сохранению файла в айклоуд, сам разобрался что к чему, а должны были вы )))

Делают хорошие курсы за деньги (при этом на дастаточно высоком уровне: вы просто звук сравните, детали, типа вылавливания ошибок на раннем этапе и прочее. Большинство (а это от 2 до 5 человек ))) ) в рунете делают просто чтобы работало) - это абсолютно нормально. Так же как и все разработчики хотят зарабатывать - всегда нужно ощущать отдачу за свой труд. А когда за альтруизм ещё и негатив получаешь, вряд ли кто-то захочет вам помогать в будущем…


#52

Вы про что? Мне банально не хватает времени на переписку, тут вариантов много вам дали, вы просто не смогли все свести воедино. Иногда проще поправить код человеку иди сделать за него, чем мониторить сообщения. Ну и вспомните, я вам предлагал прислать проблемный код, чтобы я помог его написать для вас. Вы просто отморозились! Тогда я решил, что вы хотите все делать сами. Дело ваше, но у админов тоже своя работа (постоянная) есть, им нужно работать. А обижаться не на кого, все пишут по мере свободного времени.

По поводу сообщений в личку без приглашения… Знаете как раздражает, когда все считают, что если они засрут мне или другому ящик со своими просьбами, то и проблема решится сама собой. Для того и существует форум, чтобы помочь разобраться в теме, направить по верному пути. Но личка к форуму не относится.

Ну так всей информации на русском и не будет. Русскоязычный ресурс для помощи вхождения в мир разработки. Для разработчика нормально изучать инфу на английском. Как минимум, уметь читать со словарем.

По мне, еще то извращение!

Для хранения информации в офлайн. Если требуется синхронизация и резервирование пользовательских данных, потрудитесь разобраться со способами хранения информации на сервере. Не одним CloudKit этот способ хранения обладает. Всякие облачные платформы, можно Parse себе на сервере поставить.


#53

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

//
//  CloudKitHelper.swift
//  Best Radio TV
//
//  Created by VITALIY PODOLSKIY on 16/04/16.
//  Copyright © 2016 InstaRobot.NET. All rights reserved.
//

import Foundation
import CloudKit

fileprivate func < <T : Comparable>(lhs: T?, rhs: T?) -> Bool {
  switch (lhs, rhs) {
  case let (l?, r?):
    return l < r
  case (nil, _?):
    return true
  default:
    return false
  }
}

fileprivate func > <T : Comparable>(lhs: T?, rhs: T?) -> Bool {
  switch (lhs, rhs) {
  case let (l?, r?):
    return l > r
  default:
    return rhs < lhs
  }
}

class CloudKitHelper {
    
  static let sharedInstance = CloudKitHelper()
  
  let container: CKContainer!
  let privateDatabase, publicDatabase: CKDatabase!
  let recordTypeStringFavorites, recordTypeStringPopulars: String!
   
  fileprivate init() {
    container                 = CKContainer.default()
    privateDatabase           = container.privateCloudDatabase
    publicDatabase            = container.publicCloudDatabase
    recordTypeStringFavorites = "Favorites"
    recordTypeStringPopulars  = "Populars"
  }
    
  //MARK: - METHODS FOR CLOUD KIT - PRIVATE DATABASE
  /**
   Save favorite station for current user
   - parameter station:    Name starion <String>
   - parameter url:        Url station <String>
   - parameter completion: for cuccess <Cloud Kir Record>
   */
  func saveFavorite(_ station:String, url: String, completion: @escaping ((_ record: CKRecord?) -> Void)) {
    let timestampAsString = String(format: "%f", Date.timeIntervalSinceReferenceDate)
    let timestampParts    = timestampAsString.components(separatedBy: ".")
    let recordID          = CKRecordID(recordName: timestampParts[0])
    let favoriteRecord    = CKRecord(recordType: recordTypeStringFavorites, recordID: recordID)
    favoriteRecord.setObject(station as CKRecordValue?, forKey: "station")
    favoriteRecord.setObject(url as CKRecordValue?, forKey: "url")
    privateDatabase.save(favoriteRecord, completionHandler: { record, error -> Void in
      if (error != nil) {
        print(error?.localizedDescription ?? "")
      }
      completion(record)
    })
  }
    
  /**
   Fetch list of favorite's stations - Private Database
   - parameter completion: for success Array<Cloud Kit Records>
   */
  func fetchFavorites(_ completion: @escaping ((_ favorites: Array<CKRecord>?) -> Void)) {
    var arrayFavorites: Array<CKRecord> = []
    let predicate = NSPredicate(value: true)
    let query = CKQuery(recordType: recordTypeStringFavorites, predicate: predicate)
    privateDatabase.perform(query, inZoneWith: nil) { results, error -> Void in
      if error != nil {
        print(error?.localizedDescription ?? "")
      } else {
        for item in results! {
          arrayFavorites.append(item as CKRecord)
        }
      }
      completion(arrayFavorites)
    }
  }
 
  /**
   Delete favorite station from CloudKit - Private Database
   - parameter recordID:   ID for current Record <Cloud Kit Record ID>
   - parameter completion: for success <true ? false>
   */
  func deleteFavoriteRecord(_ recordID: CKRecordID, completion: @escaping ((_ result: Bool?) -> Void)) {
    let selectedRecordID = recordID
    var result: Bool!
    privateDatabase.delete(withRecordID: selectedRecordID) { recordID, error -> Void in
      if error != nil {
        result = false
        debugPrint(error?.localizedDescription ?? "")
      }
      else {
        result = true
      }
      completion(result)
    }
  }
    
  /**
   Check favorite station from CloudKit - Private Database
   - parameter stationName: Name foe station <String>
   - parameter completion:  for success <true ? false : faborite ID <Cloud Kit Record ID>>
   */
  func checkStationInFavorites(_ stationName: String! ,completion: @escaping ((_ result: Bool?, _ favoriteID: CKRecordID?) -> Void)) {
    let predicate = NSPredicate(format: "station = %@", stationName)
    let query = CKQuery(recordType: recordTypeStringFavorites, predicate: predicate)
    privateDatabase.perform(query, inZoneWith: nil) { results, error -> Void in
      if error != nil {
        print(error?.localizedDescription ?? "")
      } else {
        if results?.count > 0 {
          var arrayFavorites: Array<CKRecord> = []
          for item in results! {
            arrayFavorites.append(item as CKRecord)
          }
          completion(true, arrayFavorites.first?.recordID)
        } else {
          completion(false, nil)
        }
      }
    }
  }
    
  //MARK: - METHODS FOR CLOUD KIT - PUBLIC DATABASE
  /**
   Save popular station to CloudKit - Piblic Database
   - parameter station:    Name for current user station <String>
   - parameter url:        Url for current user station <String>
   - parameter completion: for success <Cloud Kit Record>
   */
  func savePopular(_ station:String, url: String, completion: @escaping ((_ record: CKRecord?) -> Void)) {
    if station != "" {
      checkStationInPopulars(station, completion: { result, popularRecord -> Void in
        if result == true && popularRecord != nil {
          let currentRecord = popularRecord
          var currentCount = currentRecord?.value(forKey: "count") as! NSInteger
          currentCount += 1
          currentRecord?.setObject(station as CKRecordValue?, forKey: "station")
          currentRecord?.setObject(url as CKRecordValue?, forKey: "url")
          currentRecord?.setValue(currentCount, forKey: "count")
          self.publicDatabase.save(currentRecord!, completionHandler: { (record, error) -> Void in
            if (error != nil) {
              print(error?.localizedDescription ?? "")
            }
            completion(record)
          })
        } else {
          let timestampAsString = String(format: "%f", Date.timeIntervalSinceReferenceDate)
          let timestampParts = timestampAsString.components(separatedBy: ".")
          let recordID = CKRecordID(recordName: timestampParts[0])
          let popularRecord = CKRecord(recordType: self.recordTypeStringPopulars, recordID: recordID)
          popularRecord.setObject(station as CKRecordValue?, forKey: "station")
          popularRecord.setObject(url as CKRecordValue?, forKey: "url")
          popularRecord.setValue(1, forKey: "count")
          self.publicDatabase.save(popularRecord, completionHandler: { record, error -> Void in
            if (error != nil) {
              print(error?.localizedDescription ?? "")
            }
            completion(record)
          })
        }
      })
    }
  }
    
  /**
   Fetch list of popular's stations - Public Database
   - parameter completion: for success <Array Cloud Kit Records>
   */
  func fetchPopulars(_ completion: @escaping ((_ populars: Array<CKRecord>?) -> Void)) {
    var arrayPopulars: Array<CKRecord> = []
    let predicate = NSPredicate(value: true)
    let query = CKQuery(recordType: recordTypeStringPopulars, predicate: predicate)
    query.sortDescriptors = [NSSortDescriptor(key: "count", ascending: false)]
    publicDatabase.perform(query, inZoneWith: nil) { results, error -> Void in
      if error != nil {
        print(error?.localizedDescription ?? "")
      } else {
        for item in results! {
          arrayPopulars.append(item as CKRecord)
        }
      }
      completion(arrayPopulars)
    }
  }
    
  /**
   Check popular station from CloudKit - Public Database
   - parameter stationName: Station namr <String>
   - parameter completion:  for success <true ? false: Cloud Lit Record>
   */
  func checkStationInPopulars(_ stationName: String! ,completion: @escaping ((_ result: Bool?, _ popularRecord: CKRecord?) -> Void)) {
    let predicate = NSPredicate(format: "station = %@", stationName)
    let query = CKQuery(recordType: recordTypeStringPopulars, predicate: predicate)
    publicDatabase.perform(query, inZoneWith: nil) { results, error -> Void in
      if error != nil {
        print(error?.localizedDescription ?? "")
      } else {
        if results?.count > 0 {
          var arrayPopulars: Array<CKRecord> = []
          for item in results! {
            arrayPopulars.append(item as CKRecord)
          }
          completion(true, arrayPopulars.first)
        } else {
          completion(false, nil)
        }
      }
    }
  }
    
}

#54
  1. Месяц назад я приводила пример, что десятки тем по cloud и тп. без ответа. + люди просят дать информацию = никакой реакции от админов.

  2. “админы” в данном случае люди, которые на всём этом бабосики рубят, а не те ребята, которые помогают бесплатно в разы больше админов. А как раз вот эти простые ребята - дают 99% информации и помогают, за что им огромное спасибо…

  3. Как минимум, если сами админы не хотят помогать, то должны делиться своими деньгами с теми, кто помимо основной работы сидит и помогает таким, как я … - судя по всему этого нет даже в мыслях у них.

  4. “По мне, еще то извращение!” вот этот ответ очень важен, хотя всего 5 слов… но почему извращение? Но я нашла минимум 8 вариантов, как бэкапить информацию … + на фрилансе мне ещё накидали кучу вариантов и получается, что крыша едет … но мать их админы - они могли бы взять и объяснить, что в таком случае так и так, а в таком - вот так, потому что бред получается, … если почитать их ответы, то они без проблем помогут сегу настроить между контроллеров - это же сложно очень, но как клоудКит - это ж несложно - сами разберетесь …

  5. Прежде чем код, нужно сперва определить единственный самый оптимальный вариант, а потом в нем копаться. Я не ленивая и не хочу тупо копипастить, но я не понимаю до сих пор, какой вариант выбрать … почему действительно не проще хранить SQLite в iCloud Drive и обновлять его, синхронизация не нужна … мне всегда больше теория нужна, чтобы логически понимать, а потом уже код.

  6. И ещё раз обращаю внимание на то, что админы - в данном случае организаторы всего этого… А вот Вы (rocotech), ODIN, RexHunt и другие ребята … это реальная помощь … и только благодаря вам я смогла разобраться, потому что вы направляли.

Rocotech - по коду - мне банально стыдно обо всем спрашивать, поэтому я лучше лишние сутки покапаюсь и разберусь … вы мне показали направление - достаточно, дальше сама должна. Иногда спрашиваю после того, как сделала сама … чтобы убедиться, что правильно выбрала решение + чтобы ответ на этот вопрос на форуме остался, если я не нашла - кому-то пригодится. Или как с уведомлениями … Артём (Psilc) показал как - я не копипастила, а поняла как и ручками раза 4 переписывала всё, пока не получилось, теперь смогу помочь тоже кому-то. А если бы я писала обо всем, то весь форум был бы в моих вопросах, штук по 50 в день.

  1. Я тоже отвечаю на сообщения. которые мне пишут в личку, даю ссылки, помогаю с кодом, как могу … Но это мелочи… А ещё для тех, кто может помочь толково - можно было бы сделать платные ответы … как на фрилансе … и люди бы пользовались. Потому что фриланс забит такими заказами … там помочь, здесь объяснить, тут подправить. И люди готовы платить за это и не по 100р … хорошо платить, от нескольких тысяч.

Так что у меня не к вам претензии … а к админам, могли бы хотя бы общаться, а не проходить мимо и ждать, когда другие ответят … а если у них времени нет, так пусть делегируют (платно)


#55

Ну так я один из админов ) И бабосики не рублю на этом проекте! Я знаю историю создания проекта, как все начиналось и как выросло потихоньку. Админ (с правами админа) здесь на самом деле всего один, Иван. Он потихоньку отвечает, некоторые вопросы нам перекидывает. Ивана тоже поймите, он курсы пишет, постоянно в поиске новой и интересной информации. Плюсом идет новый проект, который скоро откроется, а его подрядчики периодически подводят. Так что, ему явно сейчас не до форума.

Потому, что бекапить придется и служебную информацию к таблицам. Поначалу БД мало места занимает, после она становится огромной.

На самом деле в iCloud имеет смысл сохранять информацию из document based приложений, которые работают со своим типом информации. Если покопаетесь по приложениям сохраненных в айслауд, увидите, что они хранят обычно, это банально документы.

Тот же WhatsApp не “бэкапит” данные, как они есть, а заливает на iCloud лишь служебную информацию, как все это развернуть, сама информация хранится на их серверах.

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

Я могу помочь с Parse-сервером, если хотите. Настрою его вам, все установлю и покажу как использовать. У вас отлетит тот геморрой, что вы себе придумали.

Стремление разобраться похвально, но не задавая вопрос, вы рискуете изобрести велосипед. Я на старте задавал очень много вопросов. Пол года ездил к одному человеку и мы с утра до вечера копались в коде. Он натаскивал меня и отвечал на вопросы. Только после этого я почувствовал, что могу продолжать самостоятельно и если что, то найти правильный ответ в интернете. Свифт тогда не существовал, это был Objective-C


#56

Решение проблемы наметилось. Потому закрываем тему. Для обсуждения похожего вопроса, лучше создать новый топик


Закрыл тему #57