Home Php C# Sql C C++ Javascript Python Java Go Android Git Linux Asp.net Django .net Node.js Ios Xcode Cocoa Iphone Mysql Tomcat Mongodb Bash Objective-c Scala Visual-studio Apache Elasticsearch Jar Eclipse Jquery Ruby-on-rails Ruby Rubygems Android-studio Spring Lua Sqlite Emacs Ubuntu Perl Docker Swift Amazon-web-services Svn Html Ajax Xml Java-ee Maven Intellij-idea Rvm Macos Unix Css Ipad Postgresql Css3 Json Windows-server Vue.js Typescript Oracle Hibernate Internet-explorer Github Tensorflow Laravel Symfony Redis Html5 Google-app-engine Nginx Firefox Sqlalchemy Lucene Erlang Flask Vim Solr Webview Facebook Zend-framework Virtualenv Nosql Ide Twitter Safari Flutter Bundle Phonegap Centos Sphinx Actionscript Tornado Register | Login | Edit Tags | New Questions | 繁体 | 简体


10 questions online user: 39

109
votes
answers
34 views
+10

When should I release objects in -(void)viewDidUnload rather than in -dealloc?

What is the -(void)viewDidUnload is good for?

Could I not just relase everything in -dealloc? If the view did unload, wouldn't -dealloc be called anyway?

up vote 51 down vote accepted favorite
沙发
+510
+50

除了已經指出的內容之外,我還想詳細說明 -viewDidUnload 背後的邏輯。

實現它的最重要原因之一是 UIViewController 子類通常還包含對視圖層次結構中各種子視圖的擁有引用。這些屬性可以在從nib加載時通過 IBOutlets 設置,或者在 -loadView 中以編程方式設置。

子視圖的附加所有權 UIViewController 意味著即使從視圖層次結構中刪除其視圖並釋放以節省內存(視圖也通過該視圖釋放子視圖),它們實際上也不會被釋放,因為< 代碼> UIViewController 本身仍然包含它們對這些對象的突出保留引用。釋放 UIViewController 這些對象的其他所有權可確保它們被釋放以釋放內存。

此處釋放的對象通常在時重新創建並再次設置UIViewController 視圖是重新加載,來自Nib或通過 -loadView 的實現。

還要注意 UIViewController view 屬性為 nil 它本身仍然包含它們對這些對象的突出保留引用。釋放 UIViewController 這些對象的其他所有權可確保它們被釋放以釋放內存。

此處釋放的對象通常在時重新創建並再次設置UIViewController 視圖是重新加載,來自Nib或通過 -loadView 的實現。

還要注意 UIViewController view 屬性為 nil 它本身仍然包含它們對這些對象的突出保留引用。釋放 UIViewController 這些對象的其他所有權可確保它們被釋放以釋放內存。

此處釋放的對象通常在時重新創建並再次設置UIViewController 視圖是重新加載,來自Nib或通過 -loadView 的實現。

還要注意 UIViewController view 屬性為 nil

你應該閱讀developer.apple.com/library/ios/#featuredarticles/...來了解視圖/視圖控制器的生命週期 - 保羅索爾特2010年12月20日15:37

+210

文檔說明

在低內存條件下調用它時視圖控制器需要釋放其視圖以及與該視圖關聯的任何對像以釋放記憶。

在同樣的情況下, dealloc 調用。此方法僅適用於OS3及更高版本。處理iPhone OS 2.x中的相同情況真是太痛苦了!

2015年7月更新:應該注意 viewDidUnload 在iOS 6中被棄用,因為“在低內存條件下不再清除視圖,因此永遠不會調用此方法。” 因此,現代建議不要擔心它並使用 dealloc

同樣來自文檔:“您應該只對以後可以輕鬆重新創建的對象執行此操作,無論是在viewDidLoad方法中還是在應用程序的其他部分中。您不應使用此方法來釋放用戶數據或任何其他不可能的信息。容易重建“。這也是我自己的問題,謝謝! - leolobato 09年7月21日在12:52

如果視圖當前可見怎麼辦?因內存警告低而放棄它不是很糟糕嗎?;)那麼應用程序只是空白。由於內存不足,我沒有得到釋放視圖的意義。如果我沒有看到視圖,我總是釋放整個控制器。Althogh我有一個根視圖控制器,它保持完好無損並管理它的子視圖控制器的所有加載/卸載... - 謝謝2009年7月21日在18:37

不,如果您只是將一個視圖換成另一個視圖,則不會使用此方法。想想你有一個UINavigationController的“堆棧”視圖的情況。只有一個視圖可見,如果您有內存警告,則可以釋放所有不可見的視圖。 - Stephen Darlington於2009年7月21日20:20

你如何控制當前可見視圖上沒有調用viewDidUnload,謝謝你注意到了? - arielcamus 2010年3月1日18:15

不會在當前可見的視圖上調用viewDidUnload,僅在不可見的視圖上調用。 - progrmr 2010年5月16日17:35

+90

這是因為您通常會將 @property 設置為“(非原子,保留)”,因此為您創建的setter會釋放當前對象,然後保留參數,即

  self.property = nil;   

...做了類似的事情:

  [property release]; property = [nil retain];   

因此,您只用一石二鳥:內存管理(釋放現有對象)並將指針指定為nil(因為將任何消息發送到nil指針將返回nil)。 / p>

希望有所幫助。

+80

請記住 viewDidUnload 是視圖控制器中的方法,而不是視圖中的方法。視圖卸載時將調用視圖的 dealloc 方法,但可能無法調用視圖控制器的 dealloc 方法直到以後。

如果你得到一個內存不足的警告並且你的視圖沒有顯示,例如你將使用UIImagePickerController讓用戶拍照,你的視圖將被卸載並且需要在此之後重新加載。

那講得通。如果我總是丟棄整個視圖控制器會發生什麼?這就是我實際做的事情。在這種情況下,我不必處理-viewDidUnload,對嗎?我從來沒有遇到只會放下視圖的情況,因為無論如何它總是放下整個控制器。 - 感謝09年7月21日18:36

好吧,請記住,在您的視圖正在顯示的情況下,但是您有一個全屏視圖(如ImagePicker),即使您沒有計劃它,您的視圖也可能會被卸載。 - David Maymudes 09年7月21日20:31

+60

結論:

