2016-03-27 2 views
-1

У меня есть контроллер чата с WKInterfaceTable из консервированных сообщений, и каждая строка таблицы - это другой тип контроллера строк, который поставляется с WKInterfaceTable в WatchKit.Словарь преобразования в Swift - «Тип выражения неоднозначен без дополнительного контекста»

Каждый rowController ссылается на MessageSource и MessageType, которые определены в перечислении.

Объявление моего перечисления выглядит хорошо, но синтаксис реализации соответствующего словаря нуждается в некоторой помощи.

Другая проблема, связанная с теми же блоками, - это преобразование Swift моих свойств. Я не уверен, правильно ли я объявил их, поэтому они могут влиять на те же блоки.

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

Obj-C

controller.m

typedef enum { 
MessageSourceIncoming = 1, 
MessageSourceOutgoing = 2 
} MessageSource; 

typedef enum { 
MessageTypeText = 1, 
MessageTypeVoice = 2, 
MessageTypeImage = 3 
} MessageType; 



@interface ChatController() <WCSessionDelegate> 
@property (strong, nonatomic) NSString *shouldSendVoice; 
@end 

@implementation ChatController { 
NSDictionary *_chat; 
NSMutableArray *_messages; 
//AVAudioPlayer *_player; 
} 

- (void)dealloc { 
_chat = nil; 
_messages = nil; 
//_player.delegate = nil; 
//_player = nil; 
} 

- (void)awakeWithContext:(id)context { 
_chat = context; 
[self setupTable]; 
} 

- (void)setupTable { 
_messages = [NSMutableArray array]; 
for (int i = 0; i < rand()%20; i++) { 
    [_messages addObject:@{@"msg":@[@"Hi", @"OK", @"Nice to meet you", @"Fine"][rand()%4], @"source":@(rand()%2), @"type":@(rand()%3)}]; 
} 

// clear the table rows 
[_table removeRowsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, _table.numberOfRows)]]; 
for (int i = 0; i < _messages.count; i++) { 
    NSDictionary *messageDic = _messages[i]; 
    [self insertRowForMessage:messageDic]; 
} 
} 

- (void)willActivate { 
[_table scrollToRowAtIndex:_table.numberOfRows - 1]; 
if (_shouldSendVoice) { 
    NSDictionary *messageDic = @{@"source":@(MessageSourceOutgoing), @"type":@(MessageTypeVoice), @"path":_shouldSendVoice}; 
    [_messages addObject:messageDic]; 
    [self insertRowForMessage:messageDic]; 
    _shouldSendVoice = nil; 
} 
} 

Swift попытка

enum MessageSource: Int { 
case MessageSourceIncoming = 1 
case MessageSourceOutgoing = 2 
} 

enum MessageType: Int { 
case MessageTypeText = 1 
case MessageTypeVoice = 2 
case MessageTypeImage = 3 
} 

