2015-04-11 19 views
0

У меня есть UITableView с его содержимым, которым управляет NSFetchedResultsController, получающая CoreData. У меня есть два типа ячеек таблицы, один с изображением и один без изображения. Изображения обрабатываются UIDocument и хранятся в контейнере вездесущих документов iCloud и ссылаются на имя клиента.Утечка памяти с помощью UITableView и NSFetchedResultsController

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

Я подозреваю, что мой метод prepareForReuse() в моей таблице tableView не выполняет свою работу правильно.

Вот что выглядит мой UITableViewCell, как сейчас:

class ClientTableViewCell: UITableViewCell { 

@IBOutlet weak var clientName: UILabel! 

@IBOutlet weak var clientModifiedDate: UILabel! 

@IBOutlet weak var profileImage: UIImageView! 

let dateFormatter = NSDateFormatter() 

var document: MyDocument? 
var documentURL: NSURL? 
var ubiquityURL: NSURL? 

var metaDataQuery: NSMetadataQuery? 

var myClient : Client? 
{ 
    didSet 
    { 
     updateClientInfo() 
    } 
} 

override func prepareForReuse() { 
    super.prepareForReuse() 

    clientName.text = nil 
    clientModifiedDate.text = nil 

    if let mc = myClient 
    { 
     if mc.imageurl != "" 
     { 
      if let p = profileImage 
      { 
       p.image = nil 
      } else 
      { 
       NSLog("nil document") 
      } 
     } 
    } else 
    { 
     NSLog("nil client") 
    } 
} 


func updateClientInfo() 
{ 
    if myClient != nil 
    { 
     clientName.text = myClient!.name 

     dateFormatter.dateStyle = .ShortStyle 

     let dispDate = dateFormatter.stringFromDate(NSDate(timeIntervalSinceReferenceDate: myClient!.dateModified)) 

     clientModifiedDate.text = dispDate 

     if let imageName = myClient?.imageurl { 

      if myClient?.imageurl != "" { 

       var myClientName : String! 

       myClientName = myClient!.name 

       metaDataQuery = NSMetadataQuery() 

       metaDataQuery?.predicate = NSPredicate(format: "%K like '\(myClientName).png'", NSMetadataItemFSNameKey) 

       metaDataQuery?.searchScopes = [NSMetadataQueryUbiquitousDocumentsScope] 

       NSNotificationCenter.defaultCenter().addObserver(self, 
        selector: "metadataQueryDidFinishGathering:", 
        name: NSMetadataQueryDidFinishGatheringNotification, 
        object: metaDataQuery!) 

       metaDataQuery!.startQuery() 

      } 
     } 
    } 

} 


func metadataQueryDidFinishGathering(notification: NSNotification) -> Void { 

     let query: NSMetadataQuery = notification.object as! NSMetadataQuery 

     query.disableUpdates() 

     NSNotificationCenter.defaultCenter().removeObserver(self, name: NSMetadataQueryDidFinishGatheringNotification, object: query) 

     query.stopQuery() 

     let results = query.results 

     if query.resultCount == 1 { 
      let resultURL = results[0].valueForAttribute(NSMetadataItemURLKey) as! NSURL 
       document = MyDocument(fileURL: resultURL) 
       document?.openWithCompletionHandler({(success: Bool) -> Void in 
      if success { 

       if let pi = self.profileImage 
       { 
        pi.image = self.document?.image 
       } 


       } else { 
        println("iCloud file open failed") 
       } 
      }) 

     } else { 
      NSLog("Could not find profile image, creating blank document") 
     } 
} 

}

Если вы не знакомы с ICloud и UIDocument, вы можете быть удивлены, почему я запрашивая метаданные, чтобы получить на них изображения/документы. Если вы знаете о надежном способе получения этих изображений/документов в вездесущем контейнере, я все уши. Это приводит к появлению этого эффекта во время прокрутки ячеек таблицы.

А вот моя функция, которая заполняет клетку:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 

    //set the client 
    let client = clients.fetchedObjects![indexPath.row] as! Client 

    //set the correct identifier 
    if let imageurl = client.imageurl as String? 
    { 
     if imageurl == "" 
     { 
      var cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifierNoImage, forIndexPath: indexPath) as? ClientTableViewCell 
      cell!.myClient = client 
      return cell! 

     } else 
     { 
      var cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as? ClientTableViewCell 
      cell!.myClient = client 
      return cell! 
     } 
    } 
    var cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifierNoImage, forIndexPath: indexPath) as? ClientTableViewCell 
    cell!.myClient = client 
    return cell! 
} 

Первоначально я собирался использовать атрибут ImageUrl, чтобы сохранить имя и URL-адрес в профиле клиента изображений, но так как вездесущий контейнер URL является уникальным для каждое устройство, теперь я использую его только для определения, есть ли изображение с этим клиентом или нет.

У меня эта проблема уже несколько недель, и я не могу ее прибить. Любое руководство будет принята с благодарностью!

Верстак: Xcode 6.3 и Swift 1.2.

ответ

0

Решила собственную утечку памяти! С помощью этого ответа здесь: [UIDocument never calling dealloc

Я обращался к UIDocuments и никогда не закрывал их. Вот почему ARC не очищал мои неиспользуемые UIDocuments. Ссылка выше имеет объектную C версии, но для людей, использующих Swift, попробуйте эти строки, чтобы закрыть свои документы после их использования:

document?.updateChangeCount(UIDocumentChangeKind.Done) 
document?.closeWithCompletionHandler(nil) 

Уф! Рад, что беспорядок закончился. Надеюсь, это поможет кому-то!

Смежные вопросы