視圖控制器具有視圖屬性。通常,nib或一段代碼會向此視圖添加其他視圖。這通常發生在-viewDidLoad方法中,如下所示:

   - (void)viewDidLoad {[super viewDidLoad]; [self createManyViewsAndAddThemToSelfDotView]; 此外,一個nib文件可以創建一個按鈕並將其附加到視圖控制器的視圖。 

在iPhone OS 2.2上,當從-didReceiveMemoryWarning中調用-didReceiveMemoryWarning時,它可以在視圖控制器的視圖中顯示。

系統,你必鬚髮布一些東西來釋放內存。如果有意義,您可以釋放整個視圖控制器的視圖。或者只是耗費大量內存的內容。

   - (void)didReceiveMemoryWarning {[super didReceiveMemoryWarning]; //釋放視圖,如果它沒有超級視圖//釋放任何不重要的內容,例如緩存數據}   

現在,在新的OS 3.0中,有一個-viewDidUnload方法,當由於內存不足而卸載視圖時將從系統調用(請更正我:何時調用它?)

-viewDidUnload用於釋放所有擁有的對象視圖控制器本身和視圖。原因是:如果視圖控制器保存對視圖的子項的引用,即按鈕,則引用的子視圖將不會被釋放,因為它們的保留計數為> = 1.在-vi??ewDidUnload中釋放它們後,它們可以被釋放從記憶中恢復過來。 //釋放視圖,如果它沒有超級視圖//釋放任何不重要的內容,例如緩存數據}

現在,在新的OS 3.0中,有一個-viewDidUnload方法,當由於內存不足而卸載視圖時將從系統調用(請更正我:何時調用它?)

-viewDidUnload用於釋放所有擁有的對象視圖控制器本身和視圖。原因是:如果視圖控制器保存對視圖的子項的引用,即按鈕,則引用的子視圖將不會被釋放,因為它們的保留計數為> = 1.在-vi??ewDidUnload中釋放它們後,它們可以被釋放從記憶中恢復過來。 //釋放視圖,如果它沒有超級視圖//釋放任何不重要的內容,例如緩存數據}

現在,在新的OS 3.0中,有一個-viewDidUnload方法,當由於內存不足而卸載視圖時將從系統調用(請更正我:何時調用它?)

-viewDidUnload用於釋放所有擁有的對象視圖控制器本身和視圖。原因是:如果視圖控制器保存對視圖的子項的引用,即按鈕,則引用的子視圖將不會被釋放,因為它們的保留計數為> = 1.在-vi??ewDidUnload中釋放它們後,它們可以被釋放從記憶中恢復過來。 不是必需的,比如緩存的數據}

現在,在新的OS 3.0中,有一個-viewDidUnload方法,當視圖被卸載時,將從系統調用該方法,因為內存不足(請糾正我:什麼時候調用它?)

-viewDidUnload用於釋放視圖控制器本身和視圖所擁有的所有對象。原因是:如果視圖控制器保存對視圖的子項的引用,即按鈕,則引用的子視圖將不會被釋放,因為它們的保留計數為> = 1.在-vi??ewDidUnload中釋放它們後,它們可以被釋放從記憶中恢復過來。 不是必需的,比如緩存的數據}

現在,在新的OS 3.0中,有一個-viewDidUnload方法,當視圖被卸載時,將從系統調用該方法,因為內存不足(請糾正我:什麼時候調用它?)

-viewDidUnload用於釋放視圖控制器本身和視圖所擁有的所有對象。原因是:如果視圖控制器保存對視圖的子項的引用,即按鈕,則引用的子視圖將不會被釋放,因為它們的保留計數為> = 1.在-vi??ewDidUnload中釋放它們後,它們可以被釋放從記憶中恢復過來。 由於內存不足而導致視圖被卸載時將從系統中調用(請更正我:何時調用它?)

-viewDidUnload用於釋放由兩者共同擁有的所有對象視圖控制器本身和視圖。原因是:如果視圖控制器保存對視圖的子項的引用,即按鈕,則引用的子視圖將不會被釋放,因為它們的保留計數為> = 1.在-vi??ewDidUnload中釋放它們後,它們可以被釋放從記憶中恢復過來。 由於內存不足而導致視圖被卸載時將從系統中調用(請更正我:何時調用它?)

-viewDidUnload用於釋放由兩者共同擁有的所有對象視圖控制器本身和視圖。原因是:如果視圖控制器保存對視圖的子項的引用,即按鈕,則引用的子視圖將不會被釋放,因為它們的保留計數為> = 1.在-vi??ewDidUnload中釋放它們後,它們可以被釋放從記憶中恢復過來。

remeber在視圖中卸載做self.button = nil;,而不是[button release] ;. - mk12 09年8月16日19:06

@ Mk12,為什麼? - ma11hew28 2011年3月22日1:48

+60

Apple棄用了viewWillUnload,現在你應該使用didReceiveMemoryWarning或dealloc來發布你的對象。

在iOS 6中,現在不推薦使用UIViewController的viewWillUnload和viewDidUnload方法。如果您使用這些方法來釋放數據,請改用didReceiveMemoryWarning方法。如果未使用此方法,也可以使用此方法釋放對視圖控制器視圖的引用。在執行此操作之前,您需要測試視圖不在窗口中。

+50

如果視圖控制器從導航控制器堆棧中彈出並且未在其他任何位置保留,則將取消分配,並且將調用dealloc而不是viewDidUnload。您應該在dealloc中釋放在loadView中創建的視圖,但沒有必要將變量設置為nil,因為在調用dealloc後不久,變量將不再存在。

+30

您可以釋放您保留的任何子視圖,例如您在loadView方法中保留的UIImageView,或者更好的是UIImageView上的圖像。

我也有同樣的問題。在iOS7上UIIMagePickerController不再工作了。 - condor304 2013年9月20日11:00

調用這種方法對我有用。在展示您的視圖後放置它。[yourViewBeingPresented.view layoutIfNeeded]; - Bobby 2016年3月31日9:15

0
votes
answers
28 views
+10

如何用Objective C殺死一個線程?

2

我有一個第三方C++庫,我已經把它放入它自己的線程(目前使用NSThread)調用。我想給用戶停止執行該線程的能力。 (我很清楚這可能導致的所有問題,但我仍然希望這樣做。)如何用Objective C殺死一個線程?