class ChatController: WKInterfaceController, WCSessionDelegate { 

@IBOutlet var table: WKInterfaceTable! 

var chat = NSDictionary() 
var messages = NSMutableArray() 
var shouldSendVoice = NSString() 

override func awakeWithContext(context: AnyObject?) { 
    super.awakeWithContext(context) 

    chat = context as! NSDictionary 
    setupTable() 

} 

override func willActivate() { 
    super.willActivate() 

    self.table.scrollToRowAtIndex(table.numberOfRows - 1) 

    // Type 'Int' does not conform to protocol 'SequenceType' 
    if (shouldSendVoice) { 

     // Type of expression is ambiguous without more context 
     var messageDic = ["source" : MessageSource.MessageSourceOutgoing, "type" : MessageType.MessageTypeVoice, "path" : shouldSendVoice] 
     messages.addObject(messageDic) 
     self.insertRowForMessage(messageDic) 
     shouldSendVoice = String() 
    } 
} 

func setupTable() { 

    self.messages = NSMutableArray()     
    for (var i : Int32 = 0; i < rand()%20; i += 1) { 
     messages.addObject("msg" : ["Hi", "OK", "Nice to meet you", "Fine"][rand()%4], "source":(rand()%2), "type" : (rand()%3)) 
    } 
    self.table.removeRowsAtIndexes(NSIndexSet(indexesInRange:NSMakeRange(0, table.numberOfRows))) 

    for i in messages.count { 
     var messageDic = messages[i] 
     self.insertRowForMessage(messageDic) 
    } 
} 
+0

Вы должны уменьшить это в [Minimal, Complete и проверяемый пример] (HTTP: // StackOverflow .com/помощь/mcve). Для такой простой ошибки существует слишком много кода. И, скорее всего, простое упражнение по созданию [MCVE] (http://stackoverflow.com/help/mcve) поможет вам самостоятельно ответить. И если нет, у вас будет гораздо лучшая форма того же вопроса, чтобы публиковать здесь. – nhgrif

+1

Прекратить использование словарей для временных данных. Почему 'messageDic'? Почему бы вам просто не объявить 'struct Message'? Зачем использовать 'NSArray' в Swift? Просто создайте массив Swift с определенным типом, например. 'var messages: [Message] = []'. У вас есть несколько проблем, но все они вызваны плохим стилем программирования и игнорированием типов. У вас, вероятно, также есть множество предупреждений. – Sulthan

+0

Если вы получаете какую-либо «неоднозначную» ошибку, вам нужно предоставить компилятору более конкретную информацию о типе в вашем случае соответствующей аннотацией.Но в основном я согласен с @Sulthan: используйте собственные типы и потрясающие объектно-ориентированные навыки и Swift – vadian

ответ

1

Давайте разбить его:

enum MessageSource: Int { 
    case MessageSourceIncoming = 1 
    case MessageSourceOutgoing = 2 
} 

enum MessageType: Int { 
    case MessageTypeText = 1 
    case MessageTypeVoice = 2 
    case MessageTypeImage = 3 
} 

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

enum MessageType: Int { 
    case MessageTypeText = 1 
    case MessageTypeVoice 
    case MessageTypeImage 
} 

будет работать нормально, а значения будут одинаковыми.

var chat = NSDictionary() 
var messages = NSMutableArray() 
var shouldSendVoice = NSString() 

chat должен вероятно быть Swift словарь, но мы не имеем достаточно информации, чтобы установить тип, поэтому я его пропустить. shouldSendVoice выглядит как boolean, почему мы должны назначать ему NSString? Я не уверен, как вы используете этот, поэтому я не буду переименовывать его, но давайте сделаем из него необязательную строку. messages должен быть массивом Swift. Давайте создадим тип для Message:

struct Message { 
    let message: String? 
    let source: MessageSource 
    let type: MessageType 
    let path: String? 
} 

var chat = NSDictionary() // let's ignore this 
var messages: [Message] = [] // empty swift array of messages 
var shouldSendVoice: String? = nil // optional String 

Теперь, давайте просто переписать все остальное:

override func willActivate() { 
    super.willActivate() 

    self.table.scrollToRowAtIndex(table.numberOfRows - 1) 

    // in Obj-C this was checking for nil!, we have to check explicitly in Swift 
    if let shouldSendVoice = self.shouldSendVoice { 
     // let's not use Dictionaries for custom objects 
     let message = Message(message: nil, source: .MessageSourceIncoming, type: .MessageTypeVoice, path: shouldSendVoice) 
     self.messages.append(message) 

     self.insertRowForMessage(message) 
     // I think you don't want new String here, just `nil` 
     shouldSendVoice = nil 
    } 
} 

func setupTable() { 
    // let's use a saner way to generate randoms 
    let numMessages = Int(arc4random_uniform(20)) 

    self.messages = (0..<numMessages).map { _ in 
     let message = // randomize the message 
     let source = // randomize source 
     let type = // randomize type 

     return Message(message: message, source: source, type: type, path: nil) 
    } 

    // let's split multiple operations into separate lines to make code more readable 
    let indicesToRemove = NSIndexSet(indexesInRange:NSMakeRange(0, table.numberOfRows)) 
    self.table.removeRowsAtIndexes(indicesToRemove) 

    // let's use for-in without using an index 
    for message in messages { 
     self.insertRowForMessage(message) 
    } 
} 
+0

Большое спасибо. Я очень ценю это. Я был настолько сосредоточен на изучении синтаксиса Obj-C и Swift, поэтому иногда забываю теорию. Я использовал NSObjects для переменных только временно, так как они все еще работают, и это помогает мне визуально. Иногда я предполагаю, что должен использовать то, что написал автор, потому что он старший разработчик. Я знаю, как закодировать структуру курса, но я не думал с точки зрения ООП. Несмотря на то, что мой код был не очень красивым, я попытался это сделать. Я смотрел на свой код в течение 2 дней, задаваясь вопросом, где я должен начать рефакторинг. Сначала ты казался сердитым. Так что спасибо за возвращение. – TokyoToo

+0

О кстати, в исходном коде 'shouldSendVoice' был NSString. И да, в Swift Xcode говорилось, что это, возможно, Bool, потому что он использовался в выражении if, поэтому я не уверен, как эта логика работает. Также изначально 'chat' является NSDictionary. Вы сказали, что я должен использовать словарь Swift. Быстрые словари могут содержать больше типов, так что не лучше ли использовать словарь Swift в Swift, а не NSDictionary? Мой вопрос в том, почему кто-то будет хранить NSDictionary вместо словаря Swift? Какая польза от NSDictionary, используемого в проекте Swift? – TokyoToo

+0

@TokyoToo Пожалуйста, не принимайте пример из исходного кода, это не хороший код :) 'if (shouldSendVoice) {' в Obj-C является коротким для 'if (shouldSendVoice! = Nil) {'. 'NSDictionary' вообще не требуется в Swift, даже если вы взаимодействуете с API-интерфейсами Obj-C,' NSDictionary' обычно преобразуется в '[String: AnyObject]'. В Swift мы всегда хотим знать, какие типы хранит массив/словарь, поэтому мы не используем 'NSDictionary', потому что он не может выражать типы. – Sulthan

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