Coder1000 Coder1000 - 7 months ago 12
Swift Question

Description Label doesn't appear in my TableViewController cells

IMPORTANT: If you don't understand something or if something is unclear, please post in the comments and I will gladly answer/ edit my question:)

As an exercise to practice Objective-C, I am converting Swift code to Objective-C.
After 1.5k lines converted, I find myself blocked since days on one last issue.
In a few cells of my TableViewController, the description labels don't appear at all. I checked my code and it seems the strings that are passed are actually empty or nil.

After much frustration, searches, and hours of debugging trial and error, here is my question.

THE CODE:

ViewController.m

...

NSDate const *now = [[NSDate alloc] init];
NSDate *date = [[NSDate alloc] init];

self.sections = [[NSMutableArray<NSString *> alloc]init];
self.items = [[NSMutableArray<NSMutableArray<TableItem *> *> alloc]init];
self.sectionItems = [[NSMutableArray<TableItem *> alloc]init];


...

This is the cell data that doesn't load correctly (empty strings are passed to
theDescription
):

anItem = [[TableItem alloc ]initWithTitle: @"Custom: dd MMM yyyy HH:mm:ss" theDescription: [NSString stringWithFormat:@"%@", [now toString: [DateFormat CustomDateFormat:@"dd MMM yyyy HH:mm:ss"]]]];
[_sectionItems addObject: anItem];

//theDescription should be: @"25 April 2016 15:04:57" after this ^, but is actually nil or @""

anItem = [[TableItem alloc ]initWithTitle: @"ISO8601(Year)" theDescription: [NSString stringWithFormat:@"%@", [now toString: [DateFormat ISODateFormat: ISOFormatYear]]]];
[_sectionItems addObject: anItem];

//theDescription should be: @"2016" after this ^, but is actually nil or @""


I think I was able to pinpoint the issue:

How to convert this Swift syntax to Objective-C?

Swift syntax:

Extension.swift
toString() function

case .ISO8601(let isoFormat):
dateFormat = (isoFormat != nil) ? isoFormat!.rawValue : ISO8601Format.DateTimeMilliSec.rawValue
zone = NSTimeZone.localTimeZone()


What I tried:

Extension.m

else if([format.dateFormatType compare: ISO8601DateFormatType] == NSOrderedSame) {
NSString *isoFormat = ISO8601DateFormatType;
dateFormat = (isoFormat != nil) ? isoFormat : ISOFormatDateTimeMilliSec;
zone = [NSTimeZone localTimeZone];
}


More context:

Swift Syntax:

Extension.swift

public enum ISO8601Format: String {

case Year = "yyyy" // 1997
case YearMonth = "yyyy-MM" // 1997-07
case Date = "yyyy-MM-dd" // 1997-07-16
case DateTime = "yyyy-MM-dd'T'HH:mmZ" // 1997-07-16T19:20+01:00
case DateTimeSec = "yyyy-MM-dd'T'HH:mm:ssZ" // 1997-07-16T19:20:30+01:00
case DateTimeMilliSec = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" // 1997-07-16T19:20:30.45+01:00

init(dateString:String) {
switch dateString.characters.count {
case 4:
self = ISO8601Format(rawValue: ISO8601Format.Year.rawValue)!
case 7:
self = ISO8601Format(rawValue: ISO8601Format.YearMonth.rawValue)!
case 10:
self = ISO8601Format(rawValue: ISO8601Format.Date.rawValue)!
case 22:
self = ISO8601Format(rawValue: ISO8601Format.DateTime.rawValue)!
case 25:
self = ISO8601Format(rawValue: ISO8601Format.DateTimeSec.rawValue)!
default:// 28:
self = ISO8601Format(rawValue: ISO8601Format.DateTimeMilliSec.rawValue)!
}
}
}

public enum DateFormat {
case ISO8601(ISO8601Format?), DotNet, RSS, AltRSS, Custom(String)
}


What I tried:

DateFormat.m

#import "DateFormat.h"

@implementation DateFormat

NSString * const ISO8601DateFormatType = @"ISO8601";
NSString * const DotNetDateFormatType = @"DotNet";
NSString * const RSSDateFormatType = @"RSS";
NSString * const AltRSSDateFormatType = @"AltRSS";
NSString * const CustomDateFormatType = @"Custom";

NSString * const ISOFormatYear = @"yyyy";
NSString * const ISOFormatYearMonth = @"yyyy-MM"; // 1997-07
NSString * const ISOFormatDate = @"yyyy-MM-dd"; // 1997-07-16
NSString * const ISOFormatDateTime = @"yyyy-MM-dd'T'HH:mmZ"; // 1997-07-16T19:20+01:00
NSString * const ISOFormatDateTimeSec = @"yyyy-MM-dd'T'HH:mm:ssZ"; // 1997-07-16T19:20:30+01:00
NSString * const ISOFormatDateTimeMilliSec = @"yyyy-MM-dd'T'HH:mm:ss.SSSZ"; // 1997-07-16T19:20:30.45+01:00

- (instancetype) initWithType: (NSString *) formatType details: (NSString *) details {

if(self = [super init]) {
_dateFormatType = formatType;
_formatDetails = details;
}

return self;
}

+ (instancetype) ISODateFormat: (NSString *) isoFormat
{
return [[DateFormat alloc] initWithType: ISO8601DateFormatType details: isoFormat];
}

+ (instancetype) DotNetDateFormat
{
return [[DateFormat alloc] initWithType: DotNetDateFormatType details: nil];
}

+ (instancetype) RSSDateFormat
{
return [[DateFormat alloc] initWithType: RSSDateFormatType details: nil];
}

+ (instancetype) AltRSSDateFormat
{
return [[DateFormat alloc] initWithType: AltRSSDateFormatType details: nil];
}

+ (instancetype) CustomDateFormat: (NSString *) formatString
{
return [[DateFormat alloc] initWithType: CustomDateFormatType details: formatString];
}

@end


I suspect some kind of syntax error on my part. It's either the toString() function or the way I converted the original swift enums:

How would you convert those 2 Swift enums to Objective-C?

TL;DR: For me the error that generates empty strings is either in my Dateformat Class or in the toString() function. I am sure it's actually something very simple (as always, GRRR), but I can't seem to find it!

JAL JAL
Answer

The problem is in this line:

NSDateFormatter *formatter = [NSDate formatter : dateFormat : [NSTimeZone localTimeZone] : [NSLocale currentLocale]];

dateFormat is @"Custom", as it was set here:

else if([format.dateFormatType compare: CustomDateFormatType] == NSOrderedSame) {
    NSString *string = CustomDateFormatType;
    dateFormat = string;
}

This is passed into your NSDateFormatter constructor here:

formatter.dateFormat = format;

@"Custom" is not a valid date format string. Instead, pass in format.formatDetails:

NSDateFormatter *formatter = [NSDate formatter : format.formatDetails : [NSTimeZone localTimeZone] : [NSLocale currentLocale]];

I should note that not using named arguments in Objective-C makes your code much harder to read.

Comments