根據Apple's Thread Programming Guide,Cocoa有可能這樣做。這也適用於iPhone嗎?還是我必須依靠Posix線程來完成我的目標?

乾杯

MrMage

+4

如果你認爲你想停止一個線程直接和外部沒有某種同步原語來停止它在一個已知點然後,不,你不明白它可能造成的問題。其中一個問題很可能是崩潰或損壞的內存。不可避免的如此。 – bbum 2009-08-29 18:35:46

+0

即使當我想殺死的線程(工作線程)不使用任何主線程的對象,反之亦然? 圖書館的開發者告訴我,他很高興地使用這種線程取消來阻止他的工作線程,並且他沒有遇到這樣的主要問題。 – MrMage 2009-08-29 21:46:37

+0

如果他的庫以任何方式使用任何系統庫調用,則強制殺死線程將導致未定義的行爲。這包括malloc(),甚至。即使它現在看起來有效,它是否繼續在軟件更新和體系結構更改上工作也是一個完全不同的問題。 – bbum 2009-08-30 06:35:16

沙发
0
10

正確的方式來阻止你的線程執行是要求它很好地停止執行。然後,在你的線索中,你會聽取這樣的要求,並在適當的時候服從他們。

由於很頁面鏈接到您說:

雖然可可,POSIX,和多服務提供程序直接殺線程,使用這種程序的強烈反對。殺死一個線程可以防止線程自行清理。由該線程分配的內存可能會泄漏,並且線程當前正在使用的任何其他資源可能無法正確清理,從而在稍後創建潛在問題。

如果您預計需要在操作過程中終止線程,則應該從一開始就設計線程以響應取消或退出消息。對於長時間運行的操作,這可能意味着要定期停止工作並檢查是否收到了這樣的消息。如果消息確實要求線程退出,線程將有機會執行任何需要的清理並正常退出;否則,它可能會重新開始工作並處理下一塊數據。

0
votes
answers
20 views
+10

在macOS中接收承諾的電子郵件10.12+

1

之前,我使用以下方法來發現從Mail.app中刪除的電子郵件(/ - 線程)的電子郵件元數據&。在macOS中接收承諾的電子郵件10.12+

 if let filenames = draggingInfo.namesOfPromisedFilesDropped(atDestination: URL(fileURLWithPath: destinationDir!)) { 
      /// TODO: in future implementation Mail might return multiple filenames here. 
      ///   So we will keep this structure to iterate the filenames 
      //var aPaths: [String] = [] 
      //for _ in filenames { 
       if let aPath = pb.string(forType: "com.apple.pasteboard.promised-file-url") { 
        return aPath 
       } 
      //} 
      //return aPaths 
     } 

janky的種類,但它的工作,因爲"com.apple.pasteboard.promised-file-url"在這些情況下,只能提供。

自10.12然而,API似乎已經改變,並期待在WWDC2016 talk看來,蘋果希望我們現在使用NSFilePromiseReceiver。 我嘗試了幾種方法,但我無法獲得承諾的文件URL彈出。

設置:

class DropzoneView: NSView { 

var supportedDragTypes = [ 

    kUTTypeURL as String, // For any URL'able types 
    "public.url-name", // E-mail title 
    "public.utf8-plain-text", // Plaintext item/E-mail thread title/calendar event date placeholder 
    "com.apple.pasteboard.promised-file-content-type", // Calendar event/Web URL/E-mail thread type detection 
    "com.apple.mail.PasteboardTypeMessageTransfer", // E-mail thread detection 
    "NSPromiseContentsPboardType", // E-mail thread meta-data 
    "com.apple.pasteboard.promised-file-url", // E-mail thread meta-data 
    "com.apple.NSFilePromiseItemMetaData" // E-mail thread meta-data 
] 

override func viewDidMoveToSuperview() { 
    var dragTypes = self.supportedDragTypes.map { (type) -> NSPasteboard.PasteboardType in 
     return NSPasteboard.PasteboardType(type) 
    } // Experiment: 
    dragTypes.append(NSPasteboard.PasteboardType.fileContentsType(forPathExtension: "eml")) 
    dragTypes.append(NSPasteboard.PasteboardType.fileContentsType(forPathExtension: "emlx")) 

    self.registerForDraggedTypes(dragTypes) 
} 

} 

處理:

extension DropzoneView { 

override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation { 
    return .copy 
} 

override func draggingUpdated(_ sender: NSDraggingInfo) -> NSDragOperation { 
    return .copy 
} 

override func performDragOperation(_ sender: NSDraggingInfo) -> Bool { 

    let pasteboard: NSPasteboard = sender.draggingPasteboard() 
      guard let filePromises = pasteboard.readObjects(forClasses: [NSFilePromiseReceiver.self], options: nil) as? [NSFilePromiseReceiver] else { 
     return false 
    } 

    var files = [Any]() 
    var errors = [Error]() 

    let filePromiseGroup = DispatchGroup() 
    let operationQueue = OperationQueue() 
    let newTempDirectoryURL = URL(fileURLWithPath: (NSTemporaryDirectory() + (UUID().uuidString) + "/"), isDirectory: true) 
    do { 
     try FileManager.default.createDirectory(at: newTempDirectoryURL, withIntermediateDirectories: true, attributes: nil) 
    } 
    catch { 
     return false 
    } 

    // Async attempt, either times out after a minute or so (Error Domain=NSURLErrorDomain Code=-1001 "(null)") or gives 'operation cancelled' error 
    filePromises.forEach({ filePromiseReceiver in 
     filePromiseGroup.enter() 
     filePromiseReceiver.receivePromisedFiles(atDestination: newTempDirectoryURL, 
               options: [:], 
               operationQueue: operationQueue, 
               reader: { (url, error) in 
                Swift.print(url) 
                if let error = error { 
                 errors.append(error) 
                } 
                else if url.isFileURL { 
                 files.append(url) 
                } 
                else { 
                 Swift.print("No loadable URLs found") 
                } 

                filePromiseGroup.leave() 
     }) 
    }) 

    filePromiseGroup.notify(queue: DispatchQueue.main, 
          execute: { 
           // All done, check your files and errors array 
           Swift.print("URLs: (files)") 
           Swift.print("errors: (errors)") 
    }) 

    Swift.print("URLs: (files)") 

    return true 
} 

其它嘗試:

// returns nothing 
    if let filenames = pasteboard.propertyList(forType: NSPasteboard.PasteboardType(rawValue: "com.apple.pasteboard.promised-file-url")) as? NSArray { 
     Swift.print(filenames) 
    } 

