2014-10-22 5 views
8

मैं अपने कोड निम्न हस्ताक्षर के साथ एक अन्य परियोजना में काम कर रहे, एक कक्षा में था:NSStreamDelegate NSStreamEvent.HasSpaceAvailable प्राप्त नहीं:

class ViewController: UIViewController, NSStreamDelegate, UITextFieldDelegate { 

तो मैं अपने आप वर्ग के लिए कनेक्शन ले जाया गया, तो मैं संभवतः यह पुनः उपयोग कर सकते प्रत्येक कनेक्शन में:

class XMPPConnection: NSObject, NSStreamDelegate 

जब मैं ऐसा किया, मैं सभी viewDidLoad() कोड init() में चले गए। मैंने अलग-अलग फ़ंक्शन में init कोड डालने का प्रयास किया, और कक्षा को तुरंत चालू करने के बाद उस फ़ंक्शन को कॉल किया। उसने कुछ भी नहीं बदला।

मैं 2 परियोजनाओं, पुराने और नए के बीच स्विच कर सकता हूं, यह सुनिश्चित करने के लिए कि यह सर्वर की समस्या नहीं है, और यह पुष्टि करता है कि यह नहीं है।

आवेदन के प्रत्येक भाग के बाद, परिणाम अलग है। यह या तो HasSpaceAvailable पर कॉल नहीं करता है और बस वहां बैठता है, या (lldb) मेरी कक्षा class AppDelegate: UIResponder, UIApplicationDelegate, FBLoginViewDelegate में थ्रेड 1 पर फेंक दिया गया त्रुटि है। यह त्रुटि फेसबुक एकीकरण से संबंधित हो सकती है, लेकिन lldb के साथ देखने के लिए बहुत कुछ नहीं है। हालांकि, प्रत्येक परियोजना के साथ, प्रत्येक परियोजना के विपरीत HasSpaceAvailable कभी नहीं कहा जाता है।

यहां NSStreamDelegate का पूरा कोड है, इसलिए कोई भ्रम नहीं है। यह वर्ग एक्सएमपीपी प्रोटोकॉल का उपयोग कर कनेक्शन का एक काफी मानक तरीका है।

import UIKit 
import Foundation 


class XMPPConnection: NSObject, NSStreamDelegate { //NSObject 

    var input : NSInputStream? 
    var output: NSOutputStream? 

    //let XMLStream: String = "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' version='1.0' xmlns='jabber:client' to='mydomain.com' xml:lang='en' xmlns:xml='http://www.w3.org/XML/1998/namespace'>" 
    let XMLStream: String = "<stream:stream to='mydomain.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>" 
    var XMLAuth: String? 
    let XMLStreamEnd: String = "</stream:stream>" 
    let XMLResource: String = "<iq type='set' id='bind_1'><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><resource>OneSide</resource></bind></iq>" 
    let XMLSession: String = "<iq type='set' id='sess_1'><session xmlns='urn:ietf:params:xml:ns:xmpp-session'/></iq>" 
    let XMLStartTLS: String = "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"; 
    var messagesToBeSent:[String] = [] 
    var lastSentMessageID = 0 
    var lastReceivedMessageID = 0 


    init(facebookID: String) { 
     super.init() 
     let username = "[email protected]" //should hash device ID 
     let password = "123456" //hash it 
     var UTF8AuthStr = "\0\(username)\0\(password)".dataUsingEncoding(NSUTF8StringEncoding) 
     let Base64Str = UTF8AuthStr!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.fromRaw(0)!) 
     XMLAuth = "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>\(Base64Str)</auth>" 
     //println(XMLAuth) 

     self.connectToSocket("mydomain.com", port: 5222) 
     send(self.XMLStream) 
     //send(self.XMLStartTLS) 
     /*send(self.XMLAuth!) 
     send(self.XMLStream) 
     send(self.XMLResource) 
     send(self.XMLSession)*/ 
     //sendMessage("hi") 


    } 

