I am following Stanford's cs193P "Developing IOS 9 Apps with swift" course. I'm working on assignment-4 of the lecture. The app fetches the tweets, which include the word you search, from twitter.
I try to change the colour of words which start with special characters(#,# or http).
When I compile the app it succeeds to change colours and the app runs without problem. But then when I scroll down and my app tries to show new tweets it crashes giving the following error.
Terminating app due to uncaught exception 'NSRangeException', reason: 'NSMutableRLEArray objectAtIndex:effectiveRange:: Out of bounds'
I am using Xcode 7.3.1 with swift 2.2
I searched both on Stackoverflow and google and found the following similar questions
Question-1
Question-2
Question-3
Question-4
In the questions above problems were related to the length of the range or misusing the NSRange related to its length.
In my case I don't see any problem related to length. You can click to view my whole project in Github
public class Mention: NSObject
{
public var keyword: String // will include # or # or http prefix
public var nsrange: NSRange // index into an NS[Attributed]String made from the Tweet's text
public override var description: String { return "\(keyword) (\(nsrange.location), \(nsrange.location+nsrange.length-1))" }
init?(fromTwitterData data: NSDictionary?, inText text: NSString, withPrefix prefix: String)
{
guard
let indices = data?.valueForKeyPath(Tweet.TwitterKey.Entities.Indices) as? NSArray,
let start = (indices.firstObject as? NSNumber)?.integerValue where start >= 0,
let end = (indices.lastObject as? NSNumber)?.integerValue where end > start
else {
return nil
}
var prefixAloneOrPrefixedMention = prefix
if let mention = data?.valueForKeyPath(Tweet.TwitterKey.Entities.Text) as? String {
prefixAloneOrPrefixedMention = mention.prependPrefixIfAbsent(prefix)
}
let expectedRange = NSRange(location: start, length: end - start)
guard
let nsrange = text.rangeOfSubstringWithPrefix(prefixAloneOrPrefixedMention, expectedRange: expectedRange)
else {
return nil
}
self.keyword = text.substringWithRange(nsrange)
self.nsrange = nsrange
} }
As can be seen start is always bigger than end. That's why in expectedRange length(which is end-start) can never be minus.
And finally my code which causes the crash is below(The line starting with "tweetTextLabel?.attributedText" causes the crash)
class TweetTableViewCell: UITableViewCell
{
#IBOutlet weak var tweetScreenNameLabel: UILabel!
#IBOutlet weak var tweetTextLabel: UILabel!
#IBOutlet weak var tweetProfileImageView: UIImageView!
#IBOutlet weak var tweetCreatedLabel: UILabel!
var tweet: Twitter.Tweet? {
didSet {
updateUI()
}
}
var mentionsList = [Array<Mention>]()
private func updateUI()
{
// reset any existing tweet information
tweetTextLabel?.attributedText = nil
tweetScreenNameLabel?.text = nil
tweetProfileImageView?.image = nil
tweetCreatedLabel?.text = nil
// load new information from our tweet (if any)
if let tweet = self.tweet
{
tweetTextLabel?.text = tweet.text
if tweetTextLabel?.text != nil {
for _ in tweet.media {
tweetTextLabel.text! += " 📷"
}
}
mentionsList.append(tweet.hashtags)
mentionsList.append(tweet.urls)
mentionsList.append(tweet.userMentions)
var mentionColor = UIColor.clearColor()
for mentions in mentionsList {
switch mentions {
case _ where mentions == tweet.hashtags:
mentionColor = UIColor.blueColor()
case _ where mentions == tweet.urls:
mentionColor = UIColor.redColor()
case _ where mentions == tweet.userMentions:
mentionColor = UIColor.brownColor()
default: break
}
for mention in mentions {
(tweetTextLabel?.attributedText as? NSMutableAttributedString)?.addAttribute(
NSForegroundColorAttributeName, value: mentionColor, range: mention.nsrange) // Causes the crash
}
}
tweetScreenNameLabel?.text = "\(tweet.user)" // tweet.user.description
if let profileImageURL = tweet.user.profileImageURL {
if let imageData = NSData(contentsOfURL: profileImageURL) { // blocks main thread!
tweetProfileImageView?.image = UIImage(data: imageData)
}
}
let formatter = NSDateFormatter()
if NSDate().timeIntervalSinceDate(tweet.created) > 24*60*60 {
formatter.dateStyle = NSDateFormatterStyle.ShortStyle
} else {
formatter.timeStyle = NSDateFormatterStyle.ShortStyle
}
tweetCreatedLabel?.text = formatter.stringFromDate(tweet.created)
}
}
}
Please help me. I am already working on this issue for several days and cannot find where the mistake is. Maybe because of some special characters the number of characters in string are more. But I don't know how to figure it out.
Related
First, I initialize the variables to hold the stock data
var applePrice: String?
var googlePrice: String?
var twitterPrice: String?
var teslaPrice: String?
var samsungPrice: String?
var stockPrices = [String]()
I fetch current stock prices from YQL, and put those values into an array
func stockFetcher() {
Alamofire.request(stockUrl).responseJSON { (responseData) -> Void in
if((responseData.result.value) != nil) {
let json = JSON(responseData.result.value!)
if let applePrice = json["query"]["results"]["quote"][0]["Ask"].string {
print(applePrice)
self.applePrice = applePrice
self.tableView.reloadData()
}
if let googlePrice = json["query"]["results"]["quote"][1]["Ask"].string {
print(googlePrice)
self.googlePrice = googlePrice
self.tableView.reloadData()
}
if let twitterPrice = json["query"]["results"]["quote"][2]["Ask"].string {
print(twitterPrice)
self.twitterPrice = twitterPrice
self.tableView.reloadData()
}
if let teslaPrice = json["query"]["results"]["quote"][3]["Ask"].string {
print(teslaPrice)
self.teslaPrice = teslaPrice
self.tableView.reloadData()
}
if let samsungPrice = json["query"]["results"]["quote"][4]["Ask"].string {
print(samsungPrice)
self.samsungPrice = samsungPrice
self.tableView.reloadData()
}
let stockPrices = ["\(self.applePrice)", "\(self.googlePrice)", "\(self.twitterPrice)", "\(self.teslaPrice)", "\(self.samsungPrice)"]
self.stockPrices = stockPrices
print(json)
}
}
}
in cellForRowAt indexPath function I print to the label
if self.stockPrices.count > indexPath.row + 1 {
cell.detailTextLabel?.text = "Current Stock Price: \(self.stockPrices[indexPath.row])" ?? "Fetching stock prices..."
} else {
cell.detailTextLabel?.text = "No data found"
}
I'm running into the issue of printing Current Stock Price: Optional("stock price"), with the word optional. I gather that this is because I'm giving it an array of optional values, but I sort of have to since I actually don't know if there will be data coming from YQL, one of the 5 stocks might be nil while the others have data. From reading other similar questions I can see that the solution would be to unwrap the value with !, but I'm not so sure how to implement that solution when it's an array with data that might be nil, and not just an Int or something.
How can I safely unwrap here and get rid of the word Optional?
First off:
Any time you repeat the same block of code multiple times and only increase a value from 0 to some max, it is a code smell. You should think about a different way to handle it.
You should use an array to do this processing.
How about a set of enums for indexes:
enum companyIndexes: Int {
case apple
case google
case twitter
case tesla
//etc...
}
Now you can run through your array with a loop and install your values more cleanly:
var stockPrices = [String?]()
Alamofire.request(stockUrl).responseJSON { (responseData) -> Void in
if((responseData.result.value) != nil) {
let json = JSON(responseData.result.value!)
let pricesArray = json["query"]["results"]["quote"]
for aPriceEntry in pricesArray {
let priceString = aPriceEntry["ask"].string
stockPrices.append(priceString)
}
}
}
And to fetch a price from the array:
let applePrice = stockPrices[companyIndexes.apple.rawValue]
That will result in an optional.
You could use the nil coalescing operator (??) to replace a nil value with a string like "No price available.":
let applePrice = stockPrices[companyIndexes.apple.rawValue] ?? "No price available"
or as shown in the other answer:
if let applePrice = stockPrices[companyIndexes.apple.rawValue] {
//we got a valid price
} else
//We don't have a price for that entry
}
I'm writing this outside of Xcode (so there might be typos), but this kind of logic should work.
if self.stockPrices.count > indexPath.row + 1 {
var txt = "Fetching stock prices..."
if let price = self.stockPrices[indexPath.row] {
txt = price
}
cell.detailTextLabel?.text = txt
} else {
cell.detailTextLabel?.text = "No data found"
}
For safe unwrap use that code:
if let currentStockPrice = self.stockPrices[indexPath.row]
{
// currentStockPrice available there
}
// currentStockPrice unavailable
If you need to unwrap multiple variables in one if after another it may lead to unreadable code. In such case use this pattern
guard let currentStockPrice = self.stockPrices[indexPath.row]
else
{
// currentStockPrice is unavailable there
// must escape via return, continue, break etc.
}
// currentStockPrice is available
when i ran this code, update labels (aLabel and bLabel) perfectly. the viewDidLoad run perfectly, but when i press freshButtonPressed the Xcode show error. the unexpectedly found nil while unwrapping an Optional value appeared on self.aLabel.text = var1 (comment shows the error place).
the code of viewDidLoad is same as freshButtonPressed. I couldn't figure out the problem.
I appriciated.
import UIKit
class segView1ViewController: UIViewController {
#IBOutlet weak var dollarUSALabel: UILabel!
#IBOutlet weak var euroLabel: UILabel!
func refreshingData1() {
println("refreshing ...")
var dollar2 = ""
var euro2 = ""
var arzUrl = NSURL(string: "http://www.arzlive.com")
if arzUrl != nil {
let task2 = NSURLSession.sharedSession().dataTaskWithURL(arzUrl!, completionHandler: { (data, response, error) -> Void in
var urlError = false
if error == nil {
//main code
//parsing url contents
var arzUrlContent = NSString(data: data, encoding: NSUTF8StringEncoding) as NSString!
//println(arzUrlContent)
/////////// Dollar
var dollarTempArray = arzUrlContent.componentsSeparatedByString("s3_40 price\">")
//println(dollarTempArray[1])
if dollarTempArray.count > 0 {
var dollarTempArray2 = dollarTempArray[1].componentsSeparatedByString("<td")
dollar2 = dollarTempArray2[0] as! String
//println(dollar)
} else {
urlError = true
}
////////// Euro
var euroTempArray = arzUrlContent.componentsSeparatedByString("s3_41 price\">")
//println(euroTempArray[1])
if euroTempArray.count > 0 {
var euroTempArray2 = euroTempArray[1].componentsSeparatedByString("<td")
euro2 = euroTempArray2[0] as! String
//println(euro)
} else {
urlError = true
}
} else {
//error handling for web task error
urlError = true
}
dispatch_async(dispatch_get_main_queue()) {
//checking error
if urlError == true {
//run error func
self.showError()
} else {
//update labels here
self.dollarUSALabel.text = dollar2
self.euroLabel.text = euro2
}
}
})
//resume task
task2.resume()
} else {
// error handler
showError()
}
////////end of func
}
func showError() {
//some error handling code...
}
override func viewDidLoad() {
super.viewDidLoad()
self.dollarUSALabel.text = "0"
self.euroLabel.text = "0"
var dollar = ""
var euro = ""
// arzlive url
var arzUrl = NSURL(string: "http://www.arzlive.com")
if arzUrl != nil {
let task1 = NSURLSession.sharedSession().dataTaskWithURL(arzUrl!, completionHandler: { (data, response, error) -> Void in
var urlError = false
if error == nil {
//main code
//parsing url contents
var arzUrlContent = NSString(data: data, encoding: NSUTF8StringEncoding) as NSString!
//println(arzUrlContent)
/////////// Dollar
var dollarTempArray = arzUrlContent.componentsSeparatedByString("s3_40 price\">")
//println(dollarTempArray[1])
if dollarTempArray.count > 0 {
var dollarTempArray2 = dollarTempArray[1].componentsSeparatedByString("<td")
dollar = dollarTempArray2[0] as! String
//println(dollar)
} else {
urlError = true
}
////////// Euro
var euroTempArray = arzUrlContent.componentsSeparatedByString("s3_41 price\">")
//println(euroTempArray[1])
if euroTempArray.count > 0 {
var euroTempArray2 = euroTempArray[1].componentsSeparatedByString("<td")
euro = euroTempArray2[0] as! String
//println(euro)
} else {
urlError = true
}
} else {
//error handling for web task error
urlError = true
}
dispatch_async(dispatch_get_main_queue()) {
//checking error
if urlError == true {
//run error func
self.showError()
} else {
//update labels here
self.dollarUSALabel.text = dollar
self.euroLabel.text = euro
}
}
})
//resume task
task1.resume()
} else {
// error handler
showError()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Ran the project. Could not reproduce the problem. Two issues though:
-- Your code doesn't compile because the dollarTempArrays are not declared anywhere. Please submit something that compiles.
-- You have an array indexing logic error, because you're checking if the count is at least one, but then indexing the second element (at index 1, not index 0, where you should be checking)
Please submit a version that compiles and ideally a website that provides the data. Although, I hardcoded values in place of var1 and var2 and the UI updated no problem.
Since your crash is out of sync with your posted code, I'll bet other things are out of sync in your environment. Quit Xcode & iOS Simulator, get back in, do a clean build, verify your Outlets, and post what you really have now.
Calling your variables var12345 is both sadistic and masochistic, so start abandoning that practice now, even in test code. It's much harder to help with that kind of blatant violations of good practice.
** LATER THAT DAY **
I put it through the professional programmer descrambler and the following resulted. What you're trying to do is not complicated and need not be long. Please observe style, abstraction, efficiency, as well as bug fixes. I just tested this in Xcode 6.4 / Swift 1.2 / iOS simulator on iPhone 6.
import UIKit
class CurrencyViewController: UIViewController {
#IBOutlet weak var dollarUSALabel: UILabel!
#IBOutlet weak var euroLabel: UILabel!
let dataURL = "http://www.arzlive.com"
func refreshData() {
println("refreshing ...")
if let arzUrl = NSURL(string: dataURL) {
let task2 = NSURLSession.sharedSession().dataTaskWithURL(arzUrl)
{ [unowned self]
(data, response, error) -> Void in
if let d = data, arzUrlContent = NSString(data: d, encoding: NSUTF8StringEncoding) {
var dollar: String?
var euro: String?
let dollarTempArray = arzUrlContent.componentsSeparatedByString("s3_40 price\">")
if dollarTempArray.count >= 2 {
let dollarTempArray2 = dollarTempArray[1].componentsSeparatedByString("<td")
dollar = dollarTempArray2[0] as? String
}
let euroTempArray = arzUrlContent.componentsSeparatedByString("s3_41 price\">")
if euroTempArray.count >= 2 {
var euroTempArray2 = euroTempArray[1].componentsSeparatedByString("<td")
euro = euroTempArray2[0] as? String
}
}
dispatch_async(dispatch_get_main_queue()) {
self.dollarUSALabel.text = dollar ?? "Could not get dollars!"
self.euroLabel.text = euro ?? "Could not get euros!"
}
}
task2.resume() // START task ('resume' is misleading)
}
else {
showError("Could not access \(dataURL)")
}
} /* end of refreshData */
/* TODO for you: Use UIAlertController to inform the user */
func showError(message: String) {
println(message)
}
override func viewDidLoad() {
super.viewDidLoad()
refreshData()
}
}
I am trying to change my UIWebView Url depending on the variables I get from my Parse.com database.
First, I split the three worded String into three parts then I place the parts into the url.
However, I am getting an error! It is very strange:
Here is the code incase you are unable to see it:
import UIKit
import Parse
import ParseUI
class myBookingsItemTableViewController: UITableViewController {
var object: PFObject!
#IBOutlet weak var typeOfBookingLabel: UILabel!
#IBOutlet weak var typeOfBookingQRCode: UIWebView!
var ticketId = String()
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
if (self.object != nil) {
self.typeOfBookingLabel?.text = self.object["booking"] as? String
var ticketID = self.object["ticketId"] as? String
self.ticketId = ticketID!
var ticketIdArr = split(ticketId) {$0 == " "}
var first: String = ticketIdArr[0]
var second: String? = ticketIdArr.count > 1 ? ticketIdArr[1] : nil
var third: String? = ticketIdArr.count > 2 ? ticketIdArr[2] : nil
let url = NSURL (string: "http://chart.apis.google.com/chart?chl=\(first)+\(second)+\(third)&chs=200x200&cht=qr&chld=H%7C0")
let requestObj = NSURLRequest(URL: url!)
typeOfBookingQRCode.loadRequest(requestObj)
} else {
self.object = PFObject(className: "Bookings")
}
}
}
You have to make sure that your first, second and third do not contain any whitespaces - otherwise you will not be able to create a URL from it - it will return nil and your unwrapping fails.
You can do that using
first = first.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet())!
Additionally I would recommend against using nil in your situation but rather either exclude the second and third argument if they would be nil or replace the nil with an actual value - that way you can change their type to String and do not have to worry about the optionals any more.
The following code snippet escapes all three values and always generates an URL:
func urlEncode(par:String!) -> String! {
return par.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet())!
}
var first: String = urlEncode(ticketIdArr[0])
var second: String = ticketIdArr.count > 1 ? urlEncode(ticketIdArr[1]) : "nil"
var third: String = ticketIdArr.count > 2 ? urlEncode(ticketIdArr[2]) : "nil"
I have buttons that when pressed, will call/message a number from an array. i.e. button1 will call the number at index 0 of the array, button2 at index 1, etc.. For some reason whenever the number from the array contains a format other than xxx-xxx-xxx it crashes (i.e. (xxx) xxx-xxx). And yet, the log gives me the following error even though the array isn't nil:
Anyone know why this is happening?
Here is the code for everything:
import UIKit
import AddressBook
var contactInfo: [String] = []
[...]
override func viewDidLoad() {
super.viewDidLoad()
//this is the function that grabs the array from an app group
setUpCallMessageButtons()
[...]
callButton1.addTarget(self, action: "call:", forControlEvents: UIControlEvents.TouchUpInside)
}
func call(sender:UIButton!)
{
if (sender == callButton1) {
println("\(contactInfo)")
var url:NSURL? = NSURL(string: "tel:\(contactInfo[0])")
self.extensionContext?.openURL(url!, completionHandler:{(success: Bool) -> Void in
})
}
}
func setUpCallMessageButtons(){
let appGroupID = "**redacted**"
let defaults = NSUserDefaults(suiteName: appGroupID)
contactInfo = (defaults!.objectForKey("contactInfo") as! [String])
println("\(contactInfo)")
//This is gives the log down below. As you can see, none are nil.
}
Buttons 1,2 and 5 work while 3 and 4 always crash.
My guess is that if the phone number isn't formatted correctly, the call to convert it to an NSURL is failing and returning nil.
You probably need to wrap your call to openURL in an optional binding ("if let") block:
var url:NSURL? = NSURL(string: "tel:\(contactInfo[0])")
if let url = url
{
self.extensionContext?.openURL(url!,
completionHandler:
{
(success: Bool) -> Void in
}
}
else
{
println("Phone number \(contactInfo[0]) is not in a valid format")
}
You might want to strip away parenthesis from your phone number before trying to create your URL. A simple way would be to use the NSString method stringByReplacingOccurrencesOfString:withString:.
Here's a little storyboard - which shows you where the nil is coming from
Unexpectedly found nil means there is a variable which is expected to be non-nil but at run time was nil
This is the line of code that is causing the issue
self.extensionContext?.openURL(url!, completionHandler:{(success: Bool)
It expects url to be non-nil (i.e. the !) but it is definitely nil (see image)
If this data comes from the user or from the internet, you might want a method to strip away all non-numeric characters. Something like this (from a working playground I just banged out) :
import UIKit
func digitsOnly(#fromString: String) -> String
{
var workString = NSMutableString(string: fromString)
let digitsSet = NSCharacterSet.decimalDigitCharacterSet()
var index: Int
for index = count(fromString)-1; index>=0; index--
{
if !digitsSet.characterIsMember(workString.characterAtIndex(index))
{
workString.deleteCharactersInRange(NSRange(location:index, length:1))
}
}
return workString as String
}
let testString = "(555) 111-2222"
let result = digitsOnly(fromString:testString)
println("digitsOnly(\"\(testString)\") = \"\(result)\" ")
This displays:
digitsOnly("(555) 111-2222") = "5551112222"
Edit:
Or alternately a more Swift-like version of the same function:
func digitsOnly(#fromString: String) -> String
{
var result = String()
let digitsSet = NSCharacterSet.decimalDigitCharacterSet()
for char in fromString
{
if digitsSet.characterIsMember(char as unichar)
result += char
}
}
EDIT #2:
You can increase the set of characters that is left in place by changing the character set you use. Replace the line
let digitsSet = NSCharacterSet.decimalDigitCharacterSet()
With
let digitsSet = NSCharacterSet(charactersInString: "0123456789+-")
To preserve "+" signs and dashes. (Edit the string to include the characters you need.)
I have a UITableView with its contents managed by a NSFetchedResultsController fetching CoreData. I have two types of table view cells, one with an image and one without an image. The images are handled by UIDocument and are kept in the iCloud ubiquitous documents container and are referenced by client name.
As the cells are generated and reused when there are many user generated images on the screen, the memory usage of my program creeps higher and higher. Around 110 mb, I get a low memory warning.
I suspect my prepareForReuse() method in my tableView cell isn't doing its job correctly.
Here's what my UITableViewCell looks like now:
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")
}
}
}
If you're not familiar with iCloud and UIDocument, you might be wondering why I'm querying the metadata to get at these images/documents. If you know of a reliable way of fetching these images/documents in the ubiquitous container, I'm all ears. It causes this pop in effect during the scrolling of the table view cells.
And here's my function that populates the cells:
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!
}
I originally was going to use the attribute imageurl to store the name and url of the client profile image, but since the ubiquitous container url is unique for every device, I now only use it to detect if there is an image with this client or not.
I've been having this issue for weeks now and cannot seem to nail it down. Any guidance would be greatly appreciated!
Workbench: Xcode 6.3 and Swift 1.2.
Solved my own memory leak! With the help of this answer here: [UIDocument never calling dealloc
I was querying UIDocuments and never closing them. That's why the ARC wasn't cleaning up my unused UIDocuments. The link above has the Object C version, but for folks using Swift, try these lines to close your documents after using them:
document?.updateChangeCount(UIDocumentChangeKind.Done)
document?.closeWithCompletionHandler(nil)
Whew! Glad that mess was over. Hope this helps someone!