    // doesn't result in usable URLs either 
    if let urls = pasteboard.readObjects(forClasses: [NSPasteboardItem.self /*NSURL.self, ???*/], options: [:]) as? [... 

任何指針將不勝感激。

+0

您是否設法取得進展? – iphaaw

沙发
0
1

我設法讓文件「彈出」,但我無法得到他們的細節。它會立即傳輸,然後在返回錯誤消息之前掛起60秒。

也許這是一個線索,但checkExtension方法永遠不會返回,除非註釋掉並設置爲true。

希望這有助於踢罐頭在路上了一下:

class DropView: NSView 
{ 
    var filePath: String? 

    required init?(coder: NSCoder) { 
     super.init(coder: coder) 

     self.wantsLayer = true 
     self.layer?.backgroundColor = NSColor.red.cgColor 

     registerForDraggedTypes([NSPasteboard.PasteboardType 
      .fileNameType(forPathExtension: ".eml"), NSPasteboard.PasteboardType.filePromise]) 
    } 

    override func draw(_ dirtyRect: NSRect) { 
     super.draw(dirtyRect) 
     // Drawing code here. 
    } 

    override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation { 
     if checkExtension(sender) == true 
     { 
      self.layer?.backgroundColor = NSColor.blue.cgColor 
      return .copy 
     } 
     else 
     { 
      return NSDragOperation() 
     } 
    } 

    fileprivate func checkExtension(_ drag: NSDraggingInfo) -> Bool 
    { 
     return true 
//  guard let board = drag.draggingPasteboard().propertyList(forType: NSPasteboard.PasteboardType(rawValue: "com.apple.mail.PasteboardTypeMessageTransfer")) as? NSArray, 
//   let path = board[0] as? String 
//   else 
//   { 
//    return false 
//   } 
// 
//  let suffix = URL(fileURLWithPath: path).pathExtension 
//  for ext in self.expectedExt 
//  { 
//   if ext.lowercased() == suffix 
//   { 
//    return true 
//   } 
//  } 
//  return false 
    } 

    override func draggingExited(_ sender: NSDraggingInfo?) 
    { 
     self.layer?.backgroundColor = NSColor.gray.cgColor 
    } 

    override func draggingEnded(_ sender: NSDraggingInfo) 
    { 
     self.layer?.backgroundColor = NSColor.gray.cgColor 
    } 

    override func performDragOperation(_ sender: NSDraggingInfo) -> Bool 
    { 

     let pasteboard: NSPasteboard = sender.draggingPasteboard() 

     guard let filePromises = pasteboard.readObjects(forClasses: [NSFilePromiseReceiver.self], options: nil) as? [NSFilePromiseReceiver] else { 
      return false 
     } 

     print ("Files dropped") 
     var files = [URL]() 

     let filePromiseGroup = DispatchGroup() 
     let operationQueue = OperationQueue() 
     let destURL = URL(fileURLWithPath: "/Users/andrew/Temporary", isDirectory: true) 
     print ("Destination URL: (destURL)") 

     filePromises.forEach ({ filePromiseReceiver in 
      print (filePromiseReceiver) 
      filePromiseGroup.enter() 

      filePromiseReceiver.receivePromisedFiles(atDestination: destURL, 
                options: [:], 
                operationQueue: operationQueue, 
                reader: 
                { (url, error) in 
                 print ("Received URL: (url)") 
                 if let error = error 
                 { 
                  print ("Error: (error)") 
                 } 
                 else 
                 { 
                  files.append(url) 
                 } 
                 print (filePromiseReceiver.fileNames, filePromiseReceiver.fileTypes) 

                 filePromiseGroup.leave() 
                }) 
     }) 

     filePromiseGroup.notify(queue: DispatchQueue.main, 
           execute: 
           { 
            print ("Files: (files)") 
            print ("Done") 
           }) 
     return true 
    } 

} 

的這個輸出是有點不可思議。 url變量一直重複我通過的目錄名稱,例如:

Files dropped 
Destination URL: file:///Users/andrew/Temporary/ 
<NSFilePromiseReceiver: 0x6000000a1aa0> 

** one minute gap ** 

Received URL: file:///Users/andrew/Temporary/Temporary/ 
Error: Error Domain=NSURLErrorDomain Code=-1001 "(null)" 
["Temporary"] ["com.apple.mail.email"] 
Files: [] 
Done 
+0

謝謝@iphaaw,情節變厚了!實際上,我向蘋果提交了一份支持請求,並且收到了一條消息,說他們「知道這個問題,但目前沒有解決方法或解決方法或指示何時將解決問題」......我從應用程序中撤回了我的應用程序存儲並轉移到非osx項目。 –

619
votes
answers
19 views
+10

compilation warning: no rule to process file for architecture i386

How can I resolve this warning?

[WARN]warning: no rule to process file '$(PROJECT_DIR)/MyApp/MessageCell.h' of type sourcecode.objj.h for architecture i386

up vote 565 down vote accepted favorite
沙发
+5650
+50

Click on your project, and check that this file is not present in the tab Build Phases. Normally no header files should stay here. Clean and build it again, it should work!

我有一些頭文件。只是好奇,為什麼不應該有標題? - Sheehan Alam 2011年6月28日17:39

因為這是將要編譯的源文件列表,通常您已經包含 你內心的.h .m - Giuseppe 2011年6月28日18:55

每當我創建一個新類時,我的XCode會自動將頭文件添加到我的構建階段。我不知道為什麼,任何人都知道為什麼會這樣?目前,每次創建新類時,我都需要手動從構建階段中刪除頭文件。 - Bocaxica 12年9月9日18:55

我可能會補充一個.h文件可能出現在構建階段(當它不應該)時,因為.m文件(錯誤地)有一個不同的名稱。 - Ali於2013年10月11日15:07

這是完全合理的...我原來創建了一個.cpp文件然後將其重命名為.h - ddavison 2014年3月10日12:54

+350

Graphical guide for Xcode 4.x to remove this warning:

http://joytek.blogspot.tw/2011/09/xcode-4-warning-no-rule-to-process-file.html

+160

We can resolve this issue by simply following the steps below:- Some .md, .mdown .h files are included in the Compile Sources
Step 1) Select Project Navigator
Step 2) Select your project
Step 3) Select your targetStep
Step 4) Select Build PhasesStep
Step 5) Move files which we don't want the compiler to process from Compile Sources to Copy Bundle Resources