    func connectToSocket(host: String, port: Int) { 

     NSStream.getStreamsToHostWithName(host, port: port, inputStream: &(self.input), outputStream: &(self.output)) 

     self.input!.delegate = self 
     self.output!.delegate = self 

     self.input!.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode) 
     self.output!.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode) 

     self.input!.open() 
     self.output!.open() 

     println("Connected") 


     //let bytesWritten = self.output!.write(UnsafePointer(data.bytes), maxLength: data.length) 

     //println(bytesWritten) 


    } 

    //The delegate receives this message when a given event has occurred on a given stream. 
    func stream(theStream: NSStream!, handleEvent streamEvent: NSStreamEvent) { 

     println("Message received") 

     switch streamEvent { 
     case NSStreamEvent.None: 
      println("NSStreamEvent.None") 
     case NSStreamEvent.OpenCompleted: 
      println("NSStreamEvent.OpenCompleted") 
     case NSStreamEvent.HasBytesAvailable: 
      println("NSStreamEvent.HasBytesAvailable") 
      if let inputStream = theStream as? NSInputStream { 
       //println("is NSInputStream") 
       if inputStream.hasBytesAvailable { 
        //println("hasBytesAvailable") 
        let bufferSize = 1024 
        var buffer = Array<UInt8>(count: bufferSize, repeatedValue: 0) 

        var bytesRead: Int = inputStream.read(&buffer, maxLength: bufferSize) 
        //println(bytesRead) 
        if bytesRead >= 0 { 
         lastReceivedMessageID++ 
         var output: String = NSString(bytes: &buffer, length: bytesRead, encoding: NSUTF8StringEncoding) 
         //println("output is") 
         println(output) 
        } else { 
         println("error") 
         // Handle error 
        } 
       } 
      } 
     case NSStreamEvent.HasSpaceAvailable: 
      println("NSStreamEvent.HasSpaceAvailable") 
      send(nil) //send next item 
      //send next message or 
      //what if there is no next message to send, and instead waiting user input? 
     case NSStreamEvent.ErrorOccurred: 
      println("NSStreamEvent.ErrorOccurred") 
     case NSStreamEvent.EndEncountered: 
      println("NSStreamEvent.EndEncountered") 
     default: 
      println("default") 
     } 
    } 

    func send(message:String?){ 
     if (self.output!.hasSpaceAvailable){ //stream ready for input 
      //println("true hasSpaceAvailable") 
      var data:NSData 
      var thisMessage:String 
      if message == nil{ // no message specified 
       if messagesToBeSent.count != 0{ //messages waiting to be sent 
        thisMessage = messagesToBeSent[0] 
        data = messagesToBeSent[0].dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! 
        messagesToBeSent.removeAtIndex(0) 
       } 
       else{ //no data to be sent 
        //no message specified and nothing to be sent 
        return 
       } 
      } 
      else{ 
       thisMessage = message! 
       data = message!.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! 
      } 

      //println("Sent the following") 
      wait() 
      let bytesWritten = self.output!.write(UnsafePointer(data.bytes), maxLength: data.length) 
      lastSentMessageID++ 
      //println(thisMessage) 
      //println("Message sent to server and response is") 
      //println(bytesWritten) //int count 
     } 
     else{ //steam busy 
      println("no space available in stream") 
      if message != nil{ 
       messagesToBeSent.append(message!) 
      } 
     } 
    } 

    func sendMessage(message:String, from:String, to:String){ 
     let xmlMessage = "<message to='\(to)@mydomain.com' from='\(from)@mydomain.com' type='chat' xml:lang='en'> <body>\(message)</body></message>" 
     send(xmlMessage) 
    } 


    func wait() { 
     while true { 
      //println("waiting") 
      if lastSentMessageID == lastReceivedMessageID { 
       break 
      } 

      NSRunLoop.currentRunLoop().runUntilDate(NSDate(timeIntervalSinceNow: 0.1)); 
      NSThread.sleepForTimeInterval(0.1) 
     } 
    } 

} 

तो मैं 2 चीजें देख सकता हूं जो इसके कारण हो सकते हैं। या तो इसे अपनी कक्षा में ले जाना, और इसका उदाहरण बनाना, या विरासत में परिवर्तन करना। पहले possiblity के बारे में सोच रही थी, मैं कोड के सूत्रण लाइनों में देख रहा हूँ: self.input!.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)

streamStatus.toRaw() की जाँच के बाद, यह 1 जो NSStreamStatusOpening है कहते हैं। मुझे यकीन नहीं है कि यह कभी बदलता है या नहीं।

उत्तर

3

मैं समस्या को पुन सकता है अगर XMPPConnection एक स्थानीय चर, उदा में संग्रहित है

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 

    let conn = XMPPConnection(facebookID: "...") 
    return true 
} 

इस विधि को वापस करने पर उदाहरण को हटा दिया जाता है। दूसरी तरफ धारा प्रतिनिधि अभी भी उदाहरण को इंगित करते हैं, इससे दुर्घटनाएं होती हैं। NSStream की delegate संपत्ति

unowned(unsafe) var delegate: NSStreamDelegate? 

जो "निर्दिष्ट" उर्फ ​​"unsafe_unretained" की स्विफ्ट बराबर है के रूप में घोषित किया गया है। इसलिए प्रतिनिधि को सेट करने से ऑब्जेक्ट को बरकरार नहीं रखा जाता है, और ऑब्जेक्ट को हटाने के लिए संपत्ति को nil (कमजोर संदर्भों के लिए) सेट नहीं करता है।

यदि उदाहरण संपत्ति में संग्रहीत है, उदा।

class AppDelegate: UIResponder, UIApplicationDelegate { 

    var window: UIWindow? 
    var conn : XMPPConnection! 

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 

     conn = XMPPConnection(facebookID: "...") 
     return true 
    } 

    // ... 
} 

तो आपका कोड मेरे परीक्षण में सही तरीके से काम करता है।

-1
  CFStreamCreatePairWithSocketToHost(nil, serverAddress, Server, &readStream, &writeStream) 

CFStreamCreatePairWithSocketToHost(nil, website!.host, Server, &readStream, &writeStream) 

    CFReadStreamSetProperty(readStream!.takeUnretainedValue(), kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue) 
    CFWriteStreamSetProperty(writeStream!.takeUnretainedValue(), kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue) 
      inputStream = readStream!.takeUnretainedValue(); 
      outputStream = writeStream!.takeUnretainedValue(); 
संबंधित मुद्दे