Check this

+30

If you are getting this warning from your cocoapod you ned to make sure the s.source_files is set correctly in the .podspec.

For example I originally included all files with this line in my .podspec

s.source_files = "MyUIElements/**/*"

I was getting this compilation warning for some font files I had in the pod. You control which files show up in BuildPhases -> CompileSources on pod consumption like this:

s.source_files = "MyUIElements/**/*.swift", "MyUIElements/**/*.h"

或s.source_files =“來源** / *。{h,m,swift}”? - hstdt 17年10月26日5:42

4
votes
answers
11 views
+10

Need help linking to bundle on OS X

I'm an experienced Java coder, but I'm new to XCode and C++, so sorry for the dumb question.

I'm writing some c++ code in XCode that needs to instantiate a Java Virtual Machine. There is a method in the OS X Java plugin called JavaVM_GetJNIEnv(), and a header file in the source code from Sun/Oracle called JavaVM.h with these lines:

// Gets the JNIEnv* associated with the Java VM, creating the JVM
// instance if necessary. Note that the implementation of this routine
// must be prepared for it to be called from more than one thread.
JNIEnv* JavaVM_GetJNIEnv();

I added the .h file to my XCode project, but I don't know how to link to the binary file. I figured out how to force-load in the linker, like this:

-force_load /System/Library/Java/Support/Deploy.bundle/Contents/Resources/JavaPlugin2_NPAPI.plugin/Contents/MacOS/JavaPlugin2_NPAPI

(this file is a symbolic link; the real path is /System/Library/Java/Support/Deploy.bundle/Contents/Resources/JavaPlugin2_NPAPI.plugin/Contents/Resources/Java/libplugin2_npapi.jnilib)

But then I get this error message:

ld: in /System/Library/Java/Support/Deploy.bundle/Contents/Resources/JavaPlugin2_NPAPI.plugin/Contents/MacOS/JavaPlugin2_NPAPI, can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)
collect2: ld returned 1 exit status

So my question is, how do I link to code in a .jnilib file with XCode?

+20

You need to link to frameworks, not bundles. Choose 'Add Existing Framework' and select JavaVM.framework, and Xcode should handle the rest!

我的框架列表中已經有了JavaVM.framework ......也許這個函數是在不同的庫中定義的。我會用'nm'做一些搜索,試圖找出哪個二進製文件具有我正在尋找的功能; 也許我只需要添加一個不同的框架。 - Jesse Barnum 2011年7月11日19:55

好的,我找到了文件的真實位置。我使用'nm'來驗證我需要的功能是否包含在內。實際二進製文件的位置是'/System/Library/Java/Support/Deploy.bundle/Contents/Resources/JavaPlugin2_NPAPI.plugin/Contents/MacOS/JavaPlugin2_NPAPI'。由於我無法將捆綁包添加到XCode,我將如何鏈接到此? - Jesse Barnum 2011年7月11日20:10

在osx下,gcc包裝器接受-F 和框架 作為參數。-F / -workwork類似於-L / -l,但我認為sbooth是對的 - 如果它沒有正確鏈接,那麼某些東西是不可思議的。 - synthesizerpatel 2011年7月11日20:23

那麼如何鏈接到不是框架的代碼呢? - Jesse Barnum 2011年7月11日20:32

您嘗試鏈接的內容是Web瀏覽器的Java插件的一部分(因此路徑中的NPAPI)。你確定那是你想要的嗎? - user57368 2011年7月12日2:01

板凳
+20
+50

I figured it out. If you're trying to reference code stored in a .bundle, you don't actually link to it, you make calls to it at runtime and then reference the functions by name (ie. similar to Java's reflection, which I'm more familiar with).

NPError (*getEntryPoints)(NPPluginFuncs *aNPPFuncs); //Defines a variable which is a pointer to a function

CFURLRef bundleUrl = CFURLCreateWithFileSystemPath(NULL, CFSTR("/System/Library/Java/Support/Deploy.bundle/Contents/Resources/JavaPlugin2_NPAPI.plugin"), kCFURLPOSIXPathStyle, true);
CFBundleRef bundleRef = CFBundleCreate(NULL, bundleUrl);
getEntryPoints = (NPError (*)(NPPluginFuncs *))CFBundleGetFunctionPointerForName ( bundleRef, CFSTR("NP_GetEntryPoints" ) ); //Sets the pointer function to a function loaded from the bundle

if( getEntryPoints == NULL ) {
    printf("getEntryPoints is NULL");
} else {
    NPPluginFuncs pluginFuncs;
    pluginFuncs.size = sizeof(NPPluginFuncs);

    NPError err = getEntryPoints( &pluginFuncs ); //This is what actually calls the library function
    //... do more stuff with plugin API ...
}

As an aside, this didn't wind up being very useful for my purposes because as far as I can tell, the java plugin API is only designed to be called from Mozilla-based browsers, and I'm trying to embed Java in my own application.

0
votes
answers
29 views
+10

試圖在iOS上使用FBShimmer可可豆莢但未找到Foundation框架

0

我試圖在iOS上使用FBShimmer可可豆莢但未找到Foundation框架。 PodFile shown here試圖在iOS上使用FBShimmer可可豆莢但未找到Foundation框架

enter image description here

enter image description here

+0

嘗試取消註釋use_frameworks!從您的podfile中,然後再次安裝。它可能有幫助。 –

+0

https://stackoverflow.com/questions/24750593/unknown-type-name-cgfloat-when-try-to-add-panoramagl-to-the-static-library/27902361 –

+0

@AaqibHussain我試過,但然後標題沒有找到橋接頭中列出的文件。 –

沙发
0
0

最後我只使用一個UIView擴展達到同樣的效果。更少的代碼和外部依賴。

func startShimmering() { 
    let light = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5).cgColor 
    let dark = UIColor.white.cgColor 

    let gradient: CAGradientLayer = CAGradientLayer() 
    gradient.colors = [dark, light, dark] 
    gradient.frame = CGRect(x: -self.bounds.size.width, y: 0, width: 3*self.bounds.size.width, height: self.bounds.size.height) 
    gradient.startPoint = CGPoint(x: 0.0, y: 0.4) 
    gradient.endPoint = CGPoint(x: 1.0, y: 0.5) 
    gradient.locations = [0.4, 0.5, 0.6] 
    self.layer.mask = gradient 

    let animation: CABasicAnimation = CABasicAnimation(keyPath: "locations") 
    animation.fromValue = [0.0, 0.1, 0.2] 
    animation.toValue = [0.8, 0.9, 1.0] 

    animation.duration = 3.0 
    animation.repeatCount = HUGE 
    gradient.add(animation, forKey: "shimmer") 


} 
109
votes
answers
15 views
+10

Adding a simple UIAlertView

What is some starter code I could use to make a simple UIAlertView with one "OK" button on it?

沙发
+670

其他答案已經提供了iOS 7及更早版本的信息,但iOS 8中不推薦使用 UIAlertView

在iOS 8+中你應該使用<代碼> UIAlertController 它是 UIAlertView UIActionSheet 的替代品。文檔: UIAlertController類參考關於 NSHipster 的一篇很好的文章。

要創建一個簡單的警報視圖,你可以做以下:

  UIAlertController * alertController = [UIAlertController alertControllerWithTitle:@“Title”消息:@“Message”preferredStyle:UIAlertControllerStyleAlert]; //我們通過創建UIAlertActions向警報控制器添加按鈕:UIAlertAction * actionOk = [UIAlertAction actionWithTitle:@“Ok”style:UIAlertActionStyleDefault handler:nil]; //你可以在這裡使用一個塊來處理按下這個按鈕[alertController addAction:actionOk]; [self presentViewController:alertController animated:YES completion:nil];   

Swift 3/4:

  let alertController = UIAlertController(標題:“標題”,消息:“消息”,preferredStyle:.alert)//我們通過創建UIAlertActions向警報控制器添加按鈕:let actionOk = UIAlertAction(標題:“OK” “,style:.default,handler:nil)//你可以在這裡使用一個塊來處理按鈕這個按鈕alertController.addAction(actionOk)self.present(alertController,animated:true,completion:nil)  

請注意,由於它是在iOS 8中添加的,因此該代碼不適用於iOS 7及更早版本。所以,遺憾的是,現在我們必須使用類似的版本檢查:

  NSString * alertTitle = @“Title”; NSString * alertMessage = @“消息”; NSString * alertOkButtonText = @“Ok”; if([UIAlertController class] == nil){// [UIAlertController class]在iOS 7及更早版本上返回nil。您可以使用任何方法來檢查系統版本是否為iOS 8+ //從Xcode 9開始,您還可以使用// if(@available(iOS 8,*)){UIAlertView * alertView = [[UIAlertView alloc ] initWithTitle:alertTitle消息:alertMessage委託:nil cancelButtonTitle:nil otherButtonTitles:alertOkButtonText,nil]; [alertView show]; } else {UIAlertController * alertController = [UIAlertController alertControllerWithTitle:alertTitle message:alertMessage preferredStyle:UIAlertControllerStyleAlert]; //我們通過創建UIAlertActions向警報控制器添加按鈕:UIAlertAction * actionOk = [UIAlertAction actionWithTitle:alertOkButtonText style:UIAlertActionStyleDefault handler:nil]; //你可以在這裡使用一個塊來處理按下這個按鈕[alertController addAction:actionOk]; [self presentViewController:alertController animated:YES completion:nil]; }   

Swift 3/4:

  let alertTitle =“Title”let alertMessage =“Message”let alertOkButtonText =“好”
     
			
        
板凳
+110

UIAlertView在iOS 8上已棄用。因此,要在iOS 8及更高版本上創建警報,建議使用UIAlertController:

  UIAlertController * alert = [UIAlertController alertControllerWithTitle:@“Title “message:@”Alert Message“preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction * defaultAction = [UIAlertAction actionWithTitle:@“Ok”style:UIAlertActionStyleDefault handler:^(UIAlertAction * action){//在此處輸入代碼}]; [alert addAction:defaultAction]; //在需要的地方顯示動作[self presentViewController:alert animated:YES completion:nil];   

這就是我實現它的方式。

地板
+90
  UIAlertView * alert = [[UIAlertView alloc] initWithTitle:@“Title”message:@“Message”delegate:nil //或self cancelButtonTitle:@“OK”otherButtonTitles:nil]; [警示顯示]; [alert autorelease];  
     
			
        
4楼
+90
  UIAlertView * myAlert = [[UIAlertView alloc] initWithTitle:@“Title”message:@“Message”delegate:self cancelButtonTitle:@“Cancel”otherButtonTitles:@“Ok”,nil]; [myAlert show];  
     
			
        
5楼
+90

作為前兩個答案(用戶“sudo rm -rf”和“Evan Mulawski”)的補充,如果您在單擊警報視圖時不想執行任何操作,則可以分配,顯示和釋放它。您不必聲明委託協議。

6楼
+30
<p>這是一個完整的方法,只有一個按鈕,一個'ok',關閉UIAlert:</ p> <pre> <code> - (void)myAlert:(NSString *)errorMessage {UIAlertView * myAlert = [[UIAlertView alloc] initWithTitle:errorMessage message:@“”delegate:self cancelButtonTitle:nil otherButtonTitles:@“ok”,nil]; myAlert.cancelButtonIndex = -1; [myAlert setTag:1000]; [myAlert show]; } </ code> </ pre>
7楼
+10

此頁面顯示瞭如果使用Swift如何添加UIAlertController

8楼
0

使用數組數據的簡單警報:

  NSString * name = [[YourArray objectAtIndex:indexPath.row] valueForKey:@“Name”]; NSString * msg = [[YourArray objectAtIndex:indexPath.row] valueForKey:@“message”]; UIAlertView * alert = [[UIAlertView alloc] initWithTitle:name message:msg delegate:self cancelButtonTitle:@“OK”otherButtonTitles:nil]; [警示顯示];  
     
			
        
9楼
-10

對於Swift 3:

  let alert = UIAlertController(標題:“Alert”,消息:“Message”,preferredStyle:UIAlertControllerStyle.alert)alert.addAction(UIAlertAction(標題:“OK) “,style:UIAlertActionStyle.default,handler:nil))self.present(alert,animated:true,completion:nil) 
     
			
        
0
votes
answers
27 views
+10

取消選擇NSTextField中的文本

1

有沒有簡單的方法取消選擇 按回車?取消選擇NSTextField中的文本

沙发
0
1

首先,您需要將視圖控制器設置爲文本字段的代表。然後,您可以覆蓋NSControl實例方法controlTextDidEndEditing(_:),讓你的文本框當前編輯器中選擇範圍 並從主線程設置回您的文本字段:

import Cocoa 

class ViewController: NSViewController, NSTextFieldDelegate { 
    @IBOutlet weak var textField: NSTextField! 
    override func viewDidLoad() { 
     super.viewDidLoad() 
     textField.delegate = self 
    } 
    override func controlTextDidEndEditing(_ obj: Notification) { 
     if let selectedRange = textField.currentEditor()?.selectedRange { 
      DispatchQueue.main.async { 
       self.textField.currentEditor()?.selectedRange = selectedRange 
      } 
     } 
    } 
} 
+0

它取消textfiled但什麼即時尋找是,取消選擇文本並保持文本選擇無論是在 –

+0

bassicly即時尋找一種方式來阻止自動選擇所有文字textfiled按下回車鍵時 –

+0

@jana_lemmings檢查我的最後一次編輯 –

0
votes
answers
20 views
+10

Installing Cocoapods on OS X El Capitan error

First of all. I updated to El Capitan because of iOS 9.3 and it's support only in xCode 7.3.

After update I discovered that pod command isn't working. I executed:

sudo gem install cocoapods
ERROR:  Error installing cocoapods:
    activesupport requires Ruby version >= 2.2.2.

So my problem is that I can't install cocoapods. I don't know nothing about gems and ruby stuff. Does somebody know how to handle this?

I had second OS X with El Capitan 10.11.4 and everything went ok so I don't know from where this issue is coming from.

UPDATE: 5 April 2016

I executed several commands on terminal for more info:

Kapucha:~ kapucha$ which ruby
/usr/bin/ruby
Kapucha:~ kapucha$ which gem
/usr/bin/gem
Kapucha:~ kapucha$ which brew
/usr/local/bin/brew
Kapucha:~ kapucha$ which rvm
/Users/kapucha/.rvm/bin/rvm

Versions:

Kapucha:~ kapucha$ ruby --version
ruby 2.0.0p648 (2015-12-16 revision 53162) [universal.x86_64-darwin15]
Kapucha:~ kapucha$ gem --version
2.2.2
Kapucha:~ kapucha$ brew --version
/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/fileutils.rb:245:in `mkdir': Permission denied - /Library/Ruby/Gems/2.0.0/extensions/universal-darwin-15 (Errno::EACCES)
Kapucha:~ kapucha$ rvm --version
rvm 1.27.0 (latest) by Wayne E. Seguin <wayneeseguin@gmail.com>, Michal Papis <mpapis@gmail.com> [https://rvm.io/]

.bash_profile file and .profile

Kapucha:~ kapucha$ cat .bash_profile
export JAVA_HOME=$(/usr/libexec/java_home)
. ~/.bashrc
source ~/.profile

Kapucha:~ kapucha$ cat .profile
export PATH="$PATH:$HOME/.rvm/bin" # Add RVM to PATH for scripting
[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm" # Load RVM into a shell session *as a function*

rvm list and rvm info

Kapucha:local kapucha$ rvm list

rvm rubies


# No rvm rubies installed yet. Try 'rvm help install'.

Kapucha:local kapucha$ rvm info

system:

  system:
    uname:       "Darwin Kapucha.local 15.4.0 Darwin Kernel Version 15.4.0: Fri Feb 26 22:08:05 PST 2016; root:xnu-3248.40.184~3/RELEASE_X86_64 x86_64"
    system:      "osx/10.11/x86_64"
    bash:        "/bin/bash => GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin15)"
    zsh:         "/bin/zsh => zsh 5.0.8 (x86_64-apple-darwin15.0)"

  rvm:
    version:      "rvm 1.27.0 (latest) by Wayne E. Seguin <wayneeseguin@gmail.com>, Michal Papis <mpapis@gmail.com> [https://rvm.io/]"
    updated:      "18 hours 23 minutes 25 seconds ago"
    path:         "/Users/kapucha/.rvm"

  homes:
    gem:          "not set"
    ruby:         "not set"

  binaries:
    ruby:         "/usr/bin/ruby"
    irb:          "/usr/bin/irb"
    gem:          "/usr/bin/gem"
    rake:         "/usr/bin/rake"

  environment:
    PATH:         "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/filipkotwicki/dev/tools/android-sdk-macosx/platform-tools:~/bin:/opt/X11/bin:/usr/local/git/bin:/Users/kapucha/.rvm/bin:/Users/kapucha/.rvm/bin"
    GEM_HOME:     ""
    GEM_PATH:     ""
    MY_RUBY_HOME: ""
    IRBRC:        ""
    RUBYOPT:      ""
    gemset:       ""

When I'm triying to install Ruby with rvm

Kapucha:local kapucha$ rvm install 2.2.2
Searching for binary rubies, this might take some time.
Found remote file https://rvm_io.global.ssl.fastly.net/binaries/osx/10.11/x86_64/ruby-2.2.2.tar.bz2
Checking requirements for osx.
/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/fileutils.rb:245:in `mkdir': Permission denied - /Library/Ruby/Gems/2.0.0/extensions/universal-darwin-15 (Errno::EACCES)
...
ERROR: '/bin' is not writable - it is required for Homebrew, try 'brew doctor' to fix it!
Requirements installation failed with status: 1.

Tried brew doctor with the same result:

Kapucha:local kapucha$ brew doctor
/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/fileutils.rb:245:in `mkdir': Permission denied - /Library/Ruby/Gems/2.0.0/extensions/universal-darwin-15 (Errno::EACCES)
沙发
0

activesupportCocoapods 依賴的寶石需要Ruby版本大於2.2.2(見這裡)。

您使用的是哪個版本的Ruby(類型ruby --version)?也許您的第二個OS X系統正在使用系統Ruby版本(您可以通過鍵入來檢查它which ruby)。

可能你需要安裝更新版本的Ruby(例如2.2.3)。我建議使用RVM在您的機器上安裝和管理Ruby版本。

No problem. Glad that I helped. :) – Aleksander Grzyb Apr 5 '16 at 12:02

板凳
0

使用以下命令安裝homebrew

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

然後安裝cocoapods而不使用sudo

gem install cocoapods

地板
0

請從安裝最新版本的Ruby和RVM(Ruby的版本管理器)的這個環節。

然後運行“ sudo install cocoapods

4楼
0

El Capitan 10.11.3

1)$ sudo gem install activesupport -v 4.2.6

2)$ sudo gem install -n / usr / local / bin cocoapods

550
votes
answers
21 views
+10

Updating to latest version of CocoaPods?

I'm having some issues installing Alamofire 4.0 into my project.

I've got the latest version of Xcode, running Swift 3, and when I try to install alamofire I'm getting like 800 compiler errors.

Apparently

CocoaPods 1.1.0+ is required to build Alamofire 4.0.0+

I looked at the version of CocoaPods I have in terminal and it says I'm at 1.0.1.

Running an update didn't work I guess because CocoaPods 1.1 is in beta.

So I'm not exactly sure how to update it up to where I'm good to go. Unless being out of date doesn't force like 800 compiler errors? Does that sound like some other issue?

up vote 444 down vote accepted favorite
沙发
+4440
+50

在終端上執行以下操作以獲取最新穩定版

  sudo gem install cocoapods   

添加< code> - pre 獲取最新的預發行版:

  sudo gem install cocoapods --pre  
     
			
        

之後沒有pod設置似乎沒有工作。 - Danny Schoemann 2月13日11:11

+690

打開終端 - &gt; copy 命令

  sudo gem install cocoapods   

它將安裝 cocoapods 的最新穩定版本。

之後,您需要使用以下命令更新pod

  pod setup   

您可以使用以下命令檢查pod版本

  pod  - -version  
     
			
        

在此之後你還需要運行 pod setup --verbose 嗎? - GraSim於2017年5月31日11:06

@GraSim是的。這是必需的 - Dheeraj D 2017年5月31日11:08

您的gemfile可能被鎖定到舊版本,在這種情況下運行bundle update cocoapods以使用最新的cocoapods獲取您的項目 - dmoss18 18年6月6日15:33

+90

以下是更新cocoapods的步驟:

  1. 打開終端(快捷方式:按cmd +空格標籤打開Spotlight,然後輸入文字 terminal
  2. 使用命令 sudo gem install cocoapod 這將要求系統密碼,因為安全問題此後安裝寶石

    1. 現在,使用 pod setup 命令設置pod。這將設置cocoapods主倉庫。

      / code>命令。

      / code>命令。

+90

對於那些使用 sudo-less CocoaPods安裝(即,你想要授予RubyGems管理員權限),你不需要 sudo 命令來更新你的CocoaPods安裝:

  gem install cocoapods   

你可以找到安裝CocoaPods gem的 where

  gem cocoapods   

如果這是你的主目錄,你一定要運行<碼>gem install cocoapods ,不使用 sudo

最後,要檢查當前運行的CocoaPods是什麼類型:

  pod --version  
     
			
        
+90

如果您使用的是Homebrew,請打開終端並輸入:

  brew upgrade cocoapods   

如果不起作用,請嘗試:

  brew install cocoapods  
     
			
        
+70

如果您啟用了系統完整性保護或任何其他權限寫入錯誤(自macOS Sierra發布以來默認啟用),您應該更新CocoaPods,在終端中運行此行: < pre> sudo gem install cocoapods -n / usr / local / bin

安裝完成後,檢查你的pod版本:

  pod --version   

你將擺脫這個錯誤:

 錯誤:執行gem時...(Gem :: FilePermissionError)你沒有寫權限對於/ usr / bin目錄  

它將安裝最新的CocoaPods:

 成功安裝cocoapods-xxx解析cocoapods-xx的文檔x安裝cocoapods-xxx的ri文檔4秒後安裝cocoapods文檔1 gem安裝 
     
			
        
+30

我嘗試過更新但沒有用。最後,我不得不完全刪除(手動)cocoapods,cocoapods-core,cocoapods-try .. cocoa pods使用的任何其他包。使用此終端命令列出所有包: gem list --local | grep cocoa pods

之後,我還從用戶根文件夾中刪除./cocoapods文件夾。

-30
 首先檢查cocoapods版本,如pod --version然後更新像sudo gem install cocoapods --pre更新後你也可以檢查cocoapods版本。  

你是如何移植你的身份的?最簡單的方法是使用您所顯示窗口底部的導入/導出按鈕 - 從工作系統導出,導入到新系統。這應該確保複製所有證書和配置文件。 - 湯米2011年7月21日0:23

但是,如果舊機器有壞硬盤(沒有備份)或已經重新格式化怎麼辦? - 太極者無極而生2012年7月16日11:51

實際上,作為評論的問題顯然是一個糟糕的想法。(一個全新的stackoverflow問題。或找到現有問題是正確的想法。) - Warren P 2013年3月25日12:40

-50

我將“pod'Alamofire','?&gt; 4.0'”更改為“pod'Alamofire',:git =&gt;' https://github.com/Alamofire/Alamofire ',:commit =&gt;'3cc5b4e'“之後在終端:”pod install --repo-update“它的工作原理。

對於第3步,我沒有在LIBRARY下列出“Developer Profile”。相反,我必須在TEAMS下選擇<我的團隊名稱>。 - Steve Onorato 12年6月21日0:56

我一直在“找不到有效的簽名身份”! - RGML 12年7月4日15:41

我有2台以上用於開發的計算機。我在其中一個上導出了配置文件,但我無法從“管理器”>“庫”>“配置文件”頁面導入它。我必須轉到Library> Teams> myUserID頁面才能導入開發者配置文件。 - GLaDOS 12年7月14日14:56

蘋果正在“改進”這些東西,但每走一步都會帶來新的痛苦。我還是一次又一次地把頭髮拉出來...... - 腦筋流於13年1月28日14:17

我提供了一張圖片,以幫助XCode 4.6用戶更清楚。APPLE YU沒有讓這很容易???? - Warren P 2013年3月25